3 Copyright (C) 2010-2013 celeron55, Perttu Ahola <celeron55@gmail.com>
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU Lesser General Public License as published by
7 the Free Software Foundation; either version 2.1 of the License, or
8 (at your option) any later version.
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU Lesser General Public License for more details.
15 You should have received a copy of the GNU Lesser General Public License along
16 with this program; if not, write to the Free Software Foundation, Inc.,
17 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
24 #include "clientserver.h"
26 #include "environment.h"
28 #include "jthread/jmutexautolock.h"
30 #include "constants.h"
36 #include "serverobject.h"
37 #include "genericobject.h"
41 #include "scripting_game.h"
48 #include "content_mapnode.h"
49 #include "content_nodemeta.h"
50 #include "content_abm.h"
51 #include "content_sao.h"
56 #include "sound.h" // dummySoundManager
57 #include "event_manager.h"
59 #include "serverlist.h"
60 #include "util/string.h"
61 #include "util/pointedthing.h"
62 #include "util/mathconstants.h"
64 #include "util/serialize.h"
65 #include "util/thread.h"
66 #include "defaultsettings.h"
68 class ClientNotFoundException : public BaseException
71 ClientNotFoundException(const char *s):
76 class ServerThread : public JThread
82 ServerThread(Server *server):
91 void * ServerThread::Thread()
93 log_register_thread("ServerThread");
95 DSTACK(__FUNCTION_NAME);
96 BEGIN_DEBUG_EXCEPTION_HANDLER
98 m_server->AsyncRunStep(true);
102 porting::setThreadName("ServerThread");
104 while(!StopRequested())
107 //TimeTaker timer("AsyncRunStep() + Receive()");
109 m_server->AsyncRunStep();
114 catch(con::NoIncomingDataException &e)
117 catch(con::PeerNotFoundException &e)
119 infostream<<"Server: PeerNotFoundException"<<std::endl;
121 catch(ClientNotFoundException &e)
124 catch(con::ConnectionBindFailed &e)
126 m_server->setAsyncFatalError(e.what());
130 m_server->setAsyncFatalError(e.what());
134 END_DEBUG_EXCEPTION_HANDLER(errorstream)
139 v3f ServerSoundParams::getPos(ServerEnvironment *env, bool *pos_exists) const
141 if(pos_exists) *pos_exists = false;
146 if(pos_exists) *pos_exists = true;
151 ServerActiveObject *sao = env->getActiveObject(object);
154 if(pos_exists) *pos_exists = true;
155 return sao->getBasePosition(); }
167 const std::string &path_world,
168 const SubgameSpec &gamespec,
169 bool simple_singleplayer_mode,
172 m_path_world(path_world),
173 m_gamespec(gamespec),
174 m_simple_singleplayer_mode(simple_singleplayer_mode),
175 m_async_fatal_error(""),
184 m_enable_rollback_recording(false),
187 m_itemdef(createItemDefManager()),
188 m_nodedef(createNodeDefManager()),
189 m_craftdef(createCraftDefManager()),
190 m_event(new EventManager()),
192 m_time_of_day_send_timer(0),
195 m_shutdown_requested(false),
196 m_ignore_map_edit_events(false),
197 m_ignore_map_edit_events_peer_id(0)
200 m_liquid_transform_timer = 0.0;
201 m_liquid_transform_every = 1.0;
202 m_print_info_timer = 0.0;
203 m_masterserver_timer = 0.0;
204 m_objectdata_timer = 0.0;
205 m_emergethread_trigger_timer = 0.0;
206 m_savemap_timer = 0.0;
209 m_lag = g_settings->getFloat("dedicated_server_step");
212 throw ServerError("Supplied empty world path");
214 if(!gamespec.isValid())
215 throw ServerError("Supplied invalid gamespec");
217 infostream<<"Server created for gameid \""<<m_gamespec.id<<"\"";
218 if(m_simple_singleplayer_mode)
219 infostream<<" in simple singleplayer mode"<<std::endl;
221 infostream<<std::endl;
222 infostream<<"- world: "<<m_path_world<<std::endl;
223 infostream<<"- game: "<<m_gamespec.path<<std::endl;
225 // Initialize default settings and override defaults with those provided
227 set_default_settings(g_settings);
228 Settings gamedefaults;
229 getGameMinetestConfig(gamespec.path, gamedefaults);
230 override_default_settings(g_settings, &gamedefaults);
232 // Create server thread
233 m_thread = new ServerThread(this);
235 // Create emerge manager
236 m_emerge = new EmergeManager(this);
238 // Create world if it doesn't exist
239 if(!initializeWorld(m_path_world, m_gamespec.id))
240 throw ServerError("Failed to initialize world");
242 // Create ban manager
243 std::string ban_path = m_path_world + DIR_DELIM "ipban.txt";
244 m_banmanager = new BanManager(ban_path);
246 // Create rollback manager
247 m_rollback = new RollbackManager(m_path_world, this);
249 ModConfiguration modconf(m_path_world);
250 m_mods = modconf.getMods();
251 std::vector<ModSpec> unsatisfied_mods = modconf.getUnsatisfiedMods();
252 // complain about mods with unsatisfied dependencies
253 if(!modconf.isConsistent())
255 for(std::vector<ModSpec>::iterator it = unsatisfied_mods.begin();
256 it != unsatisfied_mods.end(); ++it)
259 errorstream << "mod \"" << mod.name << "\" has unsatisfied dependencies: ";
260 for(std::set<std::string>::iterator dep_it = mod.unsatisfied_depends.begin();
261 dep_it != mod.unsatisfied_depends.end(); ++dep_it)
262 errorstream << " \"" << *dep_it << "\"";
263 errorstream << std::endl;
267 Settings worldmt_settings;
268 std::string worldmt = m_path_world + DIR_DELIM + "world.mt";
269 worldmt_settings.readConfigFile(worldmt.c_str());
270 std::vector<std::string> names = worldmt_settings.getNames();
271 std::set<std::string> load_mod_names;
272 for(std::vector<std::string>::iterator it = names.begin();
273 it != names.end(); ++it)
275 std::string name = *it;
276 if(name.compare(0,9,"load_mod_")==0 && worldmt_settings.getBool(name))
277 load_mod_names.insert(name.substr(9));
279 // complain about mods declared to be loaded, but not found
280 for(std::vector<ModSpec>::iterator it = m_mods.begin();
281 it != m_mods.end(); ++it)
282 load_mod_names.erase((*it).name);
283 for(std::vector<ModSpec>::iterator it = unsatisfied_mods.begin();
284 it != unsatisfied_mods.end(); ++it)
285 load_mod_names.erase((*it).name);
286 if(!load_mod_names.empty())
288 errorstream << "The following mods could not be found:";
289 for(std::set<std::string>::iterator it = load_mod_names.begin();
290 it != load_mod_names.end(); ++it)
291 errorstream << " \"" << (*it) << "\"";
292 errorstream << std::endl;
296 JMutexAutoLock envlock(m_env_mutex);
298 // Initialize scripting
299 infostream<<"Server: Initializing Lua"<<std::endl;
301 m_script = new GameScripting(this);
303 std::string scriptpath = getBuiltinLuaPath() + DIR_DELIM "init.lua";
305 if (!m_script->loadScript(scriptpath)) {
306 throw ModError("Failed to load and run " + scriptpath);
311 infostream<<"Server: Loading mods: ";
312 for(std::vector<ModSpec>::iterator i = m_mods.begin();
313 i != m_mods.end(); i++){
314 const ModSpec &mod = *i;
315 infostream<<mod.name<<" ";
317 infostream<<std::endl;
318 // Load and run "mod" scripts
319 for(std::vector<ModSpec>::iterator i = m_mods.begin();
320 i != m_mods.end(); i++){
321 const ModSpec &mod = *i;
322 std::string scriptpath = mod.path + DIR_DELIM + "init.lua";
323 infostream<<" ["<<padStringRight(mod.name, 12)<<"] [\""
324 <<scriptpath<<"\"]"<<std::endl;
325 bool success = m_script->loadMod(scriptpath, mod.name);
327 errorstream<<"Server: Failed to load and run "
328 <<scriptpath<<std::endl;
329 throw ModError("Failed to load and run "+scriptpath);
333 // Read Textures and calculate sha1 sums
336 // Apply item aliases in the node definition manager
337 m_nodedef->updateAliases(m_itemdef);
339 // Perform pending node name resolutions
340 m_nodedef->getResolver()->resolveNodes();
342 // Load the mapgen params from global settings now after any
343 // initial overrides have been set by the mods
344 m_emerge->loadMapgenParams();
346 // Initialize Environment
347 ServerMap *servermap = new ServerMap(path_world, this, m_emerge);
348 m_env = new ServerEnvironment(servermap, m_script, this, m_path_world);
350 m_clients.setEnv(m_env);
352 // Run some callbacks after the MG params have been set up but before activation
353 m_script->environment_OnMapgenInit(&m_emerge->params);
355 // Initialize mapgens
356 m_emerge->initMapgens();
358 // Give environment reference to scripting api
359 m_script->initializeEnvironment(m_env);
361 // Register us to receive map edit events
362 servermap->addEventReceiver(this);
364 // If file exists, load environment metadata
365 if(fs::PathExists(m_path_world + DIR_DELIM "env_meta.txt"))
367 infostream<<"Server: Loading environment metadata"<<std::endl;
371 // Add some test ActiveBlockModifiers to environment
372 add_legacy_abms(m_env, m_nodedef);
374 m_liquid_transform_every = g_settings->getFloat("liquid_update");
379 infostream<<"Server destructing"<<std::endl;
381 // Send shutdown message
382 SendChatMessage(PEER_ID_INEXISTENT, L"*** Server shutting down");
385 JMutexAutoLock envlock(m_env_mutex);
387 // Execute script shutdown hooks
388 m_script->on_shutdown();
390 infostream<<"Server: Saving players"<<std::endl;
391 m_env->saveLoadedPlayers();
393 infostream<<"Server: Saving environment metadata"<<std::endl;
401 // stop all emerge threads before deleting players that may have
402 // requested blocks to be emerged
403 m_emerge->stopThreads();
405 // Delete things in the reverse order of creation
408 // N.B. the EmergeManager should be deleted after the Environment since Map
409 // depends on EmergeManager to write its current params to the map meta
418 // Deinitialize scripting
419 infostream<<"Server: Deinitializing scripting"<<std::endl;
422 // Delete detached inventories
423 for (std::map<std::string, Inventory*>::iterator
424 i = m_detached_inventories.begin();
425 i != m_detached_inventories.end(); i++) {
430 void Server::start(Address bind_addr)
432 DSTACK(__FUNCTION_NAME);
433 infostream<<"Starting server on "
434 << bind_addr.serializeString() <<"..."<<std::endl;
436 // Stop thread if already running
439 // Initialize connection
440 m_con.SetTimeoutMs(30);
441 m_con.Serve(bind_addr);
446 // ASCII art for the win!
448 <<" .__ __ __ "<<std::endl
449 <<" _____ |__| ____ _____/ |_ ____ _______/ |_ "<<std::endl
450 <<" / \\| |/ \\_/ __ \\ __\\/ __ \\ / ___/\\ __\\"<<std::endl
451 <<"| Y Y \\ | | \\ ___/| | \\ ___/ \\___ \\ | | "<<std::endl
452 <<"|__|_| /__|___| /\\___ >__| \\___ >____ > |__| "<<std::endl
453 <<" \\/ \\/ \\/ \\/ \\/ "<<std::endl;
454 actionstream<<"World at ["<<m_path_world<<"]"<<std::endl;
455 actionstream<<"Server for gameid=\""<<m_gamespec.id
456 <<"\" listening on "<<bind_addr.serializeString()<<":"
457 <<bind_addr.getPort() << "."<<std::endl;
462 DSTACK(__FUNCTION_NAME);
464 infostream<<"Server: Stopping and waiting threads"<<std::endl;
466 // Stop threads (set run=false first so both start stopping)
468 //m_emergethread.setRun(false);
470 //m_emergethread.stop();
472 infostream<<"Server: Threads stopped"<<std::endl;
475 void Server::step(float dtime)
477 DSTACK(__FUNCTION_NAME);
482 JMutexAutoLock lock(m_step_dtime_mutex);
483 m_step_dtime += dtime;
485 // Throw if fatal error occurred in thread
486 std::string async_err = m_async_fatal_error.get();
488 throw ServerError(async_err);
492 void Server::AsyncRunStep(bool initial_step)
494 DSTACK(__FUNCTION_NAME);
496 g_profiler->add("Server::AsyncRunStep (num)", 1);
500 JMutexAutoLock lock1(m_step_dtime_mutex);
501 dtime = m_step_dtime;
505 // Send blocks to clients
509 if((dtime < 0.001) && (initial_step == false))
512 g_profiler->add("Server::AsyncRunStep with dtime (num)", 1);
514 //infostream<<"Server steps "<<dtime<<std::endl;
515 //infostream<<"Server::AsyncRunStep(): dtime="<<dtime<<std::endl;
518 JMutexAutoLock lock1(m_step_dtime_mutex);
519 m_step_dtime -= dtime;
526 m_uptime.set(m_uptime.get() + dtime);
532 Update time of day and overall game time
535 JMutexAutoLock envlock(m_env_mutex);
537 m_env->setTimeOfDaySpeed(g_settings->getFloat("time_speed"));
540 Send to clients at constant intervals
543 m_time_of_day_send_timer -= dtime;
544 if(m_time_of_day_send_timer < 0.0)
546 m_time_of_day_send_timer = g_settings->getFloat("time_send_interval");
547 u16 time = m_env->getTimeOfDay();
548 float time_speed = g_settings->getFloat("time_speed");
549 SendTimeOfDay(PEER_ID_INEXISTENT, time, time_speed);
554 JMutexAutoLock lock(m_env_mutex);
555 // Figure out and report maximum lag to environment
556 float max_lag = m_env->getMaxLagEstimate();
557 max_lag *= 0.9998; // Decrease slowly (about half per 5 minutes)
559 if(dtime > 0.1 && dtime > max_lag * 2.0)
560 infostream<<"Server: Maximum lag peaked to "<<dtime
564 m_env->reportMaxLagEstimate(max_lag);
566 ScopeProfiler sp(g_profiler, "SEnv step");
567 ScopeProfiler sp2(g_profiler, "SEnv step avg", SPT_AVG);
571 const float map_timer_and_unload_dtime = 2.92;
572 if(m_map_timer_and_unload_interval.step(dtime, map_timer_and_unload_dtime))
574 JMutexAutoLock lock(m_env_mutex);
575 // Run Map's timers and unload unused data
576 ScopeProfiler sp(g_profiler, "Server: map timer and unload");
577 m_env->getMap().timerUpdate(map_timer_and_unload_dtime,
578 g_settings->getFloat("server_unload_unused_data_timeout"));
589 JMutexAutoLock lock(m_env_mutex);
591 std::list<u16> clientids = m_clients.getClientIDs();
593 ScopeProfiler sp(g_profiler, "Server: handle players");
595 for(std::list<u16>::iterator
596 i = clientids.begin();
597 i != clientids.end(); ++i)
599 PlayerSAO *playersao = getPlayerSAO(*i);
600 if(playersao == NULL)
604 Handle player HPs (die if hp=0)
606 if(playersao->m_hp_not_sent && g_settings->getBool("enable_damage"))
608 if(playersao->getHP() == 0)
615 Send player breath if changed
617 if(playersao->m_breath_not_sent) {
618 SendPlayerBreath(*i);
622 Send player inventories if necessary
624 if(playersao->m_moved){
626 playersao->m_moved = false;
628 if(playersao->m_inventory_not_sent){
635 /* Transform liquids */
636 m_liquid_transform_timer += dtime;
637 if(m_liquid_transform_timer >= m_liquid_transform_every)
639 m_liquid_transform_timer -= m_liquid_transform_every;
641 JMutexAutoLock lock(m_env_mutex);
643 ScopeProfiler sp(g_profiler, "Server: liquid transform");
645 std::map<v3s16, MapBlock*> modified_blocks;
646 m_env->getMap().transformLiquids(modified_blocks);
651 core::map<v3s16, MapBlock*> lighting_modified_blocks;
652 ServerMap &map = ((ServerMap&)m_env->getMap());
653 map.updateLighting(modified_blocks, lighting_modified_blocks);
655 // Add blocks modified by lighting to modified_blocks
656 for(core::map<v3s16, MapBlock*>::Iterator
657 i = lighting_modified_blocks.getIterator();
658 i.atEnd() == false; i++)
660 MapBlock *block = i.getNode()->getValue();
661 modified_blocks.insert(block->getPos(), block);
665 Set the modified blocks unsent for all the clients
667 if(modified_blocks.size() > 0)
669 SetBlocksNotSent(modified_blocks);
672 m_clients.step(dtime);
674 m_lag += (m_lag > dtime ? -1 : 1) * dtime/100;
676 // send masterserver announce
678 float &counter = m_masterserver_timer;
679 if(!isSingleplayer() && (!counter || counter >= 300.0) &&
680 g_settings->getBool("server_announce"))
682 ServerList::sendAnnounce(counter ? "update" : "start",
683 m_clients.getPlayerNames(),
685 m_env->getGameTime(),
688 m_emerge->params.mg_name,
697 Check added and deleted active objects
700 //infostream<<"Server: Checking added and deleted active objects"<<std::endl;
701 JMutexAutoLock envlock(m_env_mutex);
704 std::map<u16, RemoteClient*> clients = m_clients.getClientList();
705 ScopeProfiler sp(g_profiler, "Server: checking added and deleted objs");
707 // Radius inside which objects are active
708 s16 radius = g_settings->getS16("active_object_send_range_blocks");
709 s16 player_radius = g_settings->getS16("player_transfer_distance");
711 if (player_radius == 0 && g_settings->exists("unlimited_player_transfer_distance") &&
712 !g_settings->getBool("unlimited_player_transfer_distance"))
713 player_radius = radius;
715 radius *= MAP_BLOCKSIZE;
716 player_radius *= MAP_BLOCKSIZE;
718 for(std::map<u16, RemoteClient*>::iterator
720 i != clients.end(); ++i)
722 RemoteClient *client = i->second;
724 // If definitions and textures have not been sent, don't
725 // send objects either
726 if (client->getState() < CS_DefinitionsSent)
729 Player *player = m_env->getPlayer(client->peer_id);
732 // This can happen if the client timeouts somehow
733 /*infostream<<"WARNING: "<<__FUNCTION_NAME<<": Client "
735 <<" has no associated player"<<std::endl;*/
738 v3s16 pos = floatToInt(player->getPosition(), BS);
740 std::set<u16> removed_objects;
741 std::set<u16> added_objects;
742 m_env->getRemovedActiveObjects(pos, radius, player_radius,
743 client->m_known_objects, removed_objects);
744 m_env->getAddedActiveObjects(pos, radius, player_radius,
745 client->m_known_objects, added_objects);
747 // Ignore if nothing happened
748 if(removed_objects.size() == 0 && added_objects.size() == 0)
750 //infostream<<"active objects: none changed"<<std::endl;
754 std::string data_buffer;
758 // Handle removed objects
759 writeU16((u8*)buf, removed_objects.size());
760 data_buffer.append(buf, 2);
761 for(std::set<u16>::iterator
762 i = removed_objects.begin();
763 i != removed_objects.end(); ++i)
767 ServerActiveObject* obj = m_env->getActiveObject(id);
769 // Add to data buffer for sending
770 writeU16((u8*)buf, id);
771 data_buffer.append(buf, 2);
773 // Remove from known objects
774 client->m_known_objects.erase(id);
776 if(obj && obj->m_known_by_count > 0)
777 obj->m_known_by_count--;
780 // Handle added objects
781 writeU16((u8*)buf, added_objects.size());
782 data_buffer.append(buf, 2);
783 for(std::set<u16>::iterator
784 i = added_objects.begin();
785 i != added_objects.end(); ++i)
789 ServerActiveObject* obj = m_env->getActiveObject(id);
792 u8 type = ACTIVEOBJECT_TYPE_INVALID;
794 infostream<<"WARNING: "<<__FUNCTION_NAME
795 <<": NULL object"<<std::endl;
797 type = obj->getSendType();
799 // Add to data buffer for sending
800 writeU16((u8*)buf, id);
801 data_buffer.append(buf, 2);
802 writeU8((u8*)buf, type);
803 data_buffer.append(buf, 1);
806 data_buffer.append(serializeLongString(
807 obj->getClientInitializationData(client->net_proto_version)));
809 data_buffer.append(serializeLongString(""));
811 // Add to known objects
812 client->m_known_objects.insert(id);
815 obj->m_known_by_count++;
819 SharedBuffer<u8> reply(2 + data_buffer.size());
820 writeU16(&reply[0], TOCLIENT_ACTIVE_OBJECT_REMOVE_ADD);
821 memcpy((char*)&reply[2], data_buffer.c_str(),
824 m_clients.send(client->peer_id, 0, reply, true);
826 verbosestream<<"Server: Sent object remove/add: "
827 <<removed_objects.size()<<" removed, "
828 <<added_objects.size()<<" added, "
829 <<"packet size is "<<reply.getSize()<<std::endl;
834 Collect a list of all the objects known by the clients
835 and report it back to the environment.
838 core::map<u16, bool> all_known_objects;
840 for(core::map<u16, RemoteClient*>::Iterator
841 i = m_clients.getIterator();
842 i.atEnd() == false; i++)
844 RemoteClient *client = i.getNode()->getValue();
845 // Go through all known objects of client
846 for(core::map<u16, bool>::Iterator
847 i = client->m_known_objects.getIterator();
848 i.atEnd()==false; i++)
850 u16 id = i.getNode()->getKey();
851 all_known_objects[id] = true;
855 m_env->setKnownActiveObjects(whatever);
864 JMutexAutoLock envlock(m_env_mutex);
865 ScopeProfiler sp(g_profiler, "Server: sending object messages");
868 // Value = data sent by object
869 std::map<u16, std::list<ActiveObjectMessage>* > buffered_messages;
871 // Get active object messages from environment
874 ActiveObjectMessage aom = m_env->getActiveObjectMessage();
878 std::list<ActiveObjectMessage>* message_list = NULL;
879 std::map<u16, std::list<ActiveObjectMessage>* >::iterator n;
880 n = buffered_messages.find(aom.id);
881 if(n == buffered_messages.end())
883 message_list = new std::list<ActiveObjectMessage>;
884 buffered_messages[aom.id] = message_list;
888 message_list = n->second;
890 message_list->push_back(aom);
894 std::map<u16, RemoteClient*> clients = m_clients.getClientList();
895 // Route data to every client
896 for(std::map<u16, RemoteClient*>::iterator
898 i != clients.end(); ++i)
900 RemoteClient *client = i->second;
901 std::string reliable_data;
902 std::string unreliable_data;
903 // Go through all objects in message buffer
904 for(std::map<u16, std::list<ActiveObjectMessage>* >::iterator
905 j = buffered_messages.begin();
906 j != buffered_messages.end(); ++j)
908 // If object is not known by client, skip it
910 if(client->m_known_objects.find(id) == client->m_known_objects.end())
912 // Get message list of object
913 std::list<ActiveObjectMessage>* list = j->second;
914 // Go through every message
915 for(std::list<ActiveObjectMessage>::iterator
916 k = list->begin(); k != list->end(); ++k)
918 // Compose the full new data with header
919 ActiveObjectMessage aom = *k;
920 std::string new_data;
923 writeU16((u8*)&buf[0], aom.id);
924 new_data.append(buf, 2);
926 new_data += serializeString(aom.datastring);
927 // Add data to buffer
929 reliable_data += new_data;
931 unreliable_data += new_data;
935 reliable_data and unreliable_data are now ready.
938 if(reliable_data.size() > 0)
940 SharedBuffer<u8> reply(2 + reliable_data.size());
941 writeU16(&reply[0], TOCLIENT_ACTIVE_OBJECT_MESSAGES);
942 memcpy((char*)&reply[2], reliable_data.c_str(),
943 reliable_data.size());
945 m_clients.send(client->peer_id, 0, reply, true);
947 if(unreliable_data.size() > 0)
949 SharedBuffer<u8> reply(2 + unreliable_data.size());
950 writeU16(&reply[0], TOCLIENT_ACTIVE_OBJECT_MESSAGES);
951 memcpy((char*)&reply[2], unreliable_data.c_str(),
952 unreliable_data.size());
953 // Send as unreliable
954 m_clients.send(client->peer_id, 1, reply, false);
957 /*if(reliable_data.size() > 0 || unreliable_data.size() > 0)
959 infostream<<"Server: Size of object message data: "
960 <<"reliable: "<<reliable_data.size()
961 <<", unreliable: "<<unreliable_data.size()
967 // Clear buffered_messages
968 for(std::map<u16, std::list<ActiveObjectMessage>* >::iterator
969 i = buffered_messages.begin();
970 i != buffered_messages.end(); ++i)
977 Send queued-for-sending map edit events.
980 // We will be accessing the environment
981 JMutexAutoLock lock(m_env_mutex);
983 // Don't send too many at a time
986 // Single change sending is disabled if queue size is not small
987 bool disable_single_change_sending = false;
988 if(m_unsent_map_edit_queue.size() >= 4)
989 disable_single_change_sending = true;
991 int event_count = m_unsent_map_edit_queue.size();
993 // We'll log the amount of each
996 while(m_unsent_map_edit_queue.size() != 0)
998 MapEditEvent* event = m_unsent_map_edit_queue.pop_front();
1000 // Players far away from the change are stored here.
1001 // Instead of sending the changes, MapBlocks are set not sent
1003 std::list<u16> far_players;
1005 if(event->type == MEET_ADDNODE || event->type == MEET_SWAPNODE)
1007 //infostream<<"Server: MEET_ADDNODE"<<std::endl;
1008 prof.add("MEET_ADDNODE", 1);
1009 if(disable_single_change_sending)
1010 sendAddNode(event->p, event->n, event->already_known_by_peer,
1011 &far_players, 5, event->type == MEET_ADDNODE);
1013 sendAddNode(event->p, event->n, event->already_known_by_peer,
1014 &far_players, 30, event->type == MEET_ADDNODE);
1016 else if(event->type == MEET_REMOVENODE)
1018 //infostream<<"Server: MEET_REMOVENODE"<<std::endl;
1019 prof.add("MEET_REMOVENODE", 1);
1020 if(disable_single_change_sending)
1021 sendRemoveNode(event->p, event->already_known_by_peer,
1024 sendRemoveNode(event->p, event->already_known_by_peer,
1027 else if(event->type == MEET_BLOCK_NODE_METADATA_CHANGED)
1029 infostream<<"Server: MEET_BLOCK_NODE_METADATA_CHANGED"<<std::endl;
1030 prof.add("MEET_BLOCK_NODE_METADATA_CHANGED", 1);
1031 setBlockNotSent(event->p);
1033 else if(event->type == MEET_OTHER)
1035 infostream<<"Server: MEET_OTHER"<<std::endl;
1036 prof.add("MEET_OTHER", 1);
1037 for(std::set<v3s16>::iterator
1038 i = event->modified_blocks.begin();
1039 i != event->modified_blocks.end(); ++i)
1041 setBlockNotSent(*i);
1046 prof.add("unknown", 1);
1047 infostream<<"WARNING: Server: Unknown MapEditEvent "
1048 <<((u32)event->type)<<std::endl;
1052 Set blocks not sent to far players
1054 if(far_players.size() > 0)
1056 // Convert list format to that wanted by SetBlocksNotSent
1057 std::map<v3s16, MapBlock*> modified_blocks2;
1058 for(std::set<v3s16>::iterator
1059 i = event->modified_blocks.begin();
1060 i != event->modified_blocks.end(); ++i)
1062 modified_blocks2[*i] =
1063 m_env->getMap().getBlockNoCreateNoEx(*i);
1065 // Set blocks not sent
1066 for(std::list<u16>::iterator
1067 i = far_players.begin();
1068 i != far_players.end(); ++i)
1071 RemoteClient *client = getClient(peer_id);
1074 client->SetBlocksNotSent(modified_blocks2);
1080 /*// Don't send too many at a time
1082 if(count >= 1 && m_unsent_map_edit_queue.size() < 100)
1086 if(event_count >= 5){
1087 infostream<<"Server: MapEditEvents:"<<std::endl;
1088 prof.print(infostream);
1089 } else if(event_count != 0){
1090 verbosestream<<"Server: MapEditEvents:"<<std::endl;
1091 prof.print(verbosestream);
1097 Trigger emergethread (it somehow gets to a non-triggered but
1098 bysy state sometimes)
1101 float &counter = m_emergethread_trigger_timer;
1107 m_emerge->startThreads();
1109 // Update m_enable_rollback_recording here too
1110 m_enable_rollback_recording =
1111 g_settings->getBool("enable_rollback_recording");
1115 // Save map, players and auth stuff
1117 float &counter = m_savemap_timer;
1119 if(counter >= g_settings->getFloat("server_map_save_interval"))
1122 JMutexAutoLock lock(m_env_mutex);
1124 ScopeProfiler sp(g_profiler, "Server: saving stuff");
1127 if (m_banmanager->isModified()) {
1128 m_banmanager->save();
1131 // Save changed parts of map
1132 m_env->getMap().save(MOD_STATE_WRITE_NEEDED);
1135 m_env->saveLoadedPlayers();
1137 // Save environment metadata
1143 void Server::Receive()
1145 DSTACK(__FUNCTION_NAME);
1146 SharedBuffer<u8> data;
1150 datasize = m_con.Receive(peer_id,data);
1151 ProcessData(*data, datasize, peer_id);
1153 catch(con::InvalidIncomingDataException &e)
1155 infostream<<"Server::Receive(): "
1156 "InvalidIncomingDataException: what()="
1157 <<e.what()<<std::endl;
1159 catch(SerializationError &e) {
1160 infostream<<"Server::Receive(): "
1161 "SerializationError: what()="
1162 <<e.what()<<std::endl;
1164 catch(ClientStateError &e)
1166 errorstream << "ProcessData: peer=" << peer_id << e.what() << std::endl;
1167 DenyAccess(peer_id, L"Your client sent something server didn't expect."
1168 L"Try reconnecting or updating your client");
1170 catch(con::PeerNotFoundException &e)
1176 PlayerSAO* Server::StageTwoClientInit(u16 peer_id)
1178 std::string playername = "";
1179 PlayerSAO *playersao = NULL;
1182 RemoteClient* client = m_clients.lockedGetClientNoEx(peer_id, CS_InitDone);
1183 if (client != NULL) {
1184 playername = client->getName();
1185 playersao = emergePlayer(playername.c_str(), peer_id);
1187 } catch (std::exception &e) {
1193 RemotePlayer *player =
1194 static_cast<RemotePlayer*>(m_env->getPlayer(playername.c_str()));
1196 // If failed, cancel
1197 if((playersao == NULL) || (player == NULL))
1199 if(player && player->peer_id != 0){
1200 errorstream<<"Server: "<<playername<<": Failed to emerge player"
1201 <<" (player allocated to an another client)"<<std::endl;
1202 DenyAccess(peer_id, L"Another client is connected with this "
1203 L"name. If your client closed unexpectedly, try again in "
1206 errorstream<<"Server: "<<playername<<": Failed to emerge player"
1208 DenyAccess(peer_id, L"Could not allocate player.");
1214 Send complete position information
1216 SendMovePlayer(peer_id);
1219 SendPlayerPrivileges(peer_id);
1221 // Send inventory formspec
1222 SendPlayerInventoryFormspec(peer_id);
1225 UpdateCrafting(peer_id);
1226 SendInventory(peer_id);
1229 if(g_settings->getBool("enable_damage"))
1230 SendPlayerHP(peer_id);
1233 SendPlayerBreath(peer_id);
1235 // Show death screen if necessary
1237 SendDeathscreen(peer_id, false, v3f(0,0,0));
1239 // Note things in chat if not in simple singleplayer mode
1240 if(!m_simple_singleplayer_mode)
1242 // Send information about server to player in chat
1243 SendChatMessage(peer_id, getStatusString());
1245 // Send information about joining in chat
1247 std::wstring name = L"unknown";
1248 Player *player = m_env->getPlayer(peer_id);
1250 name = narrow_to_wide(player->getName());
1252 std::wstring message;
1255 message += L" joined the game.";
1256 SendChatMessage(PEER_ID_INEXISTENT,message);
1259 Address addr = getPeerAddress(player->peer_id);
1260 std::string ip_str = addr.serializeString();
1261 actionstream<<player->getName() <<" [" << ip_str << "] joins game. " << std::endl;
1266 std::vector<std::string> names = m_clients.getPlayerNames();
1268 actionstream<<player->getName() <<" joins game. List of players: ";
1270 for (std::vector<std::string>::iterator i = names.begin();
1271 i != names.end(); i++)
1273 actionstream << *i << " ";
1276 actionstream << player->getName() <<std::endl;
1281 void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
1283 DSTACK(__FUNCTION_NAME);
1284 // Environment is locked first.
1285 JMutexAutoLock envlock(m_env_mutex);
1287 ScopeProfiler sp(g_profiler, "Server::ProcessData");
1291 Address address = getPeerAddress(peer_id);
1292 addr_s = address.serializeString();
1294 // drop player if is ip is banned
1295 if(m_banmanager->isIpBanned(addr_s)){
1296 std::string ban_name = m_banmanager->getBanName(addr_s);
1297 infostream<<"Server: A banned client tried to connect from "
1298 <<addr_s<<"; banned name was "
1299 <<ban_name<<std::endl;
1300 // This actually doesn't seem to transfer to the client
1301 DenyAccess(peer_id, L"Your ip is banned. Banned name was "
1302 +narrow_to_wide(ban_name));
1306 catch(con::PeerNotFoundException &e)
1309 * no peer for this packet found
1310 * most common reason is peer timeout, e.g. peer didn't
1311 * respond for some time, your server was overloaded or
1314 infostream<<"Server::ProcessData(): Cancelling: peer "
1315 <<peer_id<<" not found"<<std::endl;
1325 ToServerCommand command = (ToServerCommand)readU16(&data[0]);
1327 if(command == TOSERVER_INIT)
1329 // [0] u16 TOSERVER_INIT
1330 // [2] u8 SER_FMT_VER_HIGHEST_READ
1331 // [3] u8[20] player_name
1332 // [23] u8[28] password <--- can be sent without this, from old versions
1334 if(datasize < 2+1+PLAYERNAME_SIZE)
1337 RemoteClient* client = getClient(peer_id, CS_Created);
1339 // If net_proto_version is set, this client has already been handled
1340 if(client->getState() > CS_Created)
1342 verbosestream<<"Server: Ignoring multiple TOSERVER_INITs from "
1343 <<addr_s<<" (peer_id="<<peer_id<<")"<<std::endl;
1347 verbosestream<<"Server: Got TOSERVER_INIT from "<<addr_s<<" (peer_id="
1348 <<peer_id<<")"<<std::endl;
1350 // Do not allow multiple players in simple singleplayer mode.
1351 // This isn't a perfect way to do it, but will suffice for now
1352 if(m_simple_singleplayer_mode && m_clients.getClientIDs().size() > 1){
1353 infostream<<"Server: Not allowing another client ("<<addr_s
1354 <<") to connect in simple singleplayer mode"<<std::endl;
1355 DenyAccess(peer_id, L"Running in simple singleplayer mode.");
1359 // First byte after command is maximum supported
1360 // serialization version
1361 u8 client_max = data[2];
1362 u8 our_max = SER_FMT_VER_HIGHEST_READ;
1363 // Use the highest version supported by both
1364 u8 deployed = std::min(client_max, our_max);
1365 // If it's lower than the lowest supported, give up.
1366 if(deployed < SER_FMT_VER_LOWEST)
1367 deployed = SER_FMT_VER_INVALID;
1369 if(deployed == SER_FMT_VER_INVALID)
1371 actionstream<<"Server: A mismatched client tried to connect from "
1372 <<addr_s<<std::endl;
1373 infostream<<"Server: Cannot negotiate serialization version with "
1374 <<addr_s<<std::endl;
1375 DenyAccess(peer_id, std::wstring(
1376 L"Your client's version is not supported.\n"
1377 L"Server version is ")
1378 + narrow_to_wide(minetest_version_simple) + L"."
1383 client->setPendingSerializationVersion(deployed);
1386 Read and check network protocol version
1389 u16 min_net_proto_version = 0;
1390 if(datasize >= 2+1+PLAYERNAME_SIZE+PASSWORD_SIZE+2)
1391 min_net_proto_version = readU16(&data[2+1+PLAYERNAME_SIZE+PASSWORD_SIZE]);
1393 // Use same version as minimum and maximum if maximum version field
1394 // doesn't exist (backwards compatibility)
1395 u16 max_net_proto_version = min_net_proto_version;
1396 if(datasize >= 2+1+PLAYERNAME_SIZE+PASSWORD_SIZE+2+2)
1397 max_net_proto_version = readU16(&data[2+1+PLAYERNAME_SIZE+PASSWORD_SIZE+2]);
1399 // Start with client's maximum version
1400 u16 net_proto_version = max_net_proto_version;
1402 // Figure out a working version if it is possible at all
1403 if(max_net_proto_version >= SERVER_PROTOCOL_VERSION_MIN ||
1404 min_net_proto_version <= SERVER_PROTOCOL_VERSION_MAX)
1406 // If maximum is larger than our maximum, go with our maximum
1407 if(max_net_proto_version > SERVER_PROTOCOL_VERSION_MAX)
1408 net_proto_version = SERVER_PROTOCOL_VERSION_MAX;
1409 // Else go with client's maximum
1411 net_proto_version = max_net_proto_version;
1414 verbosestream<<"Server: "<<addr_s<<": Protocol version: min: "
1415 <<min_net_proto_version<<", max: "<<max_net_proto_version
1416 <<", chosen: "<<net_proto_version<<std::endl;
1418 client->net_proto_version = net_proto_version;
1420 if(net_proto_version < SERVER_PROTOCOL_VERSION_MIN ||
1421 net_proto_version > SERVER_PROTOCOL_VERSION_MAX)
1423 actionstream<<"Server: A mismatched client tried to connect from "
1424 <<addr_s<<std::endl;
1425 DenyAccess(peer_id, std::wstring(
1426 L"Your client's version is not supported.\n"
1427 L"Server version is ")
1428 + narrow_to_wide(minetest_version_simple) + L",\n"
1429 + L"server's PROTOCOL_VERSION is "
1430 + narrow_to_wide(itos(SERVER_PROTOCOL_VERSION_MIN))
1432 + narrow_to_wide(itos(SERVER_PROTOCOL_VERSION_MAX))
1433 + L", client's PROTOCOL_VERSION is "
1434 + narrow_to_wide(itos(min_net_proto_version))
1436 + narrow_to_wide(itos(max_net_proto_version))
1441 if(g_settings->getBool("strict_protocol_version_checking"))
1443 if(net_proto_version != LATEST_PROTOCOL_VERSION)
1445 actionstream<<"Server: A mismatched (strict) client tried to "
1446 <<"connect from "<<addr_s<<std::endl;
1447 DenyAccess(peer_id, std::wstring(
1448 L"Your client's version is not supported.\n"
1449 L"Server version is ")
1450 + narrow_to_wide(minetest_version_simple) + L",\n"
1451 + L"server's PROTOCOL_VERSION (strict) is "
1452 + narrow_to_wide(itos(LATEST_PROTOCOL_VERSION))
1453 + L", client's PROTOCOL_VERSION is "
1454 + narrow_to_wide(itos(min_net_proto_version))
1456 + narrow_to_wide(itos(max_net_proto_version))
1465 char playername[PLAYERNAME_SIZE];
1466 unsigned int playername_length = 0;
1467 for (; playername_length < PLAYERNAME_SIZE; playername_length++ ) {
1468 playername[playername_length] = data[3+playername_length];
1469 if (data[3+playername_length] == 0)
1473 if (playername_length == PLAYERNAME_SIZE) {
1474 actionstream<<"Server: Player with name exceeding max length "
1475 <<"tried to connect from "<<addr_s<<std::endl;
1476 DenyAccess(peer_id, L"Name too long");
1481 if(playername[0]=='\0')
1483 actionstream<<"Server: Player with an empty name "
1484 <<"tried to connect from "<<addr_s<<std::endl;
1485 DenyAccess(peer_id, L"Empty name");
1489 if(string_allowed(playername, PLAYERNAME_ALLOWED_CHARS)==false)
1491 actionstream<<"Server: Player with an invalid name "
1492 <<"tried to connect from "<<addr_s<<std::endl;
1493 DenyAccess(peer_id, L"Name contains unallowed characters");
1497 if(!isSingleplayer() && strcasecmp(playername, "singleplayer") == 0)
1499 actionstream<<"Server: Player with the name \"singleplayer\" "
1500 <<"tried to connect from "<<addr_s<<std::endl;
1501 DenyAccess(peer_id, L"Name is not allowed");
1507 if(m_script->on_prejoinplayer(playername, addr_s, reason))
1509 actionstream<<"Server: Player with the name \""<<playername<<"\" "
1510 <<"tried to connect from "<<addr_s<<" "
1511 <<"but it was disallowed for the following reason: "
1512 <<reason<<std::endl;
1513 DenyAccess(peer_id, narrow_to_wide(reason.c_str()));
1518 infostream<<"Server: New connection: \""<<playername<<"\" from "
1519 <<addr_s<<" (peer_id="<<peer_id<<")"<<std::endl;
1522 char given_password[PASSWORD_SIZE];
1523 if(datasize < 2+1+PLAYERNAME_SIZE+PASSWORD_SIZE)
1525 // old version - assume blank password
1526 given_password[0] = 0;
1530 for(u32 i=0; i<PASSWORD_SIZE-1; i++)
1532 given_password[i] = data[23+i];
1534 given_password[PASSWORD_SIZE-1] = 0;
1537 if(!base64_is_valid(given_password)){
1538 actionstream<<"Server: "<<playername
1539 <<" supplied invalid password hash"<<std::endl;
1540 DenyAccess(peer_id, L"Invalid password hash");
1544 // Enforce user limit.
1545 // Don't enforce for users that have some admin right
1546 if(m_clients.getClientIDs(CS_Created).size() >= g_settings->getU16("max_users") &&
1547 !checkPriv(playername, "server") &&
1548 !checkPriv(playername, "ban") &&
1549 !checkPriv(playername, "privs") &&
1550 !checkPriv(playername, "password") &&
1551 playername != g_settings->get("name"))
1553 actionstream<<"Server: "<<playername<<" tried to join, but there"
1554 <<" are already max_users="
1555 <<g_settings->getU16("max_users")<<" players."<<std::endl;
1556 DenyAccess(peer_id, L"Too many users.");
1560 std::string checkpwd; // Password hash to check against
1561 bool has_auth = m_script->getAuth(playername, &checkpwd, NULL);
1563 // If no authentication info exists for user, create it
1565 if(!isSingleplayer() &&
1566 g_settings->getBool("disallow_empty_password") &&
1567 std::string(given_password) == ""){
1568 actionstream<<"Server: "<<playername
1569 <<" supplied empty password"<<std::endl;
1570 DenyAccess(peer_id, L"Empty passwords are "
1571 L"disallowed. Set a password and try again.");
1574 std::wstring raw_default_password =
1575 narrow_to_wide(g_settings->get("default_password"));
1576 std::string initial_password =
1577 translatePassword(playername, raw_default_password);
1579 // If default_password is empty, allow any initial password
1580 if (raw_default_password.length() == 0)
1581 initial_password = given_password;
1583 m_script->createAuth(playername, initial_password);
1586 has_auth = m_script->getAuth(playername, &checkpwd, NULL);
1589 actionstream<<"Server: "<<playername<<" cannot be authenticated"
1590 <<" (auth handler does not work?)"<<std::endl;
1591 DenyAccess(peer_id, L"Not allowed to login");
1595 if(given_password != checkpwd){
1596 actionstream<<"Server: "<<playername<<" supplied wrong password"
1598 DenyAccess(peer_id, L"Wrong password");
1602 RemotePlayer *player =
1603 static_cast<RemotePlayer*>(m_env->getPlayer(playername));
1605 if(player && player->peer_id != 0){
1606 errorstream<<"Server: "<<playername<<": Failed to emerge player"
1607 <<" (player allocated to an another client)"<<std::endl;
1608 DenyAccess(peer_id, L"Another client is connected with this "
1609 L"name. If your client closed unexpectedly, try again in "
1613 m_clients.setPlayerName(peer_id,playername);
1616 Answer with a TOCLIENT_INIT
1619 SharedBuffer<u8> reply(2+1+6+8+4);
1620 writeU16(&reply[0], TOCLIENT_INIT);
1621 writeU8(&reply[2], deployed);
1622 //send dummy pos for legacy reasons only
1623 writeV3S16(&reply[2+1], floatToInt(v3f(0,0,0), BS));
1624 writeU64(&reply[2+1+6], m_env->getServerMap().getSeed());
1625 writeF1000(&reply[2+1+6+8], g_settings->getFloat("dedicated_server_step"));
1628 m_clients.send(peer_id, 0, reply, true);
1629 m_clients.event(peer_id, CSE_Init);
1635 if(command == TOSERVER_INIT2)
1638 verbosestream<<"Server: Got TOSERVER_INIT2 from "
1639 <<peer_id<<std::endl;
1641 m_clients.event(peer_id, CSE_GotInit2);
1642 u16 protocol_version = m_clients.getProtocolVersion(peer_id);
1645 ///// begin compatibility code
1646 PlayerSAO* playersao = NULL;
1647 if (protocol_version <= 22) {
1648 playersao = StageTwoClientInit(peer_id);
1650 if (playersao == NULL) {
1652 << "TOSERVER_INIT2 stage 2 client init failed for peer "
1653 << peer_id << std::endl;
1657 ///// end compatibility code
1660 Send some initialization data
1663 infostream<<"Server: Sending content to "
1664 <<getPlayerName(peer_id)<<std::endl;
1666 // Send player movement settings
1667 SendMovement(peer_id);
1669 // Send item definitions
1670 SendItemDef(peer_id, m_itemdef, protocol_version);
1672 // Send node definitions
1673 SendNodeDef(peer_id, m_nodedef, protocol_version);
1675 m_clients.event(peer_id, CSE_SetDefinitionsSent);
1677 // Send media announcement
1678 sendMediaAnnouncement(peer_id);
1680 // Send detached inventories
1681 sendDetachedInventories(peer_id);
1684 u16 time = m_env->getTimeOfDay();
1685 float time_speed = g_settings->getFloat("time_speed");
1686 SendTimeOfDay(peer_id, time, time_speed);
1688 ///// begin compatibility code
1689 if (protocol_version <= 22) {
1690 m_clients.event(peer_id, CSE_SetClientReady);
1691 m_script->on_joinplayer(playersao);
1693 ///// end compatibility code
1695 // Warnings about protocol version can be issued here
1696 if(getClient(peer_id)->net_proto_version < LATEST_PROTOCOL_VERSION)
1698 SendChatMessage(peer_id, L"# Server: WARNING: YOUR CLIENT'S "
1699 L"VERSION MAY NOT BE FULLY COMPATIBLE WITH THIS SERVER!");
1705 u8 peer_ser_ver = getClient(peer_id, CS_InitDone)->serialization_version;
1706 u16 peer_proto_ver = getClient(peer_id, CS_InitDone)->net_proto_version;
1708 if(peer_ser_ver == SER_FMT_VER_INVALID)
1710 errorstream<<"Server::ProcessData(): Cancelling: Peer"
1711 " serialization format invalid or not initialized."
1712 " Skipping incoming command="<<command<<std::endl;
1716 /* Handle commands relate to client startup */
1717 if(command == TOSERVER_REQUEST_MEDIA) {
1718 std::string datastring((char*)&data[2], datasize-2);
1719 std::istringstream is(datastring, std::ios_base::binary);
1721 std::list<std::string> tosend;
1722 u16 numfiles = readU16(is);
1724 infostream<<"Sending "<<numfiles<<" files to "
1725 <<getPlayerName(peer_id)<<std::endl;
1726 verbosestream<<"TOSERVER_REQUEST_MEDIA: "<<std::endl;
1728 for(int i = 0; i < numfiles; i++) {
1729 std::string name = deSerializeString(is);
1730 tosend.push_back(name);
1731 verbosestream<<"TOSERVER_REQUEST_MEDIA: requested file "
1735 sendRequestedMedia(peer_id, tosend);
1738 else if(command == TOSERVER_RECEIVED_MEDIA) {
1741 else if(command == TOSERVER_CLIENT_READY) {
1742 // clients <= protocol version 22 did not send ready message,
1743 // they're already initialized
1744 if (peer_proto_ver <= 22) {
1745 infostream << "Client sent message not expected by a "
1746 << "client using protocol version <= 22,"
1747 << "disconnecing peer_id: " << peer_id << std::endl;
1748 m_con.DisconnectPeer(peer_id);
1752 PlayerSAO* playersao = StageTwoClientInit(peer_id);
1754 if (playersao == NULL) {
1756 << "TOSERVER_CLIENT_READY stage 2 client init failed for peer_id: "
1757 << peer_id << std::endl;
1758 m_con.DisconnectPeer(peer_id);
1763 if(datasize < 2+8) {
1765 << "TOSERVER_CLIENT_READY client sent inconsistent data, disconnecting peer_id: "
1766 << peer_id << std::endl;
1767 m_con.DisconnectPeer(peer_id);
1771 m_clients.setClientVersion(
1773 data[2], data[3], data[4],
1774 std::string((char*) &data[8],(u16) data[6]));
1776 m_clients.event(peer_id, CSE_SetClientReady);
1777 m_script->on_joinplayer(playersao);
1780 else if(command == TOSERVER_GOTBLOCKS)
1793 u16 count = data[2];
1794 for(u16 i=0; i<count; i++)
1796 if((s16)datasize < 2+1+(i+1)*6)
1797 throw con::InvalidIncomingDataException
1798 ("GOTBLOCKS length is too short");
1799 v3s16 p = readV3S16(&data[2+1+i*6]);
1800 /*infostream<<"Server: GOTBLOCKS ("
1801 <<p.X<<","<<p.Y<<","<<p.Z<<")"<<std::endl;*/
1802 RemoteClient *client = getClient(peer_id);
1803 client->GotBlock(p);
1808 if (m_clients.getClientState(peer_id) < CS_Active)
1810 if (command == TOSERVER_PLAYERPOS) return;
1812 errorstream<<"Got packet command: " << command << " for peer id "
1813 << peer_id << " but client isn't active yet. Dropping packet "
1818 Player *player = m_env->getPlayer(peer_id);
1819 if(player == NULL) {
1820 errorstream<<"Server::ProcessData(): Cancelling: "
1821 "No player for peer_id="<<peer_id
1822 << " disconnecting peer!" <<std::endl;
1823 m_con.DisconnectPeer(peer_id);
1827 PlayerSAO *playersao = player->getPlayerSAO();
1828 if(playersao == NULL) {
1829 errorstream<<"Server::ProcessData(): Cancelling: "
1830 "No player object for peer_id="<<peer_id
1831 << " disconnecting peer!" <<std::endl;
1832 m_con.DisconnectPeer(peer_id);
1836 if(command == TOSERVER_PLAYERPOS)
1838 if(datasize < 2+12+12+4+4)
1842 v3s32 ps = readV3S32(&data[start+2]);
1843 v3s32 ss = readV3S32(&data[start+2+12]);
1844 f32 pitch = (f32)readS32(&data[2+12+12]) / 100.0;
1845 f32 yaw = (f32)readS32(&data[2+12+12+4]) / 100.0;
1847 if(datasize >= 2+12+12+4+4+4)
1848 keyPressed = (u32)readU32(&data[2+12+12+4+4]);
1849 v3f position((f32)ps.X/100., (f32)ps.Y/100., (f32)ps.Z/100.);
1850 v3f speed((f32)ss.X/100., (f32)ss.Y/100., (f32)ss.Z/100.);
1851 pitch = wrapDegrees(pitch);
1852 yaw = wrapDegrees(yaw);
1854 player->setPosition(position);
1855 player->setSpeed(speed);
1856 player->setPitch(pitch);
1857 player->setYaw(yaw);
1858 player->keyPressed=keyPressed;
1859 player->control.up = (bool)(keyPressed&1);
1860 player->control.down = (bool)(keyPressed&2);
1861 player->control.left = (bool)(keyPressed&4);
1862 player->control.right = (bool)(keyPressed&8);
1863 player->control.jump = (bool)(keyPressed&16);
1864 player->control.aux1 = (bool)(keyPressed&32);
1865 player->control.sneak = (bool)(keyPressed&64);
1866 player->control.LMB = (bool)(keyPressed&128);
1867 player->control.RMB = (bool)(keyPressed&256);
1869 bool cheated = playersao->checkMovementCheat();
1872 m_script->on_cheat(playersao, "moved_too_fast");
1875 /*infostream<<"Server::ProcessData(): Moved player "<<peer_id<<" to "
1876 <<"("<<position.X<<","<<position.Y<<","<<position.Z<<")"
1877 <<" pitch="<<pitch<<" yaw="<<yaw<<std::endl;*/
1879 else if(command == TOSERVER_DELETEDBLOCKS)
1892 u16 count = data[2];
1893 for(u16 i=0; i<count; i++)
1895 if((s16)datasize < 2+1+(i+1)*6)
1896 throw con::InvalidIncomingDataException
1897 ("DELETEDBLOCKS length is too short");
1898 v3s16 p = readV3S16(&data[2+1+i*6]);
1899 /*infostream<<"Server: DELETEDBLOCKS ("
1900 <<p.X<<","<<p.Y<<","<<p.Z<<")"<<std::endl;*/
1901 RemoteClient *client = getClient(peer_id);
1902 client->SetBlockNotSent(p);
1905 else if(command == TOSERVER_CLICK_OBJECT)
1907 infostream<<"Server: CLICK_OBJECT not supported anymore"<<std::endl;
1910 else if(command == TOSERVER_CLICK_ACTIVEOBJECT)
1912 infostream<<"Server: CLICK_ACTIVEOBJECT not supported anymore"<<std::endl;
1915 else if(command == TOSERVER_GROUND_ACTION)
1917 infostream<<"Server: GROUND_ACTION not supported anymore"<<std::endl;
1921 else if(command == TOSERVER_RELEASE)
1923 infostream<<"Server: RELEASE not supported anymore"<<std::endl;
1926 else if(command == TOSERVER_SIGNTEXT)
1928 infostream<<"Server: SIGNTEXT not supported anymore"
1932 else if(command == TOSERVER_SIGNNODETEXT)
1934 infostream<<"Server: SIGNNODETEXT not supported anymore"
1938 else if(command == TOSERVER_INVENTORY_ACTION)
1940 // Strip command and create a stream
1941 std::string datastring((char*)&data[2], datasize-2);
1942 verbosestream<<"TOSERVER_INVENTORY_ACTION: data="<<datastring<<std::endl;
1943 std::istringstream is(datastring, std::ios_base::binary);
1945 InventoryAction *a = InventoryAction::deSerialize(is);
1948 infostream<<"TOSERVER_INVENTORY_ACTION: "
1949 <<"InventoryAction::deSerialize() returned NULL"
1954 // If something goes wrong, this player is to blame
1955 RollbackScopeActor rollback_scope(m_rollback,
1956 std::string("player:")+player->getName());
1959 Note: Always set inventory not sent, to repair cases
1960 where the client made a bad prediction.
1964 Handle restrictions and special cases of the move action
1966 if(a->getType() == IACTION_MOVE)
1968 IMoveAction *ma = (IMoveAction*)a;
1970 ma->from_inv.applyCurrentPlayer(player->getName());
1971 ma->to_inv.applyCurrentPlayer(player->getName());
1973 setInventoryModified(ma->from_inv);
1974 setInventoryModified(ma->to_inv);
1976 bool from_inv_is_current_player =
1977 (ma->from_inv.type == InventoryLocation::PLAYER) &&
1978 (ma->from_inv.name == player->getName());
1980 bool to_inv_is_current_player =
1981 (ma->to_inv.type == InventoryLocation::PLAYER) &&
1982 (ma->to_inv.name == player->getName());
1985 Disable moving items out of craftpreview
1987 if(ma->from_list == "craftpreview")
1989 infostream<<"Ignoring IMoveAction from "
1990 <<(ma->from_inv.dump())<<":"<<ma->from_list
1991 <<" to "<<(ma->to_inv.dump())<<":"<<ma->to_list
1992 <<" because src is "<<ma->from_list<<std::endl;
1998 Disable moving items into craftresult and craftpreview
2000 if(ma->to_list == "craftpreview" || ma->to_list == "craftresult")
2002 infostream<<"Ignoring IMoveAction from "
2003 <<(ma->from_inv.dump())<<":"<<ma->from_list
2004 <<" to "<<(ma->to_inv.dump())<<":"<<ma->to_list
2005 <<" because dst is "<<ma->to_list<<std::endl;
2010 // Disallow moving items in elsewhere than player's inventory
2011 // if not allowed to interact
2012 if(!checkPriv(player->getName(), "interact") &&
2013 (!from_inv_is_current_player ||
2014 !to_inv_is_current_player))
2016 infostream<<"Cannot move outside of player's inventory: "
2017 <<"No interact privilege"<<std::endl;
2023 Handle restrictions and special cases of the drop action
2025 else if(a->getType() == IACTION_DROP)
2027 IDropAction *da = (IDropAction*)a;
2029 da->from_inv.applyCurrentPlayer(player->getName());
2031 setInventoryModified(da->from_inv);
2034 Disable dropping items out of craftpreview
2036 if(da->from_list == "craftpreview")
2038 infostream<<"Ignoring IDropAction from "
2039 <<(da->from_inv.dump())<<":"<<da->from_list
2040 <<" because src is "<<da->from_list<<std::endl;
2045 // Disallow dropping items if not allowed to interact
2046 if(!checkPriv(player->getName(), "interact"))
2053 Handle restrictions and special cases of the craft action
2055 else if(a->getType() == IACTION_CRAFT)
2057 ICraftAction *ca = (ICraftAction*)a;
2059 ca->craft_inv.applyCurrentPlayer(player->getName());
2061 setInventoryModified(ca->craft_inv);
2063 //bool craft_inv_is_current_player =
2064 // (ca->craft_inv.type == InventoryLocation::PLAYER) &&
2065 // (ca->craft_inv.name == player->getName());
2067 // Disallow crafting if not allowed to interact
2068 if(!checkPriv(player->getName(), "interact"))
2070 infostream<<"Cannot craft: "
2071 <<"No interact privilege"<<std::endl;
2078 a->apply(this, playersao, this);
2082 else if(command == TOSERVER_CHAT_MESSAGE)
2090 std::string datastring((char*)&data[2], datasize-2);
2091 std::istringstream is(datastring, std::ios_base::binary);
2094 is.read((char*)buf, 2);
2095 u16 len = readU16(buf);
2097 std::wstring message;
2098 for(u16 i=0; i<len; i++)
2100 is.read((char*)buf, 2);
2101 message += (wchar_t)readU16(buf);
2104 // If something goes wrong, this player is to blame
2105 RollbackScopeActor rollback_scope(m_rollback,
2106 std::string("player:")+player->getName());
2108 // Get player name of this client
2109 std::wstring name = narrow_to_wide(player->getName());
2112 bool ate = m_script->on_chat_message(player->getName(),
2113 wide_to_narrow(message));
2114 // If script ate the message, don't proceed
2118 // Line to send to players
2120 // Whether to send to the player that sent the line
2121 bool send_to_sender_only = false;
2123 // Commands are implemented in Lua, so only catch invalid
2124 // commands that were not "eaten" and send an error back
2125 if(message[0] == L'/')
2127 message = message.substr(1);
2128 send_to_sender_only = true;
2129 if(message.length() == 0)
2130 line += L"-!- Empty command";
2132 line += L"-!- Invalid command: " + str_split(message, L' ')[0];
2136 if(checkPriv(player->getName(), "shout")){
2142 line += L"-!- You don't have permission to shout.";
2143 send_to_sender_only = true;
2150 Send the message to sender
2152 if (send_to_sender_only)
2154 SendChatMessage(peer_id, line);
2157 Send the message to others
2161 actionstream<<"CHAT: "<<wide_to_narrow(line)<<std::endl;
2163 std::list<u16> clients = m_clients.getClientIDs();
2165 for(std::list<u16>::iterator
2166 i = clients.begin();
2167 i != clients.end(); ++i)
2170 SendChatMessage(*i, line);
2175 else if(command == TOSERVER_DAMAGE)
2177 std::string datastring((char*)&data[2], datasize-2);
2178 std::istringstream is(datastring, std::ios_base::binary);
2179 u8 damage = readU8(is);
2181 if(g_settings->getBool("enable_damage"))
2183 actionstream<<player->getName()<<" damaged by "
2184 <<(int)damage<<" hp at "<<PP(player->getPosition()/BS)
2187 playersao->setHP(playersao->getHP() - damage);
2189 if(playersao->getHP() == 0 && playersao->m_hp_not_sent)
2192 if(playersao->m_hp_not_sent)
2193 SendPlayerHP(peer_id);
2196 else if(command == TOSERVER_BREATH)
2198 std::string datastring((char*)&data[2], datasize-2);
2199 std::istringstream is(datastring, std::ios_base::binary);
2200 u16 breath = readU16(is);
2201 playersao->setBreath(breath);
2202 m_script->player_event(playersao,"breath_changed");
2204 else if(command == TOSERVER_PASSWORD)
2207 [0] u16 TOSERVER_PASSWORD
2208 [2] u8[28] old password
2209 [30] u8[28] new password
2212 if(datasize != 2+PASSWORD_SIZE*2)
2214 /*char password[PASSWORD_SIZE];
2215 for(u32 i=0; i<PASSWORD_SIZE-1; i++)
2216 password[i] = data[2+i];
2217 password[PASSWORD_SIZE-1] = 0;*/
2219 for(u32 i=0; i<PASSWORD_SIZE-1; i++)
2227 for(u32 i=0; i<PASSWORD_SIZE-1; i++)
2229 char c = data[2+PASSWORD_SIZE+i];
2235 if(!base64_is_valid(newpwd)){
2236 infostream<<"Server: "<<player->getName()<<" supplied invalid password hash"<<std::endl;
2237 // Wrong old password supplied!!
2238 SendChatMessage(peer_id, L"Invalid new password hash supplied. Password NOT changed.");
2242 infostream<<"Server: Client requests a password change from "
2243 <<"'"<<oldpwd<<"' to '"<<newpwd<<"'"<<std::endl;
2245 std::string playername = player->getName();
2247 std::string checkpwd;
2248 m_script->getAuth(playername, &checkpwd, NULL);
2250 if(oldpwd != checkpwd)
2252 infostream<<"Server: invalid old password"<<std::endl;
2253 // Wrong old password supplied!!
2254 SendChatMessage(peer_id, L"Invalid old password supplied. Password NOT changed.");
2258 bool success = m_script->setPassword(playername, newpwd);
2260 actionstream<<player->getName()<<" changes password"<<std::endl;
2261 SendChatMessage(peer_id, L"Password change successful.");
2263 actionstream<<player->getName()<<" tries to change password but "
2264 <<"it fails"<<std::endl;
2265 SendChatMessage(peer_id, L"Password change failed or inavailable.");
2268 else if(command == TOSERVER_PLAYERITEM)
2273 u16 item = readU16(&data[2]);
2274 playersao->setWieldIndex(item);
2276 else if(command == TOSERVER_RESPAWN)
2278 if(player->hp != 0 || !g_settings->getBool("enable_damage"))
2281 RespawnPlayer(peer_id);
2283 actionstream<<player->getName()<<" respawns at "
2284 <<PP(player->getPosition()/BS)<<std::endl;
2286 // ActiveObject is added to environment in AsyncRunStep after
2287 // the previous addition has been succesfully removed
2289 else if(command == TOSERVER_INTERACT)
2291 std::string datastring((char*)&data[2], datasize-2);
2292 std::istringstream is(datastring, std::ios_base::binary);
2298 [5] u32 length of the next item
2299 [9] serialized PointedThing
2301 0: start digging (from undersurface) or use
2302 1: stop digging (all parameters ignored)
2303 2: digging completed
2304 3: place block or item (to abovesurface)
2307 u8 action = readU8(is);
2308 u16 item_i = readU16(is);
2309 std::istringstream tmp_is(deSerializeLongString(is), std::ios::binary);
2310 PointedThing pointed;
2311 pointed.deSerialize(tmp_is);
2313 verbosestream<<"TOSERVER_INTERACT: action="<<(int)action<<", item="
2314 <<item_i<<", pointed="<<pointed.dump()<<std::endl;
2318 verbosestream<<"TOSERVER_INTERACT: "<<player->getName()
2319 <<" tried to interact, but is dead!"<<std::endl;
2323 v3f player_pos = playersao->getLastGoodPosition();
2325 // Update wielded item
2326 playersao->setWieldIndex(item_i);
2328 // Get pointed to node (undefined if not POINTEDTYPE_NODE)
2329 v3s16 p_under = pointed.node_undersurface;
2330 v3s16 p_above = pointed.node_abovesurface;
2332 // Get pointed to object (NULL if not POINTEDTYPE_OBJECT)
2333 ServerActiveObject *pointed_object = NULL;
2334 if(pointed.type == POINTEDTHING_OBJECT)
2336 pointed_object = m_env->getActiveObject(pointed.object_id);
2337 if(pointed_object == NULL)
2339 verbosestream<<"TOSERVER_INTERACT: "
2340 "pointed object is NULL"<<std::endl;
2346 v3f pointed_pos_under = player_pos;
2347 v3f pointed_pos_above = player_pos;
2348 if(pointed.type == POINTEDTHING_NODE)
2350 pointed_pos_under = intToFloat(p_under, BS);
2351 pointed_pos_above = intToFloat(p_above, BS);
2353 else if(pointed.type == POINTEDTHING_OBJECT)
2355 pointed_pos_under = pointed_object->getBasePosition();
2356 pointed_pos_above = pointed_pos_under;
2360 Check that target is reasonably close
2361 (only when digging or placing things)
2363 if(action == 0 || action == 2 || action == 3)
2365 float d = player_pos.getDistanceFrom(pointed_pos_under);
2366 float max_d = BS * 14; // Just some large enough value
2368 actionstream<<"Player "<<player->getName()
2369 <<" tried to access "<<pointed.dump()
2371 <<"d="<<d<<", max_d="<<max_d
2372 <<". ignoring."<<std::endl;
2373 // Re-send block to revert change on client-side
2374 RemoteClient *client = getClient(peer_id);
2375 v3s16 blockpos = getNodeBlockPos(floatToInt(pointed_pos_under, BS));
2376 client->SetBlockNotSent(blockpos);
2378 m_script->on_cheat(playersao, "interacted_too_far");
2385 Make sure the player is allowed to do it
2387 if(!checkPriv(player->getName(), "interact"))
2389 actionstream<<player->getName()<<" attempted to interact with "
2390 <<pointed.dump()<<" without 'interact' privilege"
2392 // Re-send block to revert change on client-side
2393 RemoteClient *client = getClient(peer_id);
2394 // Digging completed -> under
2396 v3s16 blockpos = getNodeBlockPos(floatToInt(pointed_pos_under, BS));
2397 client->SetBlockNotSent(blockpos);
2399 // Placement -> above
2401 v3s16 blockpos = getNodeBlockPos(floatToInt(pointed_pos_above, BS));
2402 client->SetBlockNotSent(blockpos);
2408 If something goes wrong, this player is to blame
2410 RollbackScopeActor rollback_scope(m_rollback,
2411 std::string("player:")+player->getName());
2414 0: start digging or punch object
2418 if(pointed.type == POINTEDTHING_NODE)
2421 NOTE: This can be used in the future to check if
2422 somebody is cheating, by checking the timing.
2424 MapNode n(CONTENT_IGNORE);
2426 n = m_env->getMap().getNodeNoEx(p_under, &pos_ok);
2428 n = m_env->getMap().getNodeNoEx(p_under, &pos_ok);
2431 infostream<<"Server: Not punching: Node not found."
2432 <<" Adding block to emerge queue."
2434 m_emerge->enqueueBlockEmerge(peer_id, getNodeBlockPos(p_above), false);
2437 if(n.getContent() != CONTENT_IGNORE)
2438 m_script->node_on_punch(p_under, n, playersao, pointed);
2440 playersao->noCheatDigStart(p_under);
2442 else if(pointed.type == POINTEDTHING_OBJECT)
2444 // Skip if object has been removed
2445 if(pointed_object->m_removed)
2448 actionstream<<player->getName()<<" punches object "
2449 <<pointed.object_id<<": "
2450 <<pointed_object->getDescription()<<std::endl;
2452 ItemStack punchitem = playersao->getWieldedItem();
2453 ToolCapabilities toolcap =
2454 punchitem.getToolCapabilities(m_itemdef);
2455 v3f dir = (pointed_object->getBasePosition() -
2456 (player->getPosition() + player->getEyeOffset())
2458 float time_from_last_punch =
2459 playersao->resetTimeFromLastPunch();
2460 pointed_object->punch(dir, &toolcap, playersao,
2461 time_from_last_punch);
2469 else if(action == 1)
2474 2: Digging completed
2476 else if(action == 2)
2478 // Only digging of nodes
2479 if(pointed.type == POINTEDTHING_NODE)
2482 MapNode n = m_env->getMap().getNodeNoEx(p_under, &pos_ok);
2484 infostream << "Server: Not finishing digging: Node not found."
2485 << " Adding block to emerge queue."
2487 m_emerge->enqueueBlockEmerge(peer_id, getNodeBlockPos(p_above), false);
2490 /* Cheat prevention */
2491 bool is_valid_dig = true;
2492 if(!isSingleplayer() && !g_settings->getBool("disable_anticheat"))
2494 v3s16 nocheat_p = playersao->getNoCheatDigPos();
2495 float nocheat_t = playersao->getNoCheatDigTime();
2496 playersao->noCheatDigEnd();
2497 // If player didn't start digging this, ignore dig
2498 if(nocheat_p != p_under){
2499 infostream<<"Server: NoCheat: "<<player->getName()
2500 <<" started digging "
2501 <<PP(nocheat_p)<<" and completed digging "
2502 <<PP(p_under)<<"; not digging."<<std::endl;
2503 is_valid_dig = false;
2505 m_script->on_cheat(playersao, "finished_unknown_dig");
2507 // Get player's wielded item
2508 ItemStack playeritem;
2509 InventoryList *mlist = playersao->getInventory()->getList("main");
2511 playeritem = mlist->getItem(playersao->getWieldIndex());
2512 ToolCapabilities playeritem_toolcap =
2513 playeritem.getToolCapabilities(m_itemdef);
2514 // Get diggability and expected digging time
2515 DigParams params = getDigParams(m_nodedef->get(n).groups,
2516 &playeritem_toolcap);
2517 // If can't dig, try hand
2518 if(!params.diggable){
2519 const ItemDefinition &hand = m_itemdef->get("");
2520 const ToolCapabilities *tp = hand.tool_capabilities;
2522 params = getDigParams(m_nodedef->get(n).groups, tp);
2524 // If can't dig, ignore dig
2525 if(!params.diggable){
2526 infostream<<"Server: NoCheat: "<<player->getName()
2527 <<" completed digging "<<PP(p_under)
2528 <<", which is not diggable with tool. not digging."
2530 is_valid_dig = false;
2532 m_script->on_cheat(playersao, "dug_unbreakable");
2534 // Check digging time
2535 // If already invalidated, we don't have to
2537 // Well not our problem then
2539 // Clean and long dig
2540 else if(params.time > 2.0 && nocheat_t * 1.2 > params.time){
2541 // All is good, but grab time from pool; don't care if
2542 // it's actually available
2543 playersao->getDigPool().grab(params.time);
2545 // Short or laggy dig
2546 // Try getting the time from pool
2547 else if(playersao->getDigPool().grab(params.time)){
2552 infostream<<"Server: NoCheat: "<<player->getName()
2553 <<" completed digging "<<PP(p_under)
2554 <<"too fast; not digging."<<std::endl;
2555 is_valid_dig = false;
2557 m_script->on_cheat(playersao, "dug_too_fast");
2561 /* Actually dig node */
2563 if(is_valid_dig && n.getContent() != CONTENT_IGNORE)
2564 m_script->node_on_dig(p_under, n, playersao);
2566 v3s16 blockpos = getNodeBlockPos(floatToInt(pointed_pos_under, BS));
2567 RemoteClient *client = getClient(peer_id);
2568 // Send unusual result (that is, node not being removed)
2569 if(m_env->getMap().getNodeNoEx(p_under).getContent() != CONTENT_AIR)
2571 // Re-send block to revert change on client-side
2572 client->SetBlockNotSent(blockpos);
2575 client->ResendBlockIfOnWire(blockpos);
2581 3: place block or right-click object
2583 else if(action == 3)
2585 ItemStack item = playersao->getWieldedItem();
2587 // Reset build time counter
2588 if(pointed.type == POINTEDTHING_NODE &&
2589 item.getDefinition(m_itemdef).type == ITEM_NODE)
2590 getClient(peer_id)->m_time_from_building = 0.0;
2592 if(pointed.type == POINTEDTHING_OBJECT)
2594 // Right click object
2596 // Skip if object has been removed
2597 if(pointed_object->m_removed)
2600 actionstream<<player->getName()<<" right-clicks object "
2601 <<pointed.object_id<<": "
2602 <<pointed_object->getDescription()<<std::endl;
2605 pointed_object->rightClick(playersao);
2607 else if(m_script->item_OnPlace(
2608 item, playersao, pointed))
2610 // Placement was handled in lua
2612 // Apply returned ItemStack
2613 playersao->setWieldedItem(item);
2616 // If item has node placement prediction, always send the
2617 // blocks to make sure the client knows what exactly happened
2618 RemoteClient *client = getClient(peer_id);
2619 v3s16 blockpos = getNodeBlockPos(floatToInt(pointed_pos_above, BS));
2620 v3s16 blockpos2 = getNodeBlockPos(floatToInt(pointed_pos_under, BS));
2621 if(item.getDefinition(m_itemdef).node_placement_prediction != "") {
2622 client->SetBlockNotSent(blockpos);
2623 if(blockpos2 != blockpos) {
2624 client->SetBlockNotSent(blockpos2);
2628 client->ResendBlockIfOnWire(blockpos);
2629 if(blockpos2 != blockpos) {
2630 client->ResendBlockIfOnWire(blockpos2);
2638 else if(action == 4)
2640 ItemStack item = playersao->getWieldedItem();
2642 actionstream<<player->getName()<<" uses "<<item.name
2643 <<", pointing at "<<pointed.dump()<<std::endl;
2645 if(m_script->item_OnUse(
2646 item, playersao, pointed))
2648 // Apply returned ItemStack
2649 playersao->setWieldedItem(item);
2656 Catch invalid actions
2660 infostream<<"WARNING: Server: Invalid action "
2661 <<action<<std::endl;
2664 else if(command == TOSERVER_REMOVED_SOUNDS)
2666 std::string datastring((char*)&data[2], datasize-2);
2667 std::istringstream is(datastring, std::ios_base::binary);
2669 int num = readU16(is);
2670 for(int k=0; k<num; k++){
2671 s32 id = readS32(is);
2672 std::map<s32, ServerPlayingSound>::iterator i =
2673 m_playing_sounds.find(id);
2674 if(i == m_playing_sounds.end())
2676 ServerPlayingSound &psound = i->second;
2677 psound.clients.erase(peer_id);
2678 if(psound.clients.size() == 0)
2679 m_playing_sounds.erase(i++);
2682 else if(command == TOSERVER_NODEMETA_FIELDS)
2684 std::string datastring((char*)&data[2], datasize-2);
2685 std::istringstream is(datastring, std::ios_base::binary);
2687 v3s16 p = readV3S16(is);
2688 std::string formname = deSerializeString(is);
2689 int num = readU16(is);
2690 std::map<std::string, std::string> fields;
2691 for(int k=0; k<num; k++){
2692 std::string fieldname = deSerializeString(is);
2693 std::string fieldvalue = deSerializeLongString(is);
2694 fields[fieldname] = fieldvalue;
2697 // If something goes wrong, this player is to blame
2698 RollbackScopeActor rollback_scope(m_rollback,
2699 std::string("player:")+player->getName());
2701 // Check the target node for rollback data; leave others unnoticed
2702 RollbackNode rn_old(&m_env->getMap(), p, this);
2704 m_script->node_on_receive_fields(p, formname, fields,playersao);
2706 // Report rollback data
2707 RollbackNode rn_new(&m_env->getMap(), p, this);
2708 if(rollback() && rn_new != rn_old){
2709 RollbackAction action;
2710 action.setSetNode(p, rn_old, rn_new);
2711 rollback()->reportAction(action);
2714 else if(command == TOSERVER_INVENTORY_FIELDS)
2716 std::string datastring((char*)&data[2], datasize-2);
2717 std::istringstream is(datastring, std::ios_base::binary);
2719 std::string formname = deSerializeString(is);
2720 int num = readU16(is);
2721 std::map<std::string, std::string> fields;
2722 for(int k=0; k<num; k++){
2723 std::string fieldname = deSerializeString(is);
2724 std::string fieldvalue = deSerializeLongString(is);
2725 fields[fieldname] = fieldvalue;
2728 m_script->on_playerReceiveFields(playersao, formname, fields);
2732 infostream<<"Server::ProcessData(): Ignoring "
2733 "unknown command "<<command<<std::endl;
2737 catch(SendFailedException &e)
2739 errorstream<<"Server::ProcessData(): SendFailedException: "
2745 void Server::setTimeOfDay(u32 time)
2747 m_env->setTimeOfDay(time);
2748 m_time_of_day_send_timer = 0;
2751 void Server::onMapEditEvent(MapEditEvent *event)
2753 //infostream<<"Server::onMapEditEvent()"<<std::endl;
2754 if(m_ignore_map_edit_events)
2756 if(m_ignore_map_edit_events_area.contains(event->getArea()))
2758 MapEditEvent *e = event->clone();
2759 m_unsent_map_edit_queue.push_back(e);
2762 Inventory* Server::getInventory(const InventoryLocation &loc)
2765 case InventoryLocation::UNDEFINED:
2768 case InventoryLocation::CURRENT_PLAYER:
2771 case InventoryLocation::PLAYER:
2773 Player *player = m_env->getPlayer(loc.name.c_str());
2776 PlayerSAO *playersao = player->getPlayerSAO();
2779 return playersao->getInventory();
2782 case InventoryLocation::NODEMETA:
2784 NodeMetadata *meta = m_env->getMap().getNodeMetadata(loc.p);
2787 return meta->getInventory();
2790 case InventoryLocation::DETACHED:
2792 if(m_detached_inventories.count(loc.name) == 0)
2794 return m_detached_inventories[loc.name];
2802 void Server::setInventoryModified(const InventoryLocation &loc)
2805 case InventoryLocation::UNDEFINED:
2808 case InventoryLocation::PLAYER:
2810 Player *player = m_env->getPlayer(loc.name.c_str());
2813 PlayerSAO *playersao = player->getPlayerSAO();
2816 playersao->m_inventory_not_sent = true;
2817 playersao->m_wielded_item_not_sent = true;
2820 case InventoryLocation::NODEMETA:
2822 v3s16 blockpos = getNodeBlockPos(loc.p);
2824 MapBlock *block = m_env->getMap().getBlockNoCreateNoEx(blockpos);
2826 block->raiseModified(MOD_STATE_WRITE_NEEDED);
2828 setBlockNotSent(blockpos);
2831 case InventoryLocation::DETACHED:
2833 sendDetachedInventory(loc.name,PEER_ID_INEXISTENT);
2841 void Server::SetBlocksNotSent(std::map<v3s16, MapBlock *>& block)
2843 std::list<u16> clients = m_clients.getClientIDs();
2845 // Set the modified blocks unsent for all the clients
2846 for (std::list<u16>::iterator
2847 i = clients.begin();
2848 i != clients.end(); ++i) {
2849 RemoteClient *client = m_clients.lockedGetClientNoEx(*i);
2851 client->SetBlocksNotSent(block);
2856 void Server::peerAdded(con::Peer *peer)
2858 DSTACK(__FUNCTION_NAME);
2859 verbosestream<<"Server::peerAdded(): peer->id="
2860 <<peer->id<<std::endl;
2863 c.type = con::PEER_ADDED;
2864 c.peer_id = peer->id;
2866 m_peer_change_queue.push_back(c);
2869 void Server::deletingPeer(con::Peer *peer, bool timeout)
2871 DSTACK(__FUNCTION_NAME);
2872 verbosestream<<"Server::deletingPeer(): peer->id="
2873 <<peer->id<<", timeout="<<timeout<<std::endl;
2875 m_clients.event(peer->id, CSE_Disconnect);
2877 c.type = con::PEER_REMOVED;
2878 c.peer_id = peer->id;
2879 c.timeout = timeout;
2880 m_peer_change_queue.push_back(c);
2883 bool Server::getClientConInfo(u16 peer_id, con::rtt_stat_type type, float* retval)
2885 *retval = m_con.getPeerStat(peer_id,type);
2886 if (*retval == -1) return false;
2890 bool Server::getClientInfo(
2899 std::string* vers_string
2902 *state = m_clients.getClientState(peer_id);
2904 RemoteClient* client = m_clients.lockedGetClientNoEx(peer_id, CS_Invalid);
2906 if (client == NULL) {
2911 *uptime = client->uptime();
2912 *ser_vers = client->serialization_version;
2913 *prot_vers = client->net_proto_version;
2915 *major = client->getMajor();
2916 *minor = client->getMinor();
2917 *patch = client->getPatch();
2918 *vers_string = client->getPatch();
2925 void Server::handlePeerChanges()
2927 while(m_peer_change_queue.size() > 0)
2929 con::PeerChange c = m_peer_change_queue.pop_front();
2931 verbosestream<<"Server: Handling peer change: "
2932 <<"id="<<c.peer_id<<", timeout="<<c.timeout
2937 case con::PEER_ADDED:
2938 m_clients.CreateClient(c.peer_id);
2941 case con::PEER_REMOVED:
2942 DeleteClient(c.peer_id, c.timeout?CDR_TIMEOUT:CDR_LEAVE);
2946 assert("Invalid peer change event received!" == 0);
2952 void Server::SendMovement(u16 peer_id)
2954 DSTACK(__FUNCTION_NAME);
2955 std::ostringstream os(std::ios_base::binary);
2957 writeU16(os, TOCLIENT_MOVEMENT);
2958 writeF1000(os, g_settings->getFloat("movement_acceleration_default"));
2959 writeF1000(os, g_settings->getFloat("movement_acceleration_air"));
2960 writeF1000(os, g_settings->getFloat("movement_acceleration_fast"));
2961 writeF1000(os, g_settings->getFloat("movement_speed_walk"));
2962 writeF1000(os, g_settings->getFloat("movement_speed_crouch"));
2963 writeF1000(os, g_settings->getFloat("movement_speed_fast"));
2964 writeF1000(os, g_settings->getFloat("movement_speed_climb"));
2965 writeF1000(os, g_settings->getFloat("movement_speed_jump"));
2966 writeF1000(os, g_settings->getFloat("movement_liquid_fluidity"));
2967 writeF1000(os, g_settings->getFloat("movement_liquid_fluidity_smooth"));
2968 writeF1000(os, g_settings->getFloat("movement_liquid_sink"));
2969 writeF1000(os, g_settings->getFloat("movement_gravity"));
2972 std::string s = os.str();
2973 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
2975 m_clients.send(peer_id, 0, data, true);
2978 void Server::SendHP(u16 peer_id, u8 hp)
2980 DSTACK(__FUNCTION_NAME);
2981 std::ostringstream os(std::ios_base::binary);
2983 writeU16(os, TOCLIENT_HP);
2987 std::string s = os.str();
2988 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
2990 m_clients.send(peer_id, 0, data, true);
2993 void Server::SendBreath(u16 peer_id, u16 breath)
2995 DSTACK(__FUNCTION_NAME);
2996 std::ostringstream os(std::ios_base::binary);
2998 writeU16(os, TOCLIENT_BREATH);
2999 writeU16(os, breath);
3002 std::string s = os.str();
3003 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3005 m_clients.send(peer_id, 0, data, true);
3008 void Server::SendAccessDenied(u16 peer_id,const std::wstring &reason)
3010 DSTACK(__FUNCTION_NAME);
3011 std::ostringstream os(std::ios_base::binary);
3013 writeU16(os, TOCLIENT_ACCESS_DENIED);
3014 os<<serializeWideString(reason);
3017 std::string s = os.str();
3018 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3020 m_clients.send(peer_id, 0, data, true);
3023 void Server::SendDeathscreen(u16 peer_id,bool set_camera_point_target,
3024 v3f camera_point_target)
3026 DSTACK(__FUNCTION_NAME);
3027 std::ostringstream os(std::ios_base::binary);
3029 writeU16(os, TOCLIENT_DEATHSCREEN);
3030 writeU8(os, set_camera_point_target);
3031 writeV3F1000(os, camera_point_target);
3034 std::string s = os.str();
3035 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3037 m_clients.send(peer_id, 0, data, true);
3040 void Server::SendItemDef(u16 peer_id,
3041 IItemDefManager *itemdef, u16 protocol_version)
3043 DSTACK(__FUNCTION_NAME);
3044 std::ostringstream os(std::ios_base::binary);
3048 u32 length of the next item
3049 zlib-compressed serialized ItemDefManager
3051 writeU16(os, TOCLIENT_ITEMDEF);
3052 std::ostringstream tmp_os(std::ios::binary);
3053 itemdef->serialize(tmp_os, protocol_version);
3054 std::ostringstream tmp_os2(std::ios::binary);
3055 compressZlib(tmp_os.str(), tmp_os2);
3056 os<<serializeLongString(tmp_os2.str());
3059 std::string s = os.str();
3060 verbosestream<<"Server: Sending item definitions to id("<<peer_id
3061 <<"): size="<<s.size()<<std::endl;
3062 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3064 m_clients.send(peer_id, 0, data, true);
3067 void Server::SendNodeDef(u16 peer_id,
3068 INodeDefManager *nodedef, u16 protocol_version)
3070 DSTACK(__FUNCTION_NAME);
3071 std::ostringstream os(std::ios_base::binary);
3075 u32 length of the next item
3076 zlib-compressed serialized NodeDefManager
3078 writeU16(os, TOCLIENT_NODEDEF);
3079 std::ostringstream tmp_os(std::ios::binary);
3080 nodedef->serialize(tmp_os, protocol_version);
3081 std::ostringstream tmp_os2(std::ios::binary);
3082 compressZlib(tmp_os.str(), tmp_os2);
3083 os<<serializeLongString(tmp_os2.str());
3086 std::string s = os.str();
3087 verbosestream<<"Server: Sending node definitions to id("<<peer_id
3088 <<"): size="<<s.size()<<std::endl;
3089 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3091 m_clients.send(peer_id, 0, data, true);
3095 Non-static send methods
3098 void Server::SendInventory(u16 peer_id)
3100 DSTACK(__FUNCTION_NAME);
3102 PlayerSAO *playersao = getPlayerSAO(peer_id);
3105 playersao->m_inventory_not_sent = false;
3111 std::ostringstream os;
3112 playersao->getInventory()->serialize(os);
3114 std::string s = os.str();
3116 SharedBuffer<u8> data(s.size()+2);
3117 writeU16(&data[0], TOCLIENT_INVENTORY);
3118 memcpy(&data[2], s.c_str(), s.size());
3121 m_clients.send(peer_id, 0, data, true);
3124 void Server::SendChatMessage(u16 peer_id, const std::wstring &message)
3126 DSTACK(__FUNCTION_NAME);
3128 std::ostringstream os(std::ios_base::binary);
3132 writeU16(buf, TOCLIENT_CHAT_MESSAGE);
3133 os.write((char*)buf, 2);
3136 writeU16(buf, message.size());
3137 os.write((char*)buf, 2);
3140 for(u32 i=0; i<message.size(); i++)
3144 os.write((char*)buf, 2);
3148 std::string s = os.str();
3149 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3151 if (peer_id != PEER_ID_INEXISTENT)
3154 m_clients.send(peer_id, 0, data, true);
3158 m_clients.sendToAll(0,data,true);
3162 void Server::SendShowFormspecMessage(u16 peer_id, const std::string &formspec,
3163 const std::string &formname)
3165 DSTACK(__FUNCTION_NAME);
3167 std::ostringstream os(std::ios_base::binary);
3172 writeU16(buf, TOCLIENT_SHOW_FORMSPEC);
3173 os.write((char*)buf, 2);
3174 os<<serializeLongString(FORMSPEC_VERSION_STRING + formspec);
3175 os<<serializeString(formname);
3178 std::string s = os.str();
3179 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3181 m_clients.send(peer_id, 0, data, true);
3184 // Spawns a particle on peer with peer_id
3185 void Server::SendSpawnParticle(u16 peer_id, v3f pos, v3f velocity, v3f acceleration,
3186 float expirationtime, float size, bool collisiondetection,
3187 bool vertical, std::string texture)
3189 DSTACK(__FUNCTION_NAME);
3191 std::ostringstream os(std::ios_base::binary);
3192 writeU16(os, TOCLIENT_SPAWN_PARTICLE);
3193 writeV3F1000(os, pos);
3194 writeV3F1000(os, velocity);
3195 writeV3F1000(os, acceleration);
3196 writeF1000(os, expirationtime);
3197 writeF1000(os, size);
3198 writeU8(os, collisiondetection);
3199 os<<serializeLongString(texture);
3200 writeU8(os, vertical);
3203 std::string s = os.str();
3204 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3206 if (peer_id != PEER_ID_INEXISTENT)
3209 m_clients.send(peer_id, 0, data, true);
3213 m_clients.sendToAll(0,data,true);
3217 // Adds a ParticleSpawner on peer with peer_id
3218 void Server::SendAddParticleSpawner(u16 peer_id, u16 amount, float spawntime, v3f minpos, v3f maxpos,
3219 v3f minvel, v3f maxvel, v3f minacc, v3f maxacc, float minexptime, float maxexptime,
3220 float minsize, float maxsize, bool collisiondetection, bool vertical, std::string texture, u32 id)
3222 DSTACK(__FUNCTION_NAME);
3224 std::ostringstream os(std::ios_base::binary);
3225 writeU16(os, TOCLIENT_ADD_PARTICLESPAWNER);
3227 writeU16(os, amount);
3228 writeF1000(os, spawntime);
3229 writeV3F1000(os, minpos);
3230 writeV3F1000(os, maxpos);
3231 writeV3F1000(os, minvel);
3232 writeV3F1000(os, maxvel);
3233 writeV3F1000(os, minacc);
3234 writeV3F1000(os, maxacc);
3235 writeF1000(os, minexptime);
3236 writeF1000(os, maxexptime);
3237 writeF1000(os, minsize);
3238 writeF1000(os, maxsize);
3239 writeU8(os, collisiondetection);
3240 os<<serializeLongString(texture);
3242 writeU8(os, vertical);
3245 std::string s = os.str();
3246 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3248 if (peer_id != PEER_ID_INEXISTENT)
3251 m_clients.send(peer_id, 0, data, true);
3254 m_clients.sendToAll(0,data,true);
3258 void Server::SendDeleteParticleSpawner(u16 peer_id, u32 id)
3260 DSTACK(__FUNCTION_NAME);
3262 std::ostringstream os(std::ios_base::binary);
3263 writeU16(os, TOCLIENT_DELETE_PARTICLESPAWNER);
3268 std::string s = os.str();
3269 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3271 if (peer_id != PEER_ID_INEXISTENT) {
3273 m_clients.send(peer_id, 0, data, true);
3276 m_clients.sendToAll(0,data,true);
3281 void Server::SendHUDAdd(u16 peer_id, u32 id, HudElement *form)
3283 std::ostringstream os(std::ios_base::binary);
3286 writeU16(os, TOCLIENT_HUDADD);
3288 writeU8(os, (u8)form->type);
3289 writeV2F1000(os, form->pos);
3290 os << serializeString(form->name);
3291 writeV2F1000(os, form->scale);
3292 os << serializeString(form->text);
3293 writeU32(os, form->number);
3294 writeU32(os, form->item);
3295 writeU32(os, form->dir);
3296 writeV2F1000(os, form->align);
3297 writeV2F1000(os, form->offset);
3298 writeV3F1000(os, form->world_pos);
3299 writeV2S32(os,form->size);
3302 std::string s = os.str();
3303 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3305 m_clients.send(peer_id, 1, data, true);
3308 void Server::SendHUDRemove(u16 peer_id, u32 id)
3310 std::ostringstream os(std::ios_base::binary);
3313 writeU16(os, TOCLIENT_HUDRM);
3317 std::string s = os.str();
3318 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3321 m_clients.send(peer_id, 1, data, true);
3324 void Server::SendHUDChange(u16 peer_id, u32 id, HudElementStat stat, void *value)
3326 std::ostringstream os(std::ios_base::binary);
3329 writeU16(os, TOCLIENT_HUDCHANGE);
3331 writeU8(os, (u8)stat);
3334 case HUD_STAT_SCALE:
3335 case HUD_STAT_ALIGN:
3336 case HUD_STAT_OFFSET:
3337 writeV2F1000(os, *(v2f *)value);
3341 os << serializeString(*(std::string *)value);
3343 case HUD_STAT_WORLD_POS:
3344 writeV3F1000(os, *(v3f *)value);
3347 writeV2S32(os,*(v2s32 *)value);
3349 case HUD_STAT_NUMBER:
3353 writeU32(os, *(u32 *)value);
3358 std::string s = os.str();
3359 SharedBuffer<u8> data((u8 *)s.c_str(), s.size());
3361 m_clients.send(peer_id, 0, data, true);
3364 void Server::SendHUDSetFlags(u16 peer_id, u32 flags, u32 mask)
3366 std::ostringstream os(std::ios_base::binary);
3369 writeU16(os, TOCLIENT_HUD_SET_FLAGS);
3371 //////////////////////////// compatibility code to be removed //////////////
3372 flags &= ~(HUD_FLAG_HEALTHBAR_VISIBLE | HUD_FLAG_BREATHBAR_VISIBLE);
3373 ////////////////////////////////////////////////////////////////////////////
3374 writeU32(os, flags);
3378 std::string s = os.str();
3379 SharedBuffer<u8> data((u8 *)s.c_str(), s.size());
3381 m_clients.send(peer_id, 0, data, true);
3384 void Server::SendHUDSetParam(u16 peer_id, u16 param, const std::string &value)
3386 std::ostringstream os(std::ios_base::binary);
3389 writeU16(os, TOCLIENT_HUD_SET_PARAM);
3390 writeU16(os, param);
3391 os<<serializeString(value);
3394 std::string s = os.str();
3395 SharedBuffer<u8> data((u8 *)s.c_str(), s.size());
3397 m_clients.send(peer_id, 0, data, true);
3400 void Server::SendSetSky(u16 peer_id, const video::SColor &bgcolor,
3401 const std::string &type, const std::vector<std::string> ¶ms)
3403 std::ostringstream os(std::ios_base::binary);
3406 writeU16(os, TOCLIENT_SET_SKY);
3407 writeARGB8(os, bgcolor);
3408 os<<serializeString(type);
3409 writeU16(os, params.size());
3410 for(size_t i=0; i<params.size(); i++)
3411 os<<serializeString(params[i]);
3414 std::string s = os.str();
3415 SharedBuffer<u8> data((u8 *)s.c_str(), s.size());
3417 m_clients.send(peer_id, 0, data, true);
3420 void Server::SendOverrideDayNightRatio(u16 peer_id, bool do_override,
3423 std::ostringstream os(std::ios_base::binary);
3426 writeU16(os, TOCLIENT_OVERRIDE_DAY_NIGHT_RATIO);
3427 writeU8(os, do_override);
3428 writeU16(os, ratio*65535);
3431 std::string s = os.str();
3432 SharedBuffer<u8> data((u8 *)s.c_str(), s.size());
3434 m_clients.send(peer_id, 0, data, true);
3437 void Server::SendTimeOfDay(u16 peer_id, u16 time, f32 time_speed)
3439 DSTACK(__FUNCTION_NAME);
3442 SharedBuffer<u8> data(2+2+4);
3443 writeU16(&data[0], TOCLIENT_TIME_OF_DAY);
3444 writeU16(&data[2], time);
3445 writeF1000(&data[4], time_speed);
3447 if (peer_id == PEER_ID_INEXISTENT) {
3448 m_clients.sendToAll(0,data,true);
3452 m_clients.send(peer_id, 0, data, true);
3456 void Server::SendPlayerHP(u16 peer_id)
3458 DSTACK(__FUNCTION_NAME);
3459 PlayerSAO *playersao = getPlayerSAO(peer_id);
3461 playersao->m_hp_not_sent = false;
3462 SendHP(peer_id, playersao->getHP());
3463 m_script->player_event(playersao,"health_changed");
3465 // Send to other clients
3466 std::string str = gob_cmd_punched(playersao->readDamage(), playersao->getHP());
3467 ActiveObjectMessage aom(playersao->getId(), true, str);
3468 playersao->m_messages_out.push_back(aom);
3471 void Server::SendPlayerBreath(u16 peer_id)
3473 DSTACK(__FUNCTION_NAME);
3474 PlayerSAO *playersao = getPlayerSAO(peer_id);
3476 playersao->m_breath_not_sent = false;
3477 m_script->player_event(playersao,"breath_changed");
3478 SendBreath(peer_id, playersao->getBreath());
3481 void Server::SendMovePlayer(u16 peer_id)
3483 DSTACK(__FUNCTION_NAME);
3484 Player *player = m_env->getPlayer(peer_id);
3487 std::ostringstream os(std::ios_base::binary);
3488 writeU16(os, TOCLIENT_MOVE_PLAYER);
3489 writeV3F1000(os, player->getPosition());
3490 writeF1000(os, player->getPitch());
3491 writeF1000(os, player->getYaw());
3494 v3f pos = player->getPosition();
3495 f32 pitch = player->getPitch();
3496 f32 yaw = player->getYaw();
3497 verbosestream<<"Server: Sending TOCLIENT_MOVE_PLAYER"
3498 <<" pos=("<<pos.X<<","<<pos.Y<<","<<pos.Z<<")"
3505 std::string s = os.str();
3506 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3508 m_clients.send(peer_id, 0, data, true);
3511 void Server::SendLocalPlayerAnimations(u16 peer_id, v2s32 animation_frames[4], f32 animation_speed)
3513 std::ostringstream os(std::ios_base::binary);
3515 writeU16(os, TOCLIENT_LOCAL_PLAYER_ANIMATIONS);
3516 writeV2S32(os, animation_frames[0]);
3517 writeV2S32(os, animation_frames[1]);
3518 writeV2S32(os, animation_frames[2]);
3519 writeV2S32(os, animation_frames[3]);
3520 writeF1000(os, animation_speed);
3523 std::string s = os.str();
3524 SharedBuffer<u8> data((u8 *)s.c_str(), s.size());
3526 m_clients.send(peer_id, 0, data, true);
3529 void Server::SendEyeOffset(u16 peer_id, v3f first, v3f third)
3531 std::ostringstream os(std::ios_base::binary);
3533 writeU16(os, TOCLIENT_EYE_OFFSET);
3534 writeV3F1000(os, first);
3535 writeV3F1000(os, third);
3538 std::string s = os.str();
3539 SharedBuffer<u8> data((u8 *)s.c_str(), s.size());
3541 m_clients.send(peer_id, 0, data, true);
3543 void Server::SendPlayerPrivileges(u16 peer_id)
3545 Player *player = m_env->getPlayer(peer_id);
3547 if(player->peer_id == PEER_ID_INEXISTENT)
3550 std::set<std::string> privs;
3551 m_script->getAuth(player->getName(), NULL, &privs);
3553 std::ostringstream os(std::ios_base::binary);
3554 writeU16(os, TOCLIENT_PRIVILEGES);
3555 writeU16(os, privs.size());
3556 for(std::set<std::string>::const_iterator i = privs.begin();
3557 i != privs.end(); i++){
3558 os<<serializeString(*i);
3562 std::string s = os.str();
3563 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3565 m_clients.send(peer_id, 0, data, true);
3568 void Server::SendPlayerInventoryFormspec(u16 peer_id)
3570 Player *player = m_env->getPlayer(peer_id);
3572 if(player->peer_id == PEER_ID_INEXISTENT)
3575 std::ostringstream os(std::ios_base::binary);
3576 writeU16(os, TOCLIENT_INVENTORY_FORMSPEC);
3577 os<<serializeLongString(FORMSPEC_VERSION_STRING + player->inventory_formspec);
3580 std::string s = os.str();
3581 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3583 m_clients.send(peer_id, 0, data, true);
3586 s32 Server::playSound(const SimpleSoundSpec &spec,
3587 const ServerSoundParams ¶ms)
3589 // Find out initial position of sound
3590 bool pos_exists = false;
3591 v3f pos = params.getPos(m_env, &pos_exists);
3592 // If position is not found while it should be, cancel sound
3593 if(pos_exists != (params.type != ServerSoundParams::SSP_LOCAL))
3596 // Filter destination clients
3597 std::list<u16> dst_clients;
3598 if(params.to_player != "")
3600 Player *player = m_env->getPlayer(params.to_player.c_str());
3602 infostream<<"Server::playSound: Player \""<<params.to_player
3603 <<"\" not found"<<std::endl;
3606 if(player->peer_id == PEER_ID_INEXISTENT){
3607 infostream<<"Server::playSound: Player \""<<params.to_player
3608 <<"\" not connected"<<std::endl;
3611 dst_clients.push_back(player->peer_id);
3615 std::list<u16> clients = m_clients.getClientIDs();
3617 for(std::list<u16>::iterator
3618 i = clients.begin(); i != clients.end(); ++i)
3620 Player *player = m_env->getPlayer(*i);
3624 if(player->getPosition().getDistanceFrom(pos) >
3625 params.max_hear_distance)
3628 dst_clients.push_back(*i);
3631 if(dst_clients.size() == 0)
3635 s32 id = m_next_sound_id++;
3636 // The sound will exist as a reference in m_playing_sounds
3637 m_playing_sounds[id] = ServerPlayingSound();
3638 ServerPlayingSound &psound = m_playing_sounds[id];
3639 psound.params = params;
3640 for(std::list<u16>::iterator i = dst_clients.begin();
3641 i != dst_clients.end(); i++)
3642 psound.clients.insert(*i);
3644 std::ostringstream os(std::ios_base::binary);
3645 writeU16(os, TOCLIENT_PLAY_SOUND);
3647 os<<serializeString(spec.name);
3648 writeF1000(os, spec.gain * params.gain);
3649 writeU8(os, params.type);
3650 writeV3F1000(os, pos);
3651 writeU16(os, params.object);
3652 writeU8(os, params.loop);
3654 std::string s = os.str();
3655 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3657 for(std::list<u16>::iterator i = dst_clients.begin();
3658 i != dst_clients.end(); i++){
3660 m_clients.send(*i, 0, data, true);
3664 void Server::stopSound(s32 handle)
3666 // Get sound reference
3667 std::map<s32, ServerPlayingSound>::iterator i =
3668 m_playing_sounds.find(handle);
3669 if(i == m_playing_sounds.end())
3671 ServerPlayingSound &psound = i->second;
3673 std::ostringstream os(std::ios_base::binary);
3674 writeU16(os, TOCLIENT_STOP_SOUND);
3675 writeS32(os, handle);
3677 std::string s = os.str();
3678 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3680 for(std::set<u16>::iterator i = psound.clients.begin();
3681 i != psound.clients.end(); i++){
3683 m_clients.send(*i, 0, data, true);
3685 // Remove sound reference
3686 m_playing_sounds.erase(i);
3689 void Server::sendRemoveNode(v3s16 p, u16 ignore_id,
3690 std::list<u16> *far_players, float far_d_nodes)
3692 float maxd = far_d_nodes*BS;
3693 v3f p_f = intToFloat(p, BS);
3697 SharedBuffer<u8> reply(replysize);
3698 writeU16(&reply[0], TOCLIENT_REMOVENODE);
3699 writeS16(&reply[2], p.X);
3700 writeS16(&reply[4], p.Y);
3701 writeS16(&reply[6], p.Z);
3703 std::list<u16> clients = m_clients.getClientIDs();
3704 for(std::list<u16>::iterator
3705 i = clients.begin();
3706 i != clients.end(); ++i)
3711 Player *player = m_env->getPlayer(*i);
3714 // If player is far away, only set modified blocks not sent
3715 v3f player_pos = player->getPosition();
3716 if(player_pos.getDistanceFrom(p_f) > maxd)
3718 far_players->push_back(*i);
3725 m_clients.send(*i, 0, reply, true);
3729 void Server::sendAddNode(v3s16 p, MapNode n, u16 ignore_id,
3730 std::list<u16> *far_players, float far_d_nodes,
3731 bool remove_metadata)
3733 float maxd = far_d_nodes*BS;
3734 v3f p_f = intToFloat(p, BS);
3736 std::list<u16> clients = m_clients.getClientIDs();
3737 for(std::list<u16>::iterator
3738 i = clients.begin();
3739 i != clients.end(); ++i)
3745 Player *player = m_env->getPlayer(*i);
3748 // If player is far away, only set modified blocks not sent
3749 v3f player_pos = player->getPosition();
3750 if(player_pos.getDistanceFrom(p_f) > maxd)
3752 far_players->push_back(*i);
3757 SharedBuffer<u8> reply(0);
3759 RemoteClient* client = m_clients.lockedGetClientNoEx(*i);
3763 u32 replysize = 9 + MapNode::serializedLength(client->serialization_version);
3764 reply = SharedBuffer<u8>(replysize);
3765 writeU16(&reply[0], TOCLIENT_ADDNODE);
3766 writeS16(&reply[2], p.X);
3767 writeS16(&reply[4], p.Y);
3768 writeS16(&reply[6], p.Z);
3769 n.serialize(&reply[8], client->serialization_version);
3770 u32 index = 8 + MapNode::serializedLength(client->serialization_version);
3771 writeU8(&reply[index], remove_metadata ? 0 : 1);
3773 if (!remove_metadata) {
3774 if (client->net_proto_version <= 21) {
3775 // Old clients always clear metadata; fix it
3776 // by sending the full block again.
3777 client->SetBlockNotSent(p);
3784 if (reply.getSize() > 0)
3785 m_clients.send(*i, 0, reply, true);
3789 void Server::setBlockNotSent(v3s16 p)
3791 std::list<u16> clients = m_clients.getClientIDs();
3793 for(std::list<u16>::iterator
3794 i = clients.begin();
3795 i != clients.end(); ++i)
3797 RemoteClient *client = m_clients.lockedGetClientNoEx(*i);
3798 client->SetBlockNotSent(p);
3803 void Server::SendBlockNoLock(u16 peer_id, MapBlock *block, u8 ver, u16 net_proto_version)
3805 DSTACK(__FUNCTION_NAME);
3807 v3s16 p = block->getPos();
3811 bool completely_air = true;
3812 for(s16 z0=0; z0<MAP_BLOCKSIZE; z0++)
3813 for(s16 x0=0; x0<MAP_BLOCKSIZE; x0++)
3814 for(s16 y0=0; y0<MAP_BLOCKSIZE; y0++)
3816 if(block->getNodeNoEx(v3s16(x0,y0,z0)).d != CONTENT_AIR)
3818 completely_air = false;
3819 x0 = y0 = z0 = MAP_BLOCKSIZE; // Break out
3824 infostream<<"Server: Sending block ("<<p.X<<","<<p.Y<<","<<p.Z<<"): ";
3826 infostream<<"[completely air] ";
3827 infostream<<std::endl;
3831 Create a packet with the block in the right format
3834 std::ostringstream os(std::ios_base::binary);
3835 block->serialize(os, ver, false);
3836 block->serializeNetworkSpecific(os, net_proto_version);
3837 std::string s = os.str();
3838 SharedBuffer<u8> blockdata((u8*)s.c_str(), s.size());
3840 u32 replysize = 8 + blockdata.getSize();
3841 SharedBuffer<u8> reply(replysize);
3842 writeU16(&reply[0], TOCLIENT_BLOCKDATA);
3843 writeS16(&reply[2], p.X);
3844 writeS16(&reply[4], p.Y);
3845 writeS16(&reply[6], p.Z);
3846 memcpy(&reply[8], *blockdata, blockdata.getSize());
3848 /*infostream<<"Server: Sending block ("<<p.X<<","<<p.Y<<","<<p.Z<<")"
3849 <<": \tpacket size: "<<replysize<<std::endl;*/
3854 m_clients.send(peer_id, 2, reply, true);
3857 void Server::SendBlocks(float dtime)
3859 DSTACK(__FUNCTION_NAME);
3861 JMutexAutoLock envlock(m_env_mutex);
3862 //TODO check if one big lock could be faster then multiple small ones
3864 ScopeProfiler sp(g_profiler, "Server: sel and send blocks to clients");
3866 std::vector<PrioritySortedBlockTransfer> queue;
3868 s32 total_sending = 0;
3871 ScopeProfiler sp(g_profiler, "Server: selecting blocks for sending");
3873 std::list<u16> clients = m_clients.getClientIDs();
3876 for(std::list<u16>::iterator
3877 i = clients.begin();
3878 i != clients.end(); ++i)
3880 RemoteClient *client = m_clients.lockedGetClientNoEx(*i, CS_Active);
3885 total_sending += client->SendingCount();
3886 client->GetNextBlocks(m_env,m_emerge, dtime, queue);
3892 // Lowest priority number comes first.
3893 // Lowest is most important.
3894 std::sort(queue.begin(), queue.end());
3897 for(u32 i=0; i<queue.size(); i++)
3899 //TODO: Calculate limit dynamically
3900 if(total_sending >= g_settings->getS32
3901 ("max_simultaneous_block_sends_server_total"))
3904 PrioritySortedBlockTransfer q = queue[i];
3906 MapBlock *block = NULL;
3909 block = m_env->getMap().getBlockNoCreate(q.pos);
3911 catch(InvalidPositionException &e)
3916 RemoteClient *client = m_clients.lockedGetClientNoEx(q.peer_id, CS_Active);
3921 SendBlockNoLock(q.peer_id, block, client->serialization_version, client->net_proto_version);
3923 client->SentBlock(q.pos);
3929 void Server::fillMediaCache()
3931 DSTACK(__FUNCTION_NAME);
3933 infostream<<"Server: Calculating media file checksums"<<std::endl;
3935 // Collect all media file paths
3936 std::list<std::string> paths;
3937 for(std::vector<ModSpec>::iterator i = m_mods.begin();
3938 i != m_mods.end(); i++){
3939 const ModSpec &mod = *i;
3940 paths.push_back(mod.path + DIR_DELIM + "textures");
3941 paths.push_back(mod.path + DIR_DELIM + "sounds");
3942 paths.push_back(mod.path + DIR_DELIM + "media");
3943 paths.push_back(mod.path + DIR_DELIM + "models");
3945 paths.push_back(porting::path_user + DIR_DELIM + "textures" + DIR_DELIM + "server");
3947 // Collect media file information from paths into cache
3948 for(std::list<std::string>::iterator i = paths.begin();
3949 i != paths.end(); i++)
3951 std::string mediapath = *i;
3952 std::vector<fs::DirListNode> dirlist = fs::GetDirListing(mediapath);
3953 for(u32 j=0; j<dirlist.size(); j++){
3954 if(dirlist[j].dir) // Ignode dirs
3956 std::string filename = dirlist[j].name;
3957 // If name contains illegal characters, ignore the file
3958 if(!string_allowed(filename, TEXTURENAME_ALLOWED_CHARS)){
3959 infostream<<"Server: ignoring illegal file name: \""
3960 <<filename<<"\""<<std::endl;
3963 // If name is not in a supported format, ignore it
3964 const char *supported_ext[] = {
3965 ".png", ".jpg", ".bmp", ".tga",
3966 ".pcx", ".ppm", ".psd", ".wal", ".rgb",
3968 ".x", ".b3d", ".md2", ".obj",
3971 if(removeStringEnd(filename, supported_ext) == ""){
3972 infostream<<"Server: ignoring unsupported file extension: \""
3973 <<filename<<"\""<<std::endl;
3976 // Ok, attempt to load the file and add to cache
3977 std::string filepath = mediapath + DIR_DELIM + filename;
3979 std::ifstream fis(filepath.c_str(), std::ios_base::binary);
3980 if(fis.good() == false){
3981 errorstream<<"Server::fillMediaCache(): Could not open \""
3982 <<filename<<"\" for reading"<<std::endl;
3985 std::ostringstream tmp_os(std::ios_base::binary);
3989 fis.read(buf, 1024);
3990 std::streamsize len = fis.gcount();
3991 tmp_os.write(buf, len);
4000 errorstream<<"Server::fillMediaCache(): Failed to read \""
4001 <<filename<<"\""<<std::endl;
4004 if(tmp_os.str().length() == 0){
4005 errorstream<<"Server::fillMediaCache(): Empty file \""
4006 <<filepath<<"\""<<std::endl;
4011 sha1.addBytes(tmp_os.str().c_str(), tmp_os.str().length());
4013 unsigned char *digest = sha1.getDigest();
4014 std::string sha1_base64 = base64_encode(digest, 20);
4015 std::string sha1_hex = hex_encode((char*)digest, 20);
4019 this->m_media[filename] = MediaInfo(filepath, sha1_base64);
4020 verbosestream<<"Server: "<<sha1_hex<<" is "<<filename<<std::endl;
4025 struct SendableMediaAnnouncement
4028 std::string sha1_digest;
4030 SendableMediaAnnouncement(const std::string &name_="",
4031 const std::string &sha1_digest_=""):
4033 sha1_digest(sha1_digest_)
4037 void Server::sendMediaAnnouncement(u16 peer_id)
4039 DSTACK(__FUNCTION_NAME);
4041 verbosestream<<"Server: Announcing files to id("<<peer_id<<")"
4044 std::list<SendableMediaAnnouncement> file_announcements;
4046 for(std::map<std::string, MediaInfo>::iterator i = m_media.begin();
4047 i != m_media.end(); i++){
4049 file_announcements.push_back(
4050 SendableMediaAnnouncement(i->first, i->second.sha1_digest));
4054 std::ostringstream os(std::ios_base::binary);
4062 u16 length of sha1_digest
4067 writeU16(os, TOCLIENT_ANNOUNCE_MEDIA);
4068 writeU16(os, file_announcements.size());
4070 for(std::list<SendableMediaAnnouncement>::iterator
4071 j = file_announcements.begin();
4072 j != file_announcements.end(); ++j){
4073 os<<serializeString(j->name);
4074 os<<serializeString(j->sha1_digest);
4076 os<<serializeString(g_settings->get("remote_media"));
4079 std::string s = os.str();
4080 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
4083 m_clients.send(peer_id, 0, data, true);
4086 struct SendableMedia
4092 SendableMedia(const std::string &name_="", const std::string &path_="",
4093 const std::string &data_=""):
4100 void Server::sendRequestedMedia(u16 peer_id,
4101 const std::list<std::string> &tosend)
4103 DSTACK(__FUNCTION_NAME);
4105 verbosestream<<"Server::sendRequestedMedia(): "
4106 <<"Sending files to client"<<std::endl;
4110 // Put 5kB in one bunch (this is not accurate)
4111 u32 bytes_per_bunch = 5000;
4113 std::vector< std::list<SendableMedia> > file_bunches;
4114 file_bunches.push_back(std::list<SendableMedia>());
4116 u32 file_size_bunch_total = 0;
4118 for(std::list<std::string>::const_iterator i = tosend.begin();
4119 i != tosend.end(); ++i)
4121 const std::string &name = *i;
4123 if(m_media.find(name) == m_media.end()){
4124 errorstream<<"Server::sendRequestedMedia(): Client asked for "
4125 <<"unknown file \""<<(name)<<"\""<<std::endl;
4129 //TODO get path + name
4130 std::string tpath = m_media[name].path;
4133 std::ifstream fis(tpath.c_str(), std::ios_base::binary);
4134 if(fis.good() == false){
4135 errorstream<<"Server::sendRequestedMedia(): Could not open \""
4136 <<tpath<<"\" for reading"<<std::endl;
4139 std::ostringstream tmp_os(std::ios_base::binary);
4143 fis.read(buf, 1024);
4144 std::streamsize len = fis.gcount();
4145 tmp_os.write(buf, len);
4146 file_size_bunch_total += len;
4155 errorstream<<"Server::sendRequestedMedia(): Failed to read \""
4156 <<name<<"\""<<std::endl;
4159 /*infostream<<"Server::sendRequestedMedia(): Loaded \""
4160 <<tname<<"\""<<std::endl;*/
4162 file_bunches[file_bunches.size()-1].push_back(
4163 SendableMedia(name, tpath, tmp_os.str()));
4165 // Start next bunch if got enough data
4166 if(file_size_bunch_total >= bytes_per_bunch){
4167 file_bunches.push_back(std::list<SendableMedia>());
4168 file_size_bunch_total = 0;
4173 /* Create and send packets */
4175 u32 num_bunches = file_bunches.size();
4176 for(u32 i=0; i<num_bunches; i++)
4178 std::ostringstream os(std::ios_base::binary);
4182 u16 total number of texture bunches
4183 u16 index of this bunch
4184 u32 number of files in this bunch
4193 writeU16(os, TOCLIENT_MEDIA);
4194 writeU16(os, num_bunches);
4196 writeU32(os, file_bunches[i].size());
4198 for(std::list<SendableMedia>::iterator
4199 j = file_bunches[i].begin();
4200 j != file_bunches[i].end(); ++j){
4201 os<<serializeString(j->name);
4202 os<<serializeLongString(j->data);
4206 std::string s = os.str();
4207 verbosestream<<"Server::sendRequestedMedia(): bunch "
4208 <<i<<"/"<<num_bunches
4209 <<" files="<<file_bunches[i].size()
4210 <<" size=" <<s.size()<<std::endl;
4211 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
4213 m_clients.send(peer_id, 2, data, true);
4217 void Server::sendDetachedInventory(const std::string &name, u16 peer_id)
4219 if(m_detached_inventories.count(name) == 0){
4220 errorstream<<__FUNCTION_NAME<<": \""<<name<<"\" not found"<<std::endl;
4223 Inventory *inv = m_detached_inventories[name];
4225 std::ostringstream os(std::ios_base::binary);
4226 writeU16(os, TOCLIENT_DETACHED_INVENTORY);
4227 os<<serializeString(name);
4231 std::string s = os.str();
4232 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
4234 if (peer_id != PEER_ID_INEXISTENT)
4237 m_clients.send(peer_id, 0, data, true);
4241 m_clients.sendToAll(0,data,true);
4245 void Server::sendDetachedInventories(u16 peer_id)
4247 DSTACK(__FUNCTION_NAME);
4249 for(std::map<std::string, Inventory*>::iterator
4250 i = m_detached_inventories.begin();
4251 i != m_detached_inventories.end(); i++){
4252 const std::string &name = i->first;
4253 //Inventory *inv = i->second;
4254 sendDetachedInventory(name, peer_id);
4262 void Server::DiePlayer(u16 peer_id)
4264 DSTACK(__FUNCTION_NAME);
4266 PlayerSAO *playersao = getPlayerSAO(peer_id);
4269 infostream<<"Server::DiePlayer(): Player "
4270 <<playersao->getPlayer()->getName()
4271 <<" dies"<<std::endl;
4273 playersao->setHP(0);
4275 // Trigger scripted stuff
4276 m_script->on_dieplayer(playersao);
4278 SendPlayerHP(peer_id);
4279 SendDeathscreen(peer_id, false, v3f(0,0,0));
4282 void Server::RespawnPlayer(u16 peer_id)
4284 DSTACK(__FUNCTION_NAME);
4286 PlayerSAO *playersao = getPlayerSAO(peer_id);
4289 infostream<<"Server::RespawnPlayer(): Player "
4290 <<playersao->getPlayer()->getName()
4291 <<" respawns"<<std::endl;
4293 playersao->setHP(PLAYER_MAX_HP);
4295 bool repositioned = m_script->on_respawnplayer(playersao);
4297 v3f pos = findSpawnPos(m_env->getServerMap());
4298 playersao->setPos(pos);
4302 void Server::DenyAccess(u16 peer_id, const std::wstring &reason)
4304 DSTACK(__FUNCTION_NAME);
4306 SendAccessDenied(peer_id, reason);
4307 m_clients.event(peer_id, CSE_SetDenied);
4308 m_con.DisconnectPeer(peer_id);
4311 void Server::DeleteClient(u16 peer_id, ClientDeletionReason reason)
4313 DSTACK(__FUNCTION_NAME);
4314 std::wstring message;
4317 Clear references to playing sounds
4319 for(std::map<s32, ServerPlayingSound>::iterator
4320 i = m_playing_sounds.begin();
4321 i != m_playing_sounds.end();)
4323 ServerPlayingSound &psound = i->second;
4324 psound.clients.erase(peer_id);
4325 if(psound.clients.size() == 0)
4326 m_playing_sounds.erase(i++);
4331 Player *player = m_env->getPlayer(peer_id);
4333 // Collect information about leaving in chat
4335 if(player != NULL && reason != CDR_DENY)
4337 std::wstring name = narrow_to_wide(player->getName());
4340 message += L" left the game.";
4341 if(reason == CDR_TIMEOUT)
4342 message += L" (timed out)";
4346 /* Run scripts and remove from environment */
4350 PlayerSAO *playersao = player->getPlayerSAO();
4353 m_script->on_leaveplayer(playersao);
4355 playersao->disconnected();
4363 if(player != NULL && reason != CDR_DENY)
4365 std::ostringstream os(std::ios_base::binary);
4366 std::list<u16> clients = m_clients.getClientIDs();
4368 for(std::list<u16>::iterator
4369 i = clients.begin();
4370 i != clients.end(); ++i)
4373 Player *player = m_env->getPlayer(*i);
4376 // Get name of player
4377 os<<player->getName()<<" ";
4380 actionstream<<player->getName()<<" "
4381 <<(reason==CDR_TIMEOUT?"times out.":"leaves game.")
4382 <<" List of players: "<<os.str()<<std::endl;
4386 JMutexAutoLock env_lock(m_env_mutex);
4387 m_clients.DeleteClient(peer_id);
4391 // Send leave chat message to all remaining clients
4392 if(message.length() != 0)
4393 SendChatMessage(PEER_ID_INEXISTENT,message);
4396 void Server::UpdateCrafting(u16 peer_id)
4398 DSTACK(__FUNCTION_NAME);
4400 Player* player = m_env->getPlayer(peer_id);
4403 // Get a preview for crafting
4405 InventoryLocation loc;
4406 loc.setPlayer(player->getName());
4407 getCraftingResult(&player->inventory, preview, false, this);
4408 m_env->getScriptIface()->item_CraftPredict(preview, player->getPlayerSAO(), (&player->inventory)->getList("craft"), loc);
4410 // Put the new preview in
4411 InventoryList *plist = player->inventory.getList("craftpreview");
4413 assert(plist->getSize() >= 1);
4414 plist->changeItem(0, preview);
4417 RemoteClient* Server::getClient(u16 peer_id, ClientState state_min)
4419 RemoteClient *client = getClientNoEx(peer_id,state_min);
4421 throw ClientNotFoundException("Client not found");
4425 RemoteClient* Server::getClientNoEx(u16 peer_id, ClientState state_min)
4427 return m_clients.getClientNoEx(peer_id, state_min);
4430 std::string Server::getPlayerName(u16 peer_id)
4432 Player *player = m_env->getPlayer(peer_id);
4434 return "[id="+itos(peer_id)+"]";
4435 return player->getName();
4438 PlayerSAO* Server::getPlayerSAO(u16 peer_id)
4440 Player *player = m_env->getPlayer(peer_id);
4443 return player->getPlayerSAO();
4446 std::wstring Server::getStatusString()
4448 std::wostringstream os(std::ios_base::binary);
4451 os<<L"version="<<narrow_to_wide(minetest_version_simple);
4453 os<<L", uptime="<<m_uptime.get();
4455 os<<L", max_lag="<<m_env->getMaxLagEstimate();
4456 // Information about clients
4459 std::list<u16> clients = m_clients.getClientIDs();
4460 for(std::list<u16>::iterator i = clients.begin();
4461 i != clients.end(); ++i)
4464 Player *player = m_env->getPlayer(*i);
4465 // Get name of player
4466 std::wstring name = L"unknown";
4468 name = narrow_to_wide(player->getName());
4469 // Add name to information string
4477 if(((ServerMap*)(&m_env->getMap()))->isSavingEnabled() == false)
4478 os<<std::endl<<L"# Server: "<<" WARNING: Map saving is disabled.";
4479 if(g_settings->get("motd") != "")
4480 os<<std::endl<<L"# Server: "<<narrow_to_wide(g_settings->get("motd"));
4484 std::set<std::string> Server::getPlayerEffectivePrivs(const std::string &name)
4486 std::set<std::string> privs;
4487 m_script->getAuth(name, NULL, &privs);
4491 bool Server::checkPriv(const std::string &name, const std::string &priv)
4493 std::set<std::string> privs = getPlayerEffectivePrivs(name);
4494 return (privs.count(priv) != 0);
4497 void Server::reportPrivsModified(const std::string &name)
4500 std::list<u16> clients = m_clients.getClientIDs();
4501 for(std::list<u16>::iterator
4502 i = clients.begin();
4503 i != clients.end(); ++i){
4504 Player *player = m_env->getPlayer(*i);
4505 reportPrivsModified(player->getName());
4508 Player *player = m_env->getPlayer(name.c_str());
4511 SendPlayerPrivileges(player->peer_id);
4512 PlayerSAO *sao = player->getPlayerSAO();
4515 sao->updatePrivileges(
4516 getPlayerEffectivePrivs(name),
4521 void Server::reportInventoryFormspecModified(const std::string &name)
4523 Player *player = m_env->getPlayer(name.c_str());
4526 SendPlayerInventoryFormspec(player->peer_id);
4529 void Server::setIpBanned(const std::string &ip, const std::string &name)
4531 m_banmanager->add(ip, name);
4534 void Server::unsetIpBanned(const std::string &ip_or_name)
4536 m_banmanager->remove(ip_or_name);
4539 std::string Server::getBanDescription(const std::string &ip_or_name)
4541 return m_banmanager->getBanDescription(ip_or_name);
4544 void Server::notifyPlayer(const char *name, const std::wstring &msg)
4546 Player *player = m_env->getPlayer(name);
4550 if (player->peer_id == PEER_ID_INEXISTENT)
4553 SendChatMessage(player->peer_id, msg);
4556 bool Server::showFormspec(const char *playername, const std::string &formspec, const std::string &formname)
4558 Player *player = m_env->getPlayer(playername);
4562 infostream<<"showFormspec: couldn't find player:"<<playername<<std::endl;
4566 SendShowFormspecMessage(player->peer_id, formspec, formname);
4570 u32 Server::hudAdd(Player *player, HudElement *form) {
4574 u32 id = player->addHud(form);
4576 SendHUDAdd(player->peer_id, id, form);
4581 bool Server::hudRemove(Player *player, u32 id) {
4585 HudElement* todel = player->removeHud(id);
4592 SendHUDRemove(player->peer_id, id);
4596 bool Server::hudChange(Player *player, u32 id, HudElementStat stat, void *data) {
4600 SendHUDChange(player->peer_id, id, stat, data);
4604 bool Server::hudSetFlags(Player *player, u32 flags, u32 mask) {
4608 SendHUDSetFlags(player->peer_id, flags, mask);
4609 player->hud_flags = flags;
4611 PlayerSAO* playersao = player->getPlayerSAO();
4613 if (playersao == NULL)
4616 m_script->player_event(playersao, "hud_changed");
4620 bool Server::hudSetHotbarItemcount(Player *player, s32 hotbar_itemcount) {
4623 if (hotbar_itemcount <= 0 || hotbar_itemcount > HUD_HOTBAR_ITEMCOUNT_MAX)
4626 std::ostringstream os(std::ios::binary);
4627 writeS32(os, hotbar_itemcount);
4628 SendHUDSetParam(player->peer_id, HUD_PARAM_HOTBAR_ITEMCOUNT, os.str());
4632 void Server::hudSetHotbarImage(Player *player, std::string name) {
4636 SendHUDSetParam(player->peer_id, HUD_PARAM_HOTBAR_IMAGE, name);
4639 void Server::hudSetHotbarSelectedImage(Player *player, std::string name) {
4643 SendHUDSetParam(player->peer_id, HUD_PARAM_HOTBAR_SELECTED_IMAGE, name);
4646 bool Server::setLocalPlayerAnimations(Player *player, v2s32 animation_frames[4], f32 frame_speed)
4651 SendLocalPlayerAnimations(player->peer_id, animation_frames, frame_speed);
4655 bool Server::setPlayerEyeOffset(Player *player, v3f first, v3f third)
4660 SendEyeOffset(player->peer_id, first, third);
4664 bool Server::setSky(Player *player, const video::SColor &bgcolor,
4665 const std::string &type, const std::vector<std::string> ¶ms)
4670 SendSetSky(player->peer_id, bgcolor, type, params);
4674 bool Server::overrideDayNightRatio(Player *player, bool do_override,
4680 SendOverrideDayNightRatio(player->peer_id, do_override, ratio);
4684 void Server::notifyPlayers(const std::wstring &msg)
4686 SendChatMessage(PEER_ID_INEXISTENT,msg);
4689 void Server::spawnParticle(const char *playername, v3f pos,
4690 v3f velocity, v3f acceleration,
4691 float expirationtime, float size, bool
4692 collisiondetection, bool vertical, std::string texture)
4694 Player *player = m_env->getPlayer(playername);
4697 SendSpawnParticle(player->peer_id, pos, velocity, acceleration,
4698 expirationtime, size, collisiondetection, vertical, texture);
4701 void Server::spawnParticleAll(v3f pos, v3f velocity, v3f acceleration,
4702 float expirationtime, float size,
4703 bool collisiondetection, bool vertical, std::string texture)
4705 SendSpawnParticle(PEER_ID_INEXISTENT,pos, velocity, acceleration,
4706 expirationtime, size, collisiondetection, vertical, texture);
4709 u32 Server::addParticleSpawner(const char *playername,
4710 u16 amount, float spawntime,
4711 v3f minpos, v3f maxpos,
4712 v3f minvel, v3f maxvel,
4713 v3f minacc, v3f maxacc,
4714 float minexptime, float maxexptime,
4715 float minsize, float maxsize,
4716 bool collisiondetection, bool vertical, std::string texture)
4718 Player *player = m_env->getPlayer(playername);
4723 for(;;) // look for unused particlespawner id
4726 if (std::find(m_particlespawner_ids.begin(),
4727 m_particlespawner_ids.end(), id)
4728 == m_particlespawner_ids.end())
4730 m_particlespawner_ids.push_back(id);
4735 SendAddParticleSpawner(player->peer_id, amount, spawntime,
4736 minpos, maxpos, minvel, maxvel, minacc, maxacc,
4737 minexptime, maxexptime, minsize, maxsize,
4738 collisiondetection, vertical, texture, id);
4743 u32 Server::addParticleSpawnerAll(u16 amount, float spawntime,
4744 v3f minpos, v3f maxpos,
4745 v3f minvel, v3f maxvel,
4746 v3f minacc, v3f maxacc,
4747 float minexptime, float maxexptime,
4748 float minsize, float maxsize,
4749 bool collisiondetection, bool vertical, std::string texture)
4752 for(;;) // look for unused particlespawner id
4755 if (std::find(m_particlespawner_ids.begin(),
4756 m_particlespawner_ids.end(), id)
4757 == m_particlespawner_ids.end())
4759 m_particlespawner_ids.push_back(id);
4764 SendAddParticleSpawner(PEER_ID_INEXISTENT, amount, spawntime,
4765 minpos, maxpos, minvel, maxvel, minacc, maxacc,
4766 minexptime, maxexptime, minsize, maxsize,
4767 collisiondetection, vertical, texture, id);
4772 void Server::deleteParticleSpawner(const char *playername, u32 id)
4774 Player *player = m_env->getPlayer(playername);
4778 m_particlespawner_ids.erase(
4779 std::remove(m_particlespawner_ids.begin(),
4780 m_particlespawner_ids.end(), id),
4781 m_particlespawner_ids.end());
4782 SendDeleteParticleSpawner(player->peer_id, id);
4785 void Server::deleteParticleSpawnerAll(u32 id)
4787 m_particlespawner_ids.erase(
4788 std::remove(m_particlespawner_ids.begin(),
4789 m_particlespawner_ids.end(), id),
4790 m_particlespawner_ids.end());
4791 SendDeleteParticleSpawner(PEER_ID_INEXISTENT, id);
4794 Inventory* Server::createDetachedInventory(const std::string &name)
4796 if(m_detached_inventories.count(name) > 0){
4797 infostream<<"Server clearing detached inventory \""<<name<<"\""<<std::endl;
4798 delete m_detached_inventories[name];
4800 infostream<<"Server creating detached inventory \""<<name<<"\""<<std::endl;
4802 Inventory *inv = new Inventory(m_itemdef);
4804 m_detached_inventories[name] = inv;
4805 //TODO find a better way to do this
4806 sendDetachedInventory(name,PEER_ID_INEXISTENT);
4813 BoolScopeSet(bool *dst, bool val):
4816 m_orig_state = *m_dst;
4821 *m_dst = m_orig_state;
4828 // actions: time-reversed list
4829 // Return value: success/failure
4830 bool Server::rollbackRevertActions(const std::list<RollbackAction> &actions,
4831 std::list<std::string> *log)
4833 infostream<<"Server::rollbackRevertActions(len="<<actions.size()<<")"<<std::endl;
4834 ServerMap *map = (ServerMap*)(&m_env->getMap());
4836 // Fail if no actions to handle
4837 if(actions.empty()){
4838 log->push_back("Nothing to do.");
4845 for(std::list<RollbackAction>::const_iterator
4846 i = actions.begin();
4847 i != actions.end(); i++)
4849 const RollbackAction &action = *i;
4851 bool success = action.applyRevert(map, this, this);
4854 std::ostringstream os;
4855 os<<"Revert of step ("<<num_tried<<") "<<action.toString()<<" failed";
4856 infostream<<"Map::rollbackRevertActions(): "<<os.str()<<std::endl;
4858 log->push_back(os.str());
4860 std::ostringstream os;
4861 os<<"Successfully reverted step ("<<num_tried<<") "<<action.toString();
4862 infostream<<"Map::rollbackRevertActions(): "<<os.str()<<std::endl;
4864 log->push_back(os.str());
4868 infostream<<"Map::rollbackRevertActions(): "<<num_failed<<"/"<<num_tried
4869 <<" failed"<<std::endl;
4871 // Call it done if less than half failed
4872 return num_failed <= num_tried/2;
4875 // IGameDef interface
4877 IItemDefManager* Server::getItemDefManager()
4881 INodeDefManager* Server::getNodeDefManager()
4885 ICraftDefManager* Server::getCraftDefManager()
4889 ITextureSource* Server::getTextureSource()
4893 IShaderSource* Server::getShaderSource()
4897 scene::ISceneManager* Server::getSceneManager()
4902 u16 Server::allocateUnknownNodeId(const std::string &name)
4904 return m_nodedef->allocateDummy(name);
4906 ISoundManager* Server::getSoundManager()
4908 return &dummySoundManager;
4910 MtEventManager* Server::getEventManager()
4915 IWritableItemDefManager* Server::getWritableItemDefManager()
4919 IWritableNodeDefManager* Server::getWritableNodeDefManager()
4923 IWritableCraftDefManager* Server::getWritableCraftDefManager()
4928 const ModSpec* Server::getModSpec(const std::string &modname)
4930 for(std::vector<ModSpec>::iterator i = m_mods.begin();
4931 i != m_mods.end(); i++){
4932 const ModSpec &mod = *i;
4933 if(mod.name == modname)
4938 void Server::getModNames(std::list<std::string> &modlist)
4940 for(std::vector<ModSpec>::iterator i = m_mods.begin(); i != m_mods.end(); i++)
4942 modlist.push_back(i->name);
4945 std::string Server::getBuiltinLuaPath()
4947 return porting::path_share + DIR_DELIM + "builtin";
4950 v3f findSpawnPos(ServerMap &map)
4952 //return v3f(50,50,50)*BS;
4957 nodepos = v2s16(0,0);
4962 s16 water_level = map.getWaterLevel();
4964 // Try to find a good place a few times
4965 for(s32 i=0; i<1000; i++)
4968 // We're going to try to throw the player to this position
4969 v2s16 nodepos2d = v2s16(
4970 -range + (myrand() % (range * 2)),
4971 -range + (myrand() % (range * 2)));
4973 // Get ground height at point
4974 s16 groundheight = map.findGroundLevel(nodepos2d);
4975 if (groundheight <= water_level) // Don't go underwater
4977 if (groundheight > water_level + 6) // Don't go to high places
4980 nodepos = v3s16(nodepos2d.X, groundheight, nodepos2d.Y);
4981 bool is_good = false;
4983 for (s32 i = 0; i < 10; i++) {
4984 v3s16 blockpos = getNodeBlockPos(nodepos);
4985 map.emergeBlock(blockpos, true);
4986 content_t c = map.getNodeNoEx(nodepos).getContent();
4987 if (c == CONTENT_AIR || c == CONTENT_IGNORE) {
4989 if (air_count >= 2){
4997 // Found a good place
4998 //infostream<<"Searched through "<<i<<" places."<<std::endl;
5004 return intToFloat(nodepos, BS);
5007 PlayerSAO* Server::emergePlayer(const char *name, u16 peer_id)
5009 RemotePlayer *player = NULL;
5010 bool newplayer = false;
5013 Try to get an existing player
5015 player = static_cast<RemotePlayer*>(m_env->getPlayer(name));
5017 // If player is already connected, cancel
5018 if(player != NULL && player->peer_id != 0)
5020 infostream<<"emergePlayer(): Player already connected"<<std::endl;
5025 If player with the wanted peer_id already exists, cancel.
5027 if(m_env->getPlayer(peer_id) != NULL)
5029 infostream<<"emergePlayer(): Player with wrong name but same"
5030 " peer_id already exists"<<std::endl;
5034 // Load player if it isn't already loaded
5036 player = static_cast<RemotePlayer*>(m_env->loadPlayer(name));
5039 // Create player if it doesn't exist
5042 player = new RemotePlayer(this, name);
5043 // Set player position
5044 infostream<<"Server: Finding spawn place for player \""
5045 <<name<<"\""<<std::endl;
5046 v3f pos = findSpawnPos(m_env->getServerMap());
5047 player->setPosition(pos);
5049 // Make sure the player is saved
5050 player->setModified(true);
5052 // Add player to environment
5053 m_env->addPlayer(player);
5056 // Create a new player active object
5057 PlayerSAO *playersao = new PlayerSAO(m_env, player, peer_id,
5058 getPlayerEffectivePrivs(player->getName()),
5061 /* Clean up old HUD elements from previous sessions */
5064 /* Add object to environment */
5065 m_env->addActiveObject(playersao);
5069 m_script->on_newplayer(playersao);
5075 void dedicated_server_loop(Server &server, bool &kill)
5077 DSTACK(__FUNCTION_NAME);
5079 verbosestream<<"dedicated_server_loop()"<<std::endl;
5081 IntervalLimiter m_profiler_interval;
5085 float steplen = g_settings->getFloat("dedicated_server_step");
5086 // This is kind of a hack but can be done like this
5087 // because server.step() is very light
5089 ScopeProfiler sp(g_profiler, "dedicated server sleep");
5090 sleep_ms((int)(steplen*1000.0));
5092 server.step(steplen);
5094 if(server.getShutdownRequested() || kill)
5096 infostream<<"Dedicated server quitting"<<std::endl;
5098 if(g_settings->getBool("server_announce") == true)
5099 ServerList::sendAnnounce("delete");
5107 float profiler_print_interval =
5108 g_settings->getFloat("profiler_print_interval");
5109 if(profiler_print_interval != 0)
5111 if(m_profiler_interval.step(steplen, profiler_print_interval))
5113 infostream<<"Profiler:"<<std::endl;
5114 g_profiler->print(infostream);
5115 g_profiler->clear();