3 Copyright (C) 2010-2013 celeron55, Perttu Ahola <celeron55@gmail.com>
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU Lesser General Public License as published by
7 the Free Software Foundation; either version 2.1 of the License, or
8 (at your option) any later version.
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU Lesser General Public License for more details.
15 You should have received a copy of the GNU Lesser General Public License along
16 with this program; if not, write to the Free Software Foundation, Inc.,
17 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
24 #include "clientserver.h"
26 #include "environment.h"
28 #include "jthread/jmutexautolock.h"
30 #include "constants.h"
36 #include "serverobject.h"
37 #include "genericobject.h"
41 #include "scripting_game.h"
48 #include "content_mapnode.h"
49 #include "content_nodemeta.h"
50 #include "content_abm.h"
51 #include "content_sao.h"
56 #include "sound.h" // dummySoundManager
57 #include "event_manager.h"
59 #include "serverlist.h"
60 #include "util/string.h"
61 #include "util/pointedthing.h"
62 #include "util/mathconstants.h"
64 #include "util/serialize.h"
65 #include "util/thread.h"
66 #include "defaultsettings.h"
68 class ClientNotFoundException : public BaseException
71 ClientNotFoundException(const char *s):
76 class ServerThread : public JThread
82 ServerThread(Server *server):
91 void * ServerThread::Thread()
93 log_register_thread("ServerThread");
95 DSTACK(__FUNCTION_NAME);
96 BEGIN_DEBUG_EXCEPTION_HANDLER
98 m_server->AsyncRunStep(true);
102 porting::setThreadName("ServerThread");
104 while(!StopRequested())
107 //TimeTaker timer("AsyncRunStep() + Receive()");
109 m_server->AsyncRunStep();
114 catch(con::NoIncomingDataException &e)
117 catch(con::PeerNotFoundException &e)
119 infostream<<"Server: PeerNotFoundException"<<std::endl;
121 catch(ClientNotFoundException &e)
124 catch(con::ConnectionBindFailed &e)
126 m_server->setAsyncFatalError(e.what());
130 m_server->setAsyncFatalError(e.what());
134 END_DEBUG_EXCEPTION_HANDLER(errorstream)
139 v3f ServerSoundParams::getPos(ServerEnvironment *env, bool *pos_exists) const
141 if(pos_exists) *pos_exists = false;
146 if(pos_exists) *pos_exists = true;
151 ServerActiveObject *sao = env->getActiveObject(object);
154 if(pos_exists) *pos_exists = true;
155 return sao->getBasePosition(); }
167 const std::string &path_world,
168 const SubgameSpec &gamespec,
169 bool simple_singleplayer_mode,
172 m_path_world(path_world),
173 m_gamespec(gamespec),
174 m_simple_singleplayer_mode(simple_singleplayer_mode),
175 m_async_fatal_error(""),
184 m_enable_rollback_recording(false),
187 m_itemdef(createItemDefManager()),
188 m_nodedef(createNodeDefManager()),
189 m_craftdef(createCraftDefManager()),
190 m_event(new EventManager()),
192 m_time_of_day_send_timer(0),
195 m_shutdown_requested(false),
196 m_ignore_map_edit_events(false),
197 m_ignore_map_edit_events_peer_id(0)
200 m_liquid_transform_timer = 0.0;
201 m_liquid_transform_every = 1.0;
202 m_print_info_timer = 0.0;
203 m_masterserver_timer = 0.0;
204 m_objectdata_timer = 0.0;
205 m_emergethread_trigger_timer = 0.0;
206 m_savemap_timer = 0.0;
209 m_lag = g_settings->getFloat("dedicated_server_step");
212 throw ServerError("Supplied empty world path");
214 if(!gamespec.isValid())
215 throw ServerError("Supplied invalid gamespec");
217 infostream<<"Server created for gameid \""<<m_gamespec.id<<"\"";
218 if(m_simple_singleplayer_mode)
219 infostream<<" in simple singleplayer mode"<<std::endl;
221 infostream<<std::endl;
222 infostream<<"- world: "<<m_path_world<<std::endl;
223 infostream<<"- game: "<<m_gamespec.path<<std::endl;
225 // Initialize default settings and override defaults with those provided
227 set_default_settings(g_settings);
228 Settings gamedefaults;
229 getGameMinetestConfig(gamespec.path, gamedefaults);
230 override_default_settings(g_settings, &gamedefaults);
232 // Create server thread
233 m_thread = new ServerThread(this);
235 // Create emerge manager
236 m_emerge = new EmergeManager(this);
238 // Create world if it doesn't exist
239 if(!initializeWorld(m_path_world, m_gamespec.id))
240 throw ServerError("Failed to initialize world");
242 // Create ban manager
243 std::string ban_path = m_path_world + DIR_DELIM "ipban.txt";
244 m_banmanager = new BanManager(ban_path);
246 // Create rollback manager
247 m_rollback = new RollbackManager(m_path_world, this);
249 ModConfiguration modconf(m_path_world);
250 m_mods = modconf.getMods();
251 std::vector<ModSpec> unsatisfied_mods = modconf.getUnsatisfiedMods();
252 // complain about mods with unsatisfied dependencies
253 if(!modconf.isConsistent())
255 for(std::vector<ModSpec>::iterator it = unsatisfied_mods.begin();
256 it != unsatisfied_mods.end(); ++it)
259 errorstream << "mod \"" << mod.name << "\" has unsatisfied dependencies: ";
260 for(std::set<std::string>::iterator dep_it = mod.unsatisfied_depends.begin();
261 dep_it != mod.unsatisfied_depends.end(); ++dep_it)
262 errorstream << " \"" << *dep_it << "\"";
263 errorstream << std::endl;
267 Settings worldmt_settings;
268 std::string worldmt = m_path_world + DIR_DELIM + "world.mt";
269 worldmt_settings.readConfigFile(worldmt.c_str());
270 std::vector<std::string> names = worldmt_settings.getNames();
271 std::set<std::string> load_mod_names;
272 for(std::vector<std::string>::iterator it = names.begin();
273 it != names.end(); ++it)
275 std::string name = *it;
276 if(name.compare(0,9,"load_mod_")==0 && worldmt_settings.getBool(name))
277 load_mod_names.insert(name.substr(9));
279 // complain about mods declared to be loaded, but not found
280 for(std::vector<ModSpec>::iterator it = m_mods.begin();
281 it != m_mods.end(); ++it)
282 load_mod_names.erase((*it).name);
283 for(std::vector<ModSpec>::iterator it = unsatisfied_mods.begin();
284 it != unsatisfied_mods.end(); ++it)
285 load_mod_names.erase((*it).name);
286 if(!load_mod_names.empty())
288 errorstream << "The following mods could not be found:";
289 for(std::set<std::string>::iterator it = load_mod_names.begin();
290 it != load_mod_names.end(); ++it)
291 errorstream << " \"" << (*it) << "\"";
292 errorstream << std::endl;
296 JMutexAutoLock envlock(m_env_mutex);
298 // Load mapgen params from Settings
299 m_emerge->loadMapgenParams();
301 // Create the Map (loads map_meta.txt, overriding configured mapgen params)
302 ServerMap *servermap = new ServerMap(path_world, this, m_emerge);
304 // Initialize scripting
305 infostream<<"Server: Initializing Lua"<<std::endl;
307 m_script = new GameScripting(this);
309 std::string scriptpath = getBuiltinLuaPath() + DIR_DELIM "init.lua";
311 if (!m_script->loadScript(scriptpath))
312 throw ModError("Failed to load and run " + scriptpath);
315 infostream<<"Server: Loading mods: ";
316 for(std::vector<ModSpec>::iterator i = m_mods.begin();
317 i != m_mods.end(); i++){
318 const ModSpec &mod = *i;
319 infostream<<mod.name<<" ";
321 infostream<<std::endl;
322 // Load and run "mod" scripts
323 for(std::vector<ModSpec>::iterator i = m_mods.begin();
324 i != m_mods.end(); i++){
325 const ModSpec &mod = *i;
326 std::string scriptpath = mod.path + DIR_DELIM + "init.lua";
327 infostream<<" ["<<padStringRight(mod.name, 12)<<"] [\""
328 <<scriptpath<<"\"]"<<std::endl;
329 bool success = m_script->loadMod(scriptpath, mod.name);
331 errorstream<<"Server: Failed to load and run "
332 <<scriptpath<<std::endl;
333 throw ModError("Failed to load and run "+scriptpath);
337 // Read Textures and calculate sha1 sums
340 // Apply item aliases in the node definition manager
341 m_nodedef->updateAliases(m_itemdef);
343 // Perform pending node name resolutions
344 m_nodedef->runNodeResolverCallbacks();
346 // Initialize Environment
347 m_env = new ServerEnvironment(servermap, m_script, this, m_path_world);
349 m_clients.setEnv(m_env);
351 // Initialize mapgens
352 m_emerge->initMapgens();
354 // Give environment reference to scripting api
355 m_script->initializeEnvironment(m_env);
357 // Register us to receive map edit events
358 servermap->addEventReceiver(this);
360 // If file exists, load environment metadata
361 if(fs::PathExists(m_path_world + DIR_DELIM "env_meta.txt"))
363 infostream<<"Server: Loading environment metadata"<<std::endl;
367 // Add some test ActiveBlockModifiers to environment
368 add_legacy_abms(m_env, m_nodedef);
370 m_liquid_transform_every = g_settings->getFloat("liquid_update");
375 infostream<<"Server destructing"<<std::endl;
377 // Send shutdown message
378 SendChatMessage(PEER_ID_INEXISTENT, L"*** Server shutting down");
381 JMutexAutoLock envlock(m_env_mutex);
383 // Execute script shutdown hooks
384 m_script->on_shutdown();
386 infostream<<"Server: Saving players"<<std::endl;
387 m_env->saveLoadedPlayers();
389 infostream<<"Server: Saving environment metadata"<<std::endl;
397 // stop all emerge threads before deleting players that may have
398 // requested blocks to be emerged
399 m_emerge->stopThreads();
401 // Delete things in the reverse order of creation
404 // N.B. the EmergeManager should be deleted after the Environment since Map
405 // depends on EmergeManager to write its current params to the map meta
414 // Deinitialize scripting
415 infostream<<"Server: Deinitializing scripting"<<std::endl;
418 // Delete detached inventories
419 for (std::map<std::string, Inventory*>::iterator
420 i = m_detached_inventories.begin();
421 i != m_detached_inventories.end(); i++) {
426 void Server::start(Address bind_addr)
428 DSTACK(__FUNCTION_NAME);
429 infostream<<"Starting server on "
430 << bind_addr.serializeString() <<"..."<<std::endl;
432 // Stop thread if already running
435 // Initialize connection
436 m_con.SetTimeoutMs(30);
437 m_con.Serve(bind_addr);
442 // ASCII art for the win!
444 <<" .__ __ __ "<<std::endl
445 <<" _____ |__| ____ _____/ |_ ____ _______/ |_ "<<std::endl
446 <<" / \\| |/ \\_/ __ \\ __\\/ __ \\ / ___/\\ __\\"<<std::endl
447 <<"| Y Y \\ | | \\ ___/| | \\ ___/ \\___ \\ | | "<<std::endl
448 <<"|__|_| /__|___| /\\___ >__| \\___ >____ > |__| "<<std::endl
449 <<" \\/ \\/ \\/ \\/ \\/ "<<std::endl;
450 actionstream<<"World at ["<<m_path_world<<"]"<<std::endl;
451 actionstream<<"Server for gameid=\""<<m_gamespec.id
452 <<"\" listening on "<<bind_addr.serializeString()<<":"
453 <<bind_addr.getPort() << "."<<std::endl;
458 DSTACK(__FUNCTION_NAME);
460 infostream<<"Server: Stopping and waiting threads"<<std::endl;
462 // Stop threads (set run=false first so both start stopping)
464 //m_emergethread.setRun(false);
466 //m_emergethread.stop();
468 infostream<<"Server: Threads stopped"<<std::endl;
471 void Server::step(float dtime)
473 DSTACK(__FUNCTION_NAME);
478 JMutexAutoLock lock(m_step_dtime_mutex);
479 m_step_dtime += dtime;
481 // Throw if fatal error occurred in thread
482 std::string async_err = m_async_fatal_error.get();
484 throw ServerError(async_err);
488 void Server::AsyncRunStep(bool initial_step)
490 DSTACK(__FUNCTION_NAME);
492 g_profiler->add("Server::AsyncRunStep (num)", 1);
496 JMutexAutoLock lock1(m_step_dtime_mutex);
497 dtime = m_step_dtime;
501 // Send blocks to clients
505 if((dtime < 0.001) && (initial_step == false))
508 g_profiler->add("Server::AsyncRunStep with dtime (num)", 1);
510 //infostream<<"Server steps "<<dtime<<std::endl;
511 //infostream<<"Server::AsyncRunStep(): dtime="<<dtime<<std::endl;
514 JMutexAutoLock lock1(m_step_dtime_mutex);
515 m_step_dtime -= dtime;
522 m_uptime.set(m_uptime.get() + dtime);
528 Update time of day and overall game time
531 JMutexAutoLock envlock(m_env_mutex);
533 m_env->setTimeOfDaySpeed(g_settings->getFloat("time_speed"));
536 Send to clients at constant intervals
539 m_time_of_day_send_timer -= dtime;
540 if(m_time_of_day_send_timer < 0.0)
542 m_time_of_day_send_timer = g_settings->getFloat("time_send_interval");
543 u16 time = m_env->getTimeOfDay();
544 float time_speed = g_settings->getFloat("time_speed");
545 SendTimeOfDay(PEER_ID_INEXISTENT, time, time_speed);
550 JMutexAutoLock lock(m_env_mutex);
551 // Figure out and report maximum lag to environment
552 float max_lag = m_env->getMaxLagEstimate();
553 max_lag *= 0.9998; // Decrease slowly (about half per 5 minutes)
555 if(dtime > 0.1 && dtime > max_lag * 2.0)
556 infostream<<"Server: Maximum lag peaked to "<<dtime
560 m_env->reportMaxLagEstimate(max_lag);
562 ScopeProfiler sp(g_profiler, "SEnv step");
563 ScopeProfiler sp2(g_profiler, "SEnv step avg", SPT_AVG);
567 static const float map_timer_and_unload_dtime = 2.92;
568 if(m_map_timer_and_unload_interval.step(dtime, map_timer_and_unload_dtime))
570 JMutexAutoLock lock(m_env_mutex);
571 // Run Map's timers and unload unused data
572 ScopeProfiler sp(g_profiler, "Server: map timer and unload");
573 m_env->getMap().timerUpdate(map_timer_and_unload_dtime,
574 g_settings->getFloat("server_unload_unused_data_timeout"));
585 JMutexAutoLock lock(m_env_mutex);
587 std::list<u16> clientids = m_clients.getClientIDs();
589 ScopeProfiler sp(g_profiler, "Server: handle players");
591 for(std::list<u16>::iterator
592 i = clientids.begin();
593 i != clientids.end(); ++i)
595 PlayerSAO *playersao = getPlayerSAO(*i);
596 if(playersao == NULL)
600 Handle player HPs (die if hp=0)
602 if(playersao->m_hp_not_sent && g_settings->getBool("enable_damage"))
604 if(playersao->getHP() == 0)
611 Send player breath if changed
613 if(playersao->m_breath_not_sent) {
614 SendPlayerBreath(*i);
618 Send player inventories if necessary
620 if(playersao->m_moved){
622 playersao->m_moved = false;
624 if(playersao->m_inventory_not_sent){
631 /* Transform liquids */
632 m_liquid_transform_timer += dtime;
633 if(m_liquid_transform_timer >= m_liquid_transform_every)
635 m_liquid_transform_timer -= m_liquid_transform_every;
637 JMutexAutoLock lock(m_env_mutex);
639 ScopeProfiler sp(g_profiler, "Server: liquid transform");
641 std::map<v3s16, MapBlock*> modified_blocks;
642 m_env->getMap().transformLiquids(modified_blocks);
647 core::map<v3s16, MapBlock*> lighting_modified_blocks;
648 ServerMap &map = ((ServerMap&)m_env->getMap());
649 map.updateLighting(modified_blocks, lighting_modified_blocks);
651 // Add blocks modified by lighting to modified_blocks
652 for(core::map<v3s16, MapBlock*>::Iterator
653 i = lighting_modified_blocks.getIterator();
654 i.atEnd() == false; i++)
656 MapBlock *block = i.getNode()->getValue();
657 modified_blocks.insert(block->getPos(), block);
661 Set the modified blocks unsent for all the clients
663 if(!modified_blocks.empty())
665 SetBlocksNotSent(modified_blocks);
668 m_clients.step(dtime);
670 m_lag += (m_lag > dtime ? -1 : 1) * dtime/100;
672 // send masterserver announce
674 float &counter = m_masterserver_timer;
675 if(!isSingleplayer() && (!counter || counter >= 300.0) &&
676 g_settings->getBool("server_announce"))
678 ServerList::sendAnnounce(counter ? "update" : "start",
679 m_clients.getPlayerNames(),
681 m_env->getGameTime(),
684 m_emerge->params.mg_name,
693 Check added and deleted active objects
696 //infostream<<"Server: Checking added and deleted active objects"<<std::endl;
697 JMutexAutoLock envlock(m_env_mutex);
700 std::map<u16, RemoteClient*> clients = m_clients.getClientList();
701 ScopeProfiler sp(g_profiler, "Server: checking added and deleted objs");
703 // Radius inside which objects are active
704 s16 radius = g_settings->getS16("active_object_send_range_blocks");
705 s16 player_radius = g_settings->getS16("player_transfer_distance");
707 if (player_radius == 0 && g_settings->exists("unlimited_player_transfer_distance") &&
708 !g_settings->getBool("unlimited_player_transfer_distance"))
709 player_radius = radius;
711 radius *= MAP_BLOCKSIZE;
712 player_radius *= MAP_BLOCKSIZE;
714 for(std::map<u16, RemoteClient*>::iterator
716 i != clients.end(); ++i)
718 RemoteClient *client = i->second;
720 // If definitions and textures have not been sent, don't
721 // send objects either
722 if (client->getState() < CS_DefinitionsSent)
725 Player *player = m_env->getPlayer(client->peer_id);
728 // This can happen if the client timeouts somehow
729 /*infostream<<"WARNING: "<<__FUNCTION_NAME<<": Client "
731 <<" has no associated player"<<std::endl;*/
734 v3s16 pos = floatToInt(player->getPosition(), BS);
736 std::set<u16> removed_objects;
737 std::set<u16> added_objects;
738 m_env->getRemovedActiveObjects(pos, radius, player_radius,
739 client->m_known_objects, removed_objects);
740 m_env->getAddedActiveObjects(pos, radius, player_radius,
741 client->m_known_objects, added_objects);
743 // Ignore if nothing happened
744 if(removed_objects.empty() && added_objects.empty())
746 //infostream<<"active objects: none changed"<<std::endl;
750 std::string data_buffer;
754 // Handle removed objects
755 writeU16((u8*)buf, removed_objects.size());
756 data_buffer.append(buf, 2);
757 for(std::set<u16>::iterator
758 i = removed_objects.begin();
759 i != removed_objects.end(); ++i)
763 ServerActiveObject* obj = m_env->getActiveObject(id);
765 // Add to data buffer for sending
766 writeU16((u8*)buf, id);
767 data_buffer.append(buf, 2);
769 // Remove from known objects
770 client->m_known_objects.erase(id);
772 if(obj && obj->m_known_by_count > 0)
773 obj->m_known_by_count--;
776 // Handle added objects
777 writeU16((u8*)buf, added_objects.size());
778 data_buffer.append(buf, 2);
779 for(std::set<u16>::iterator
780 i = added_objects.begin();
781 i != added_objects.end(); ++i)
785 ServerActiveObject* obj = m_env->getActiveObject(id);
788 u8 type = ACTIVEOBJECT_TYPE_INVALID;
790 infostream<<"WARNING: "<<__FUNCTION_NAME
791 <<": NULL object"<<std::endl;
793 type = obj->getSendType();
795 // Add to data buffer for sending
796 writeU16((u8*)buf, id);
797 data_buffer.append(buf, 2);
798 writeU8((u8*)buf, type);
799 data_buffer.append(buf, 1);
802 data_buffer.append(serializeLongString(
803 obj->getClientInitializationData(client->net_proto_version)));
805 data_buffer.append(serializeLongString(""));
807 // Add to known objects
808 client->m_known_objects.insert(id);
811 obj->m_known_by_count++;
815 SharedBuffer<u8> reply(2 + data_buffer.size());
816 writeU16(&reply[0], TOCLIENT_ACTIVE_OBJECT_REMOVE_ADD);
817 memcpy((char*)&reply[2], data_buffer.c_str(),
820 m_clients.send(client->peer_id, 0, reply, true);
822 verbosestream<<"Server: Sent object remove/add: "
823 <<removed_objects.size()<<" removed, "
824 <<added_objects.size()<<" added, "
825 <<"packet size is "<<reply.getSize()<<std::endl;
830 Collect a list of all the objects known by the clients
831 and report it back to the environment.
834 core::map<u16, bool> all_known_objects;
836 for(core::map<u16, RemoteClient*>::Iterator
837 i = m_clients.getIterator();
838 i.atEnd() == false; i++)
840 RemoteClient *client = i.getNode()->getValue();
841 // Go through all known objects of client
842 for(core::map<u16, bool>::Iterator
843 i = client->m_known_objects.getIterator();
844 i.atEnd()==false; i++)
846 u16 id = i.getNode()->getKey();
847 all_known_objects[id] = true;
851 m_env->setKnownActiveObjects(whatever);
860 JMutexAutoLock envlock(m_env_mutex);
861 ScopeProfiler sp(g_profiler, "Server: sending object messages");
864 // Value = data sent by object
865 std::map<u16, std::list<ActiveObjectMessage>* > buffered_messages;
867 // Get active object messages from environment
870 ActiveObjectMessage aom = m_env->getActiveObjectMessage();
874 std::list<ActiveObjectMessage>* message_list = NULL;
875 std::map<u16, std::list<ActiveObjectMessage>* >::iterator n;
876 n = buffered_messages.find(aom.id);
877 if(n == buffered_messages.end())
879 message_list = new std::list<ActiveObjectMessage>;
880 buffered_messages[aom.id] = message_list;
884 message_list = n->second;
886 message_list->push_back(aom);
890 std::map<u16, RemoteClient*> clients = m_clients.getClientList();
891 // Route data to every client
892 for(std::map<u16, RemoteClient*>::iterator
894 i != clients.end(); ++i)
896 RemoteClient *client = i->second;
897 std::string reliable_data;
898 std::string unreliable_data;
899 // Go through all objects in message buffer
900 for(std::map<u16, std::list<ActiveObjectMessage>* >::iterator
901 j = buffered_messages.begin();
902 j != buffered_messages.end(); ++j)
904 // If object is not known by client, skip it
906 if(client->m_known_objects.find(id) == client->m_known_objects.end())
908 // Get message list of object
909 std::list<ActiveObjectMessage>* list = j->second;
910 // Go through every message
911 for(std::list<ActiveObjectMessage>::iterator
912 k = list->begin(); k != list->end(); ++k)
914 // Compose the full new data with header
915 ActiveObjectMessage aom = *k;
916 std::string new_data;
919 writeU16((u8*)&buf[0], aom.id);
920 new_data.append(buf, 2);
922 new_data += serializeString(aom.datastring);
923 // Add data to buffer
925 reliable_data += new_data;
927 unreliable_data += new_data;
931 reliable_data and unreliable_data are now ready.
934 if(reliable_data.size() > 0)
936 SharedBuffer<u8> reply(2 + reliable_data.size());
937 writeU16(&reply[0], TOCLIENT_ACTIVE_OBJECT_MESSAGES);
938 memcpy((char*)&reply[2], reliable_data.c_str(),
939 reliable_data.size());
941 m_clients.send(client->peer_id, 0, reply, true);
943 if(unreliable_data.size() > 0)
945 SharedBuffer<u8> reply(2 + unreliable_data.size());
946 writeU16(&reply[0], TOCLIENT_ACTIVE_OBJECT_MESSAGES);
947 memcpy((char*)&reply[2], unreliable_data.c_str(),
948 unreliable_data.size());
949 // Send as unreliable
950 m_clients.send(client->peer_id, 1, reply, false);
953 /*if(reliable_data.size() > 0 || unreliable_data.size() > 0)
955 infostream<<"Server: Size of object message data: "
956 <<"reliable: "<<reliable_data.size()
957 <<", unreliable: "<<unreliable_data.size()
963 // Clear buffered_messages
964 for(std::map<u16, std::list<ActiveObjectMessage>* >::iterator
965 i = buffered_messages.begin();
966 i != buffered_messages.end(); ++i)
973 Send queued-for-sending map edit events.
976 // We will be accessing the environment
977 JMutexAutoLock lock(m_env_mutex);
979 // Don't send too many at a time
982 // Single change sending is disabled if queue size is not small
983 bool disable_single_change_sending = false;
984 if(m_unsent_map_edit_queue.size() >= 4)
985 disable_single_change_sending = true;
987 int event_count = m_unsent_map_edit_queue.size();
989 // We'll log the amount of each
992 while(m_unsent_map_edit_queue.size() != 0)
994 MapEditEvent* event = m_unsent_map_edit_queue.pop_front();
996 // Players far away from the change are stored here.
997 // Instead of sending the changes, MapBlocks are set not sent
999 std::list<u16> far_players;
1001 if(event->type == MEET_ADDNODE || event->type == MEET_SWAPNODE)
1003 //infostream<<"Server: MEET_ADDNODE"<<std::endl;
1004 prof.add("MEET_ADDNODE", 1);
1005 if(disable_single_change_sending)
1006 sendAddNode(event->p, event->n, event->already_known_by_peer,
1007 &far_players, 5, event->type == MEET_ADDNODE);
1009 sendAddNode(event->p, event->n, event->already_known_by_peer,
1010 &far_players, 30, event->type == MEET_ADDNODE);
1012 else if(event->type == MEET_REMOVENODE)
1014 //infostream<<"Server: MEET_REMOVENODE"<<std::endl;
1015 prof.add("MEET_REMOVENODE", 1);
1016 if(disable_single_change_sending)
1017 sendRemoveNode(event->p, event->already_known_by_peer,
1020 sendRemoveNode(event->p, event->already_known_by_peer,
1023 else if(event->type == MEET_BLOCK_NODE_METADATA_CHANGED)
1025 infostream<<"Server: MEET_BLOCK_NODE_METADATA_CHANGED"<<std::endl;
1026 prof.add("MEET_BLOCK_NODE_METADATA_CHANGED", 1);
1027 setBlockNotSent(event->p);
1029 else if(event->type == MEET_OTHER)
1031 infostream<<"Server: MEET_OTHER"<<std::endl;
1032 prof.add("MEET_OTHER", 1);
1033 for(std::set<v3s16>::iterator
1034 i = event->modified_blocks.begin();
1035 i != event->modified_blocks.end(); ++i)
1037 setBlockNotSent(*i);
1042 prof.add("unknown", 1);
1043 infostream<<"WARNING: Server: Unknown MapEditEvent "
1044 <<((u32)event->type)<<std::endl;
1048 Set blocks not sent to far players
1050 if(!far_players.empty())
1052 // Convert list format to that wanted by SetBlocksNotSent
1053 std::map<v3s16, MapBlock*> modified_blocks2;
1054 for(std::set<v3s16>::iterator
1055 i = event->modified_blocks.begin();
1056 i != event->modified_blocks.end(); ++i)
1058 modified_blocks2[*i] =
1059 m_env->getMap().getBlockNoCreateNoEx(*i);
1061 // Set blocks not sent
1062 for(std::list<u16>::iterator
1063 i = far_players.begin();
1064 i != far_players.end(); ++i)
1067 RemoteClient *client = getClient(peer_id);
1070 client->SetBlocksNotSent(modified_blocks2);
1076 /*// Don't send too many at a time
1078 if(count >= 1 && m_unsent_map_edit_queue.size() < 100)
1082 if(event_count >= 5){
1083 infostream<<"Server: MapEditEvents:"<<std::endl;
1084 prof.print(infostream);
1085 } else if(event_count != 0){
1086 verbosestream<<"Server: MapEditEvents:"<<std::endl;
1087 prof.print(verbosestream);
1093 Trigger emergethread (it somehow gets to a non-triggered but
1094 bysy state sometimes)
1097 float &counter = m_emergethread_trigger_timer;
1103 m_emerge->startThreads();
1105 // Update m_enable_rollback_recording here too
1106 m_enable_rollback_recording =
1107 g_settings->getBool("enable_rollback_recording");
1111 // Save map, players and auth stuff
1113 float &counter = m_savemap_timer;
1115 if(counter >= g_settings->getFloat("server_map_save_interval"))
1118 JMutexAutoLock lock(m_env_mutex);
1120 ScopeProfiler sp(g_profiler, "Server: saving stuff");
1123 if (m_banmanager->isModified()) {
1124 m_banmanager->save();
1127 // Save changed parts of map
1128 m_env->getMap().save(MOD_STATE_WRITE_NEEDED);
1131 m_env->saveLoadedPlayers();
1133 // Save environment metadata
1139 void Server::Receive()
1141 DSTACK(__FUNCTION_NAME);
1142 SharedBuffer<u8> data;
1146 datasize = m_con.Receive(peer_id,data);
1147 ProcessData(*data, datasize, peer_id);
1149 catch(con::InvalidIncomingDataException &e)
1151 infostream<<"Server::Receive(): "
1152 "InvalidIncomingDataException: what()="
1153 <<e.what()<<std::endl;
1155 catch(SerializationError &e) {
1156 infostream<<"Server::Receive(): "
1157 "SerializationError: what()="
1158 <<e.what()<<std::endl;
1160 catch(ClientStateError &e)
1162 errorstream << "ProcessData: peer=" << peer_id << e.what() << std::endl;
1163 DenyAccess(peer_id, L"Your client sent something server didn't expect."
1164 L"Try reconnecting or updating your client");
1166 catch(con::PeerNotFoundException &e)
1172 PlayerSAO* Server::StageTwoClientInit(u16 peer_id)
1174 std::string playername = "";
1175 PlayerSAO *playersao = NULL;
1178 RemoteClient* client = m_clients.lockedGetClientNoEx(peer_id, CS_InitDone);
1179 if (client != NULL) {
1180 playername = client->getName();
1181 playersao = emergePlayer(playername.c_str(), peer_id);
1183 } catch (std::exception &e) {
1189 RemotePlayer *player =
1190 static_cast<RemotePlayer*>(m_env->getPlayer(playername.c_str()));
1192 // If failed, cancel
1193 if((playersao == NULL) || (player == NULL))
1195 if(player && player->peer_id != 0){
1196 errorstream<<"Server: "<<playername<<": Failed to emerge player"
1197 <<" (player allocated to an another client)"<<std::endl;
1198 DenyAccess(peer_id, L"Another client is connected with this "
1199 L"name. If your client closed unexpectedly, try again in "
1202 errorstream<<"Server: "<<playername<<": Failed to emerge player"
1204 DenyAccess(peer_id, L"Could not allocate player.");
1210 Send complete position information
1212 SendMovePlayer(peer_id);
1215 SendPlayerPrivileges(peer_id);
1217 // Send inventory formspec
1218 SendPlayerInventoryFormspec(peer_id);
1221 UpdateCrafting(peer_id);
1222 SendInventory(peer_id);
1225 if(g_settings->getBool("enable_damage"))
1226 SendPlayerHP(peer_id);
1229 SendPlayerBreath(peer_id);
1231 // Show death screen if necessary
1233 SendDeathscreen(peer_id, false, v3f(0,0,0));
1235 // Note things in chat if not in simple singleplayer mode
1236 if(!m_simple_singleplayer_mode)
1238 // Send information about server to player in chat
1239 SendChatMessage(peer_id, getStatusString());
1241 // Send information about joining in chat
1243 std::wstring name = L"unknown";
1244 Player *player = m_env->getPlayer(peer_id);
1246 name = narrow_to_wide(player->getName());
1248 std::wstring message;
1251 message += L" joined the game.";
1252 SendChatMessage(PEER_ID_INEXISTENT,message);
1255 Address addr = getPeerAddress(player->peer_id);
1256 std::string ip_str = addr.serializeString();
1257 actionstream<<player->getName() <<" [" << ip_str << "] joins game. " << std::endl;
1262 std::vector<std::string> names = m_clients.getPlayerNames();
1264 actionstream<<player->getName() <<" joins game. List of players: ";
1266 for (std::vector<std::string>::iterator i = names.begin();
1267 i != names.end(); i++)
1269 actionstream << *i << " ";
1272 actionstream << player->getName() <<std::endl;
1277 void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
1279 DSTACK(__FUNCTION_NAME);
1280 // Environment is locked first.
1281 JMutexAutoLock envlock(m_env_mutex);
1283 ScopeProfiler sp(g_profiler, "Server::ProcessData");
1287 Address address = getPeerAddress(peer_id);
1288 addr_s = address.serializeString();
1290 // drop player if is ip is banned
1291 if(m_banmanager->isIpBanned(addr_s)){
1292 std::string ban_name = m_banmanager->getBanName(addr_s);
1293 infostream<<"Server: A banned client tried to connect from "
1294 <<addr_s<<"; banned name was "
1295 <<ban_name<<std::endl;
1296 // This actually doesn't seem to transfer to the client
1297 DenyAccess(peer_id, L"Your ip is banned. Banned name was "
1298 +narrow_to_wide(ban_name));
1302 catch(con::PeerNotFoundException &e)
1305 * no peer for this packet found
1306 * most common reason is peer timeout, e.g. peer didn't
1307 * respond for some time, your server was overloaded or
1310 infostream<<"Server::ProcessData(): Cancelling: peer "
1311 <<peer_id<<" not found"<<std::endl;
1321 ToServerCommand command = (ToServerCommand)readU16(&data[0]);
1323 if(command == TOSERVER_INIT)
1325 // [0] u16 TOSERVER_INIT
1326 // [2] u8 SER_FMT_VER_HIGHEST_READ
1327 // [3] u8[20] player_name
1328 // [23] u8[28] password <--- can be sent without this, from old versions
1330 if(datasize < 2+1+PLAYERNAME_SIZE)
1333 RemoteClient* client = getClient(peer_id, CS_Created);
1335 // If net_proto_version is set, this client has already been handled
1336 if(client->getState() > CS_Created)
1338 verbosestream<<"Server: Ignoring multiple TOSERVER_INITs from "
1339 <<addr_s<<" (peer_id="<<peer_id<<")"<<std::endl;
1343 verbosestream<<"Server: Got TOSERVER_INIT from "<<addr_s<<" (peer_id="
1344 <<peer_id<<")"<<std::endl;
1346 // Do not allow multiple players in simple singleplayer mode.
1347 // This isn't a perfect way to do it, but will suffice for now
1348 if(m_simple_singleplayer_mode && m_clients.getClientIDs().size() > 1){
1349 infostream<<"Server: Not allowing another client ("<<addr_s
1350 <<") to connect in simple singleplayer mode"<<std::endl;
1351 DenyAccess(peer_id, L"Running in simple singleplayer mode.");
1355 // First byte after command is maximum supported
1356 // serialization version
1357 u8 client_max = data[2];
1358 u8 our_max = SER_FMT_VER_HIGHEST_READ;
1359 // Use the highest version supported by both
1360 int deployed = std::min(client_max, our_max);
1361 // If it's lower than the lowest supported, give up.
1362 if(deployed < SER_FMT_VER_LOWEST)
1363 deployed = SER_FMT_VER_INVALID;
1365 if(deployed == SER_FMT_VER_INVALID)
1367 actionstream<<"Server: A mismatched client tried to connect from "
1368 <<addr_s<<std::endl;
1369 infostream<<"Server: Cannot negotiate serialization version with "
1370 <<addr_s<<std::endl;
1371 DenyAccess(peer_id, std::wstring(
1372 L"Your client's version is not supported.\n"
1373 L"Server version is ")
1374 + narrow_to_wide(minetest_version_simple) + L"."
1379 client->setPendingSerializationVersion(deployed);
1382 Read and check network protocol version
1385 u16 min_net_proto_version = 0;
1386 if(datasize >= 2+1+PLAYERNAME_SIZE+PASSWORD_SIZE+2)
1387 min_net_proto_version = readU16(&data[2+1+PLAYERNAME_SIZE+PASSWORD_SIZE]);
1389 // Use same version as minimum and maximum if maximum version field
1390 // doesn't exist (backwards compatibility)
1391 u16 max_net_proto_version = min_net_proto_version;
1392 if(datasize >= 2+1+PLAYERNAME_SIZE+PASSWORD_SIZE+2+2)
1393 max_net_proto_version = readU16(&data[2+1+PLAYERNAME_SIZE+PASSWORD_SIZE+2]);
1395 // Start with client's maximum version
1396 u16 net_proto_version = max_net_proto_version;
1398 // Figure out a working version if it is possible at all
1399 if(max_net_proto_version >= SERVER_PROTOCOL_VERSION_MIN ||
1400 min_net_proto_version <= SERVER_PROTOCOL_VERSION_MAX)
1402 // If maximum is larger than our maximum, go with our maximum
1403 if(max_net_proto_version > SERVER_PROTOCOL_VERSION_MAX)
1404 net_proto_version = SERVER_PROTOCOL_VERSION_MAX;
1405 // Else go with client's maximum
1407 net_proto_version = max_net_proto_version;
1410 verbosestream<<"Server: "<<addr_s<<": Protocol version: min: "
1411 <<min_net_proto_version<<", max: "<<max_net_proto_version
1412 <<", chosen: "<<net_proto_version<<std::endl;
1414 client->net_proto_version = net_proto_version;
1416 if(net_proto_version < SERVER_PROTOCOL_VERSION_MIN ||
1417 net_proto_version > SERVER_PROTOCOL_VERSION_MAX)
1419 actionstream<<"Server: A mismatched client tried to connect from "
1420 <<addr_s<<std::endl;
1421 DenyAccess(peer_id, std::wstring(
1422 L"Your client's version is not supported.\n"
1423 L"Server version is ")
1424 + narrow_to_wide(minetest_version_simple) + L",\n"
1425 + L"server's PROTOCOL_VERSION is "
1426 + narrow_to_wide(itos(SERVER_PROTOCOL_VERSION_MIN))
1428 + narrow_to_wide(itos(SERVER_PROTOCOL_VERSION_MAX))
1429 + L", client's PROTOCOL_VERSION is "
1430 + narrow_to_wide(itos(min_net_proto_version))
1432 + narrow_to_wide(itos(max_net_proto_version))
1437 if(g_settings->getBool("strict_protocol_version_checking"))
1439 if(net_proto_version != LATEST_PROTOCOL_VERSION)
1441 actionstream<<"Server: A mismatched (strict) client tried to "
1442 <<"connect from "<<addr_s<<std::endl;
1443 DenyAccess(peer_id, std::wstring(
1444 L"Your client's version is not supported.\n"
1445 L"Server version is ")
1446 + narrow_to_wide(minetest_version_simple) + L",\n"
1447 + L"server's PROTOCOL_VERSION (strict) is "
1448 + narrow_to_wide(itos(LATEST_PROTOCOL_VERSION))
1449 + L", client's PROTOCOL_VERSION is "
1450 + narrow_to_wide(itos(min_net_proto_version))
1452 + narrow_to_wide(itos(max_net_proto_version))
1461 char playername[PLAYERNAME_SIZE];
1462 unsigned int playername_length = 0;
1463 for (; playername_length < PLAYERNAME_SIZE; playername_length++ ) {
1464 playername[playername_length] = data[3+playername_length];
1465 if (data[3+playername_length] == 0)
1469 if (playername_length == PLAYERNAME_SIZE) {
1470 actionstream<<"Server: Player with name exceeding max length "
1471 <<"tried to connect from "<<addr_s<<std::endl;
1472 DenyAccess(peer_id, L"Name too long");
1477 if(playername[0]=='\0')
1479 actionstream<<"Server: Player with an empty name "
1480 <<"tried to connect from "<<addr_s<<std::endl;
1481 DenyAccess(peer_id, L"Empty name");
1485 if(string_allowed(playername, PLAYERNAME_ALLOWED_CHARS)==false)
1487 actionstream<<"Server: Player with an invalid name "
1488 <<"tried to connect from "<<addr_s<<std::endl;
1489 DenyAccess(peer_id, L"Name contains unallowed characters");
1493 if(!isSingleplayer() && strcasecmp(playername, "singleplayer") == 0)
1495 actionstream<<"Server: Player with the name \"singleplayer\" "
1496 <<"tried to connect from "<<addr_s<<std::endl;
1497 DenyAccess(peer_id, L"Name is not allowed");
1503 if(m_script->on_prejoinplayer(playername, addr_s, reason))
1505 actionstream<<"Server: Player with the name \""<<playername<<"\" "
1506 <<"tried to connect from "<<addr_s<<" "
1507 <<"but it was disallowed for the following reason: "
1508 <<reason<<std::endl;
1509 DenyAccess(peer_id, narrow_to_wide(reason.c_str()));
1514 infostream<<"Server: New connection: \""<<playername<<"\" from "
1515 <<addr_s<<" (peer_id="<<peer_id<<")"<<std::endl;
1518 char given_password[PASSWORD_SIZE];
1519 if(datasize < 2+1+PLAYERNAME_SIZE+PASSWORD_SIZE)
1521 // old version - assume blank password
1522 given_password[0] = 0;
1526 for(u32 i=0; i<PASSWORD_SIZE-1; i++)
1528 given_password[i] = data[23+i];
1530 given_password[PASSWORD_SIZE-1] = 0;
1533 if(!base64_is_valid(given_password)){
1534 actionstream<<"Server: "<<playername
1535 <<" supplied invalid password hash"<<std::endl;
1536 DenyAccess(peer_id, L"Invalid password hash");
1540 // Enforce user limit.
1541 // Don't enforce for users that have some admin right
1542 if(m_clients.getClientIDs(CS_Created).size() >= g_settings->getU16("max_users") &&
1543 !checkPriv(playername, "server") &&
1544 !checkPriv(playername, "ban") &&
1545 !checkPriv(playername, "privs") &&
1546 !checkPriv(playername, "password") &&
1547 playername != g_settings->get("name"))
1549 actionstream<<"Server: "<<playername<<" tried to join, but there"
1550 <<" are already max_users="
1551 <<g_settings->getU16("max_users")<<" players."<<std::endl;
1552 DenyAccess(peer_id, L"Too many users.");
1556 std::string checkpwd; // Password hash to check against
1557 bool has_auth = m_script->getAuth(playername, &checkpwd, NULL);
1559 // If no authentication info exists for user, create it
1561 if(!isSingleplayer() &&
1562 g_settings->getBool("disallow_empty_password") &&
1563 std::string(given_password) == ""){
1564 actionstream<<"Server: "<<playername
1565 <<" supplied empty password"<<std::endl;
1566 DenyAccess(peer_id, L"Empty passwords are "
1567 L"disallowed. Set a password and try again.");
1570 std::wstring raw_default_password =
1571 narrow_to_wide(g_settings->get("default_password"));
1572 std::string initial_password =
1573 translatePassword(playername, raw_default_password);
1575 // If default_password is empty, allow any initial password
1576 if (raw_default_password.length() == 0)
1577 initial_password = given_password;
1579 m_script->createAuth(playername, initial_password);
1582 has_auth = m_script->getAuth(playername, &checkpwd, NULL);
1585 actionstream<<"Server: "<<playername<<" cannot be authenticated"
1586 <<" (auth handler does not work?)"<<std::endl;
1587 DenyAccess(peer_id, L"Not allowed to login");
1591 if(given_password != checkpwd){
1592 actionstream<<"Server: "<<playername<<" supplied wrong password"
1594 DenyAccess(peer_id, L"Wrong password");
1598 RemotePlayer *player =
1599 static_cast<RemotePlayer*>(m_env->getPlayer(playername));
1601 if(player && player->peer_id != 0){
1602 errorstream<<"Server: "<<playername<<": Failed to emerge player"
1603 <<" (player allocated to an another client)"<<std::endl;
1604 DenyAccess(peer_id, L"Another client is connected with this "
1605 L"name. If your client closed unexpectedly, try again in "
1609 m_clients.setPlayerName(peer_id,playername);
1612 Answer with a TOCLIENT_INIT
1615 SharedBuffer<u8> reply(2+1+6+8+4);
1616 writeU16(&reply[0], TOCLIENT_INIT);
1617 writeU8(&reply[2], deployed);
1618 //send dummy pos for legacy reasons only
1619 writeV3S16(&reply[2+1], floatToInt(v3f(0,0,0), BS));
1620 writeU64(&reply[2+1+6], m_env->getServerMap().getSeed());
1621 writeF1000(&reply[2+1+6+8], g_settings->getFloat("dedicated_server_step"));
1624 m_clients.send(peer_id, 0, reply, true);
1625 m_clients.event(peer_id, CSE_Init);
1631 if(command == TOSERVER_INIT2)
1634 verbosestream<<"Server: Got TOSERVER_INIT2 from "
1635 <<peer_id<<std::endl;
1637 m_clients.event(peer_id, CSE_GotInit2);
1638 u16 protocol_version = m_clients.getProtocolVersion(peer_id);
1641 ///// begin compatibility code
1642 PlayerSAO* playersao = NULL;
1643 if (protocol_version <= 22) {
1644 playersao = StageTwoClientInit(peer_id);
1646 if (playersao == NULL) {
1648 << "TOSERVER_INIT2 stage 2 client init failed for peer "
1649 << peer_id << std::endl;
1653 ///// end compatibility code
1656 Send some initialization data
1659 infostream<<"Server: Sending content to "
1660 <<getPlayerName(peer_id)<<std::endl;
1662 // Send player movement settings
1663 SendMovement(peer_id);
1665 // Send item definitions
1666 SendItemDef(peer_id, m_itemdef, protocol_version);
1668 // Send node definitions
1669 SendNodeDef(peer_id, m_nodedef, protocol_version);
1671 m_clients.event(peer_id, CSE_SetDefinitionsSent);
1673 // Send media announcement
1674 sendMediaAnnouncement(peer_id);
1676 // Send detached inventories
1677 sendDetachedInventories(peer_id);
1680 u16 time = m_env->getTimeOfDay();
1681 float time_speed = g_settings->getFloat("time_speed");
1682 SendTimeOfDay(peer_id, time, time_speed);
1684 ///// begin compatibility code
1685 if (protocol_version <= 22) {
1686 m_clients.event(peer_id, CSE_SetClientReady);
1687 m_script->on_joinplayer(playersao);
1689 ///// end compatibility code
1691 // Warnings about protocol version can be issued here
1692 if(getClient(peer_id)->net_proto_version < LATEST_PROTOCOL_VERSION)
1694 SendChatMessage(peer_id, L"# Server: WARNING: YOUR CLIENT'S "
1695 L"VERSION MAY NOT BE FULLY COMPATIBLE WITH THIS SERVER!");
1701 u8 peer_ser_ver = getClient(peer_id, CS_InitDone)->serialization_version;
1702 u16 peer_proto_ver = getClient(peer_id, CS_InitDone)->net_proto_version;
1704 if(peer_ser_ver == SER_FMT_VER_INVALID)
1706 errorstream<<"Server::ProcessData(): Cancelling: Peer"
1707 " serialization format invalid or not initialized."
1708 " Skipping incoming command="<<command<<std::endl;
1712 /* Handle commands relate to client startup */
1713 if(command == TOSERVER_REQUEST_MEDIA) {
1714 std::string datastring((char*)&data[2], datasize-2);
1715 std::istringstream is(datastring, std::ios_base::binary);
1717 std::list<std::string> tosend;
1718 u16 numfiles = readU16(is);
1720 infostream<<"Sending "<<numfiles<<" files to "
1721 <<getPlayerName(peer_id)<<std::endl;
1722 verbosestream<<"TOSERVER_REQUEST_MEDIA: "<<std::endl;
1724 for(int i = 0; i < numfiles; i++) {
1725 std::string name = deSerializeString(is);
1726 tosend.push_back(name);
1727 verbosestream<<"TOSERVER_REQUEST_MEDIA: requested file "
1731 sendRequestedMedia(peer_id, tosend);
1734 else if(command == TOSERVER_RECEIVED_MEDIA) {
1737 else if(command == TOSERVER_CLIENT_READY) {
1738 // clients <= protocol version 22 did not send ready message,
1739 // they're already initialized
1740 if (peer_proto_ver <= 22) {
1741 infostream << "Client sent message not expected by a "
1742 << "client using protocol version <= 22,"
1743 << "disconnecing peer_id: " << peer_id << std::endl;
1744 m_con.DisconnectPeer(peer_id);
1748 PlayerSAO* playersao = StageTwoClientInit(peer_id);
1750 if (playersao == NULL) {
1752 << "TOSERVER_CLIENT_READY stage 2 client init failed for peer_id: "
1753 << peer_id << std::endl;
1754 m_con.DisconnectPeer(peer_id);
1759 if(datasize < 2+8) {
1761 << "TOSERVER_CLIENT_READY client sent inconsistent data, disconnecting peer_id: "
1762 << peer_id << std::endl;
1763 m_con.DisconnectPeer(peer_id);
1767 m_clients.setClientVersion(
1769 data[2], data[3], data[4],
1770 std::string((char*) &data[8],(u16) data[6]));
1772 m_clients.event(peer_id, CSE_SetClientReady);
1773 m_script->on_joinplayer(playersao);
1776 else if(command == TOSERVER_GOTBLOCKS)
1789 u16 count = data[2];
1790 for(u16 i=0; i<count; i++)
1792 if((s16)datasize < 2+1+(i+1)*6)
1793 throw con::InvalidIncomingDataException
1794 ("GOTBLOCKS length is too short");
1795 v3s16 p = readV3S16(&data[2+1+i*6]);
1796 /*infostream<<"Server: GOTBLOCKS ("
1797 <<p.X<<","<<p.Y<<","<<p.Z<<")"<<std::endl;*/
1798 RemoteClient *client = getClient(peer_id);
1799 client->GotBlock(p);
1804 if (m_clients.getClientState(peer_id) < CS_Active)
1806 if (command == TOSERVER_PLAYERPOS) return;
1808 errorstream<<"Got packet command: " << command << " for peer id "
1809 << peer_id << " but client isn't active yet. Dropping packet "
1814 Player *player = m_env->getPlayer(peer_id);
1815 if(player == NULL) {
1816 errorstream<<"Server::ProcessData(): Cancelling: "
1817 "No player for peer_id="<<peer_id
1818 << " disconnecting peer!" <<std::endl;
1819 m_con.DisconnectPeer(peer_id);
1823 PlayerSAO *playersao = player->getPlayerSAO();
1824 if(playersao == NULL) {
1825 errorstream<<"Server::ProcessData(): Cancelling: "
1826 "No player object for peer_id="<<peer_id
1827 << " disconnecting peer!" <<std::endl;
1828 m_con.DisconnectPeer(peer_id);
1832 if(command == TOSERVER_PLAYERPOS)
1834 if(datasize < 2+12+12+4+4)
1838 v3s32 ps = readV3S32(&data[start+2]);
1839 v3s32 ss = readV3S32(&data[start+2+12]);
1840 f32 pitch = (f32)readS32(&data[2+12+12]) / 100.0;
1841 f32 yaw = (f32)readS32(&data[2+12+12+4]) / 100.0;
1843 if(datasize >= 2+12+12+4+4+4)
1844 keyPressed = (u32)readU32(&data[2+12+12+4+4]);
1845 v3f position((f32)ps.X/100., (f32)ps.Y/100., (f32)ps.Z/100.);
1846 v3f speed((f32)ss.X/100., (f32)ss.Y/100., (f32)ss.Z/100.);
1847 pitch = wrapDegrees(pitch);
1848 yaw = wrapDegrees(yaw);
1850 player->setPosition(position);
1851 player->setSpeed(speed);
1852 player->setPitch(pitch);
1853 player->setYaw(yaw);
1854 player->keyPressed=keyPressed;
1855 player->control.up = (bool)(keyPressed&1);
1856 player->control.down = (bool)(keyPressed&2);
1857 player->control.left = (bool)(keyPressed&4);
1858 player->control.right = (bool)(keyPressed&8);
1859 player->control.jump = (bool)(keyPressed&16);
1860 player->control.aux1 = (bool)(keyPressed&32);
1861 player->control.sneak = (bool)(keyPressed&64);
1862 player->control.LMB = (bool)(keyPressed&128);
1863 player->control.RMB = (bool)(keyPressed&256);
1865 bool cheated = playersao->checkMovementCheat();
1868 m_script->on_cheat(playersao, "moved_too_fast");
1871 /*infostream<<"Server::ProcessData(): Moved player "<<peer_id<<" to "
1872 <<"("<<position.X<<","<<position.Y<<","<<position.Z<<")"
1873 <<" pitch="<<pitch<<" yaw="<<yaw<<std::endl;*/
1875 else if(command == TOSERVER_DELETEDBLOCKS)
1888 u16 count = data[2];
1889 for(u16 i=0; i<count; i++)
1891 if((s16)datasize < 2+1+(i+1)*6)
1892 throw con::InvalidIncomingDataException
1893 ("DELETEDBLOCKS length is too short");
1894 v3s16 p = readV3S16(&data[2+1+i*6]);
1895 /*infostream<<"Server: DELETEDBLOCKS ("
1896 <<p.X<<","<<p.Y<<","<<p.Z<<")"<<std::endl;*/
1897 RemoteClient *client = getClient(peer_id);
1898 client->SetBlockNotSent(p);
1901 else if(command == TOSERVER_CLICK_OBJECT)
1903 infostream<<"Server: CLICK_OBJECT not supported anymore"<<std::endl;
1906 else if(command == TOSERVER_CLICK_ACTIVEOBJECT)
1908 infostream<<"Server: CLICK_ACTIVEOBJECT not supported anymore"<<std::endl;
1911 else if(command == TOSERVER_GROUND_ACTION)
1913 infostream<<"Server: GROUND_ACTION not supported anymore"<<std::endl;
1917 else if(command == TOSERVER_RELEASE)
1919 infostream<<"Server: RELEASE not supported anymore"<<std::endl;
1922 else if(command == TOSERVER_SIGNTEXT)
1924 infostream<<"Server: SIGNTEXT not supported anymore"
1928 else if(command == TOSERVER_SIGNNODETEXT)
1930 infostream<<"Server: SIGNNODETEXT not supported anymore"
1934 else if(command == TOSERVER_INVENTORY_ACTION)
1936 // Strip command and create a stream
1937 std::string datastring((char*)&data[2], datasize-2);
1938 verbosestream<<"TOSERVER_INVENTORY_ACTION: data="<<datastring<<std::endl;
1939 std::istringstream is(datastring, std::ios_base::binary);
1941 InventoryAction *a = InventoryAction::deSerialize(is);
1944 infostream<<"TOSERVER_INVENTORY_ACTION: "
1945 <<"InventoryAction::deSerialize() returned NULL"
1950 // If something goes wrong, this player is to blame
1951 RollbackScopeActor rollback_scope(m_rollback,
1952 std::string("player:")+player->getName());
1955 Note: Always set inventory not sent, to repair cases
1956 where the client made a bad prediction.
1960 Handle restrictions and special cases of the move action
1962 if(a->getType() == IACTION_MOVE)
1964 IMoveAction *ma = (IMoveAction*)a;
1966 ma->from_inv.applyCurrentPlayer(player->getName());
1967 ma->to_inv.applyCurrentPlayer(player->getName());
1969 setInventoryModified(ma->from_inv);
1970 setInventoryModified(ma->to_inv);
1972 bool from_inv_is_current_player =
1973 (ma->from_inv.type == InventoryLocation::PLAYER) &&
1974 (ma->from_inv.name == player->getName());
1976 bool to_inv_is_current_player =
1977 (ma->to_inv.type == InventoryLocation::PLAYER) &&
1978 (ma->to_inv.name == player->getName());
1981 Disable moving items out of craftpreview
1983 if(ma->from_list == "craftpreview")
1985 infostream<<"Ignoring IMoveAction from "
1986 <<(ma->from_inv.dump())<<":"<<ma->from_list
1987 <<" to "<<(ma->to_inv.dump())<<":"<<ma->to_list
1988 <<" because src is "<<ma->from_list<<std::endl;
1994 Disable moving items into craftresult and craftpreview
1996 if(ma->to_list == "craftpreview" || ma->to_list == "craftresult")
1998 infostream<<"Ignoring IMoveAction from "
1999 <<(ma->from_inv.dump())<<":"<<ma->from_list
2000 <<" to "<<(ma->to_inv.dump())<<":"<<ma->to_list
2001 <<" because dst is "<<ma->to_list<<std::endl;
2006 // Disallow moving items in elsewhere than player's inventory
2007 // if not allowed to interact
2008 if(!checkPriv(player->getName(), "interact") &&
2009 (!from_inv_is_current_player ||
2010 !to_inv_is_current_player))
2012 infostream<<"Cannot move outside of player's inventory: "
2013 <<"No interact privilege"<<std::endl;
2019 Handle restrictions and special cases of the drop action
2021 else if(a->getType() == IACTION_DROP)
2023 IDropAction *da = (IDropAction*)a;
2025 da->from_inv.applyCurrentPlayer(player->getName());
2027 setInventoryModified(da->from_inv);
2030 Disable dropping items out of craftpreview
2032 if(da->from_list == "craftpreview")
2034 infostream<<"Ignoring IDropAction from "
2035 <<(da->from_inv.dump())<<":"<<da->from_list
2036 <<" because src is "<<da->from_list<<std::endl;
2041 // Disallow dropping items if not allowed to interact
2042 if(!checkPriv(player->getName(), "interact"))
2049 Handle restrictions and special cases of the craft action
2051 else if(a->getType() == IACTION_CRAFT)
2053 ICraftAction *ca = (ICraftAction*)a;
2055 ca->craft_inv.applyCurrentPlayer(player->getName());
2057 setInventoryModified(ca->craft_inv);
2059 //bool craft_inv_is_current_player =
2060 // (ca->craft_inv.type == InventoryLocation::PLAYER) &&
2061 // (ca->craft_inv.name == player->getName());
2063 // Disallow crafting if not allowed to interact
2064 if(!checkPriv(player->getName(), "interact"))
2066 infostream<<"Cannot craft: "
2067 <<"No interact privilege"<<std::endl;
2074 a->apply(this, playersao, this);
2078 else if(command == TOSERVER_CHAT_MESSAGE)
2086 std::string datastring((char*)&data[2], datasize-2);
2087 std::istringstream is(datastring, std::ios_base::binary);
2090 is.read((char*)buf, 2);
2091 u16 len = readU16(buf);
2093 std::wstring message;
2094 for(u16 i=0; i<len; i++)
2096 is.read((char*)buf, 2);
2097 message += (wchar_t)readU16(buf);
2100 // If something goes wrong, this player is to blame
2101 RollbackScopeActor rollback_scope(m_rollback,
2102 std::string("player:")+player->getName());
2104 // Get player name of this client
2105 std::wstring name = narrow_to_wide(player->getName());
2108 bool ate = m_script->on_chat_message(player->getName(),
2109 wide_to_narrow(message));
2110 // If script ate the message, don't proceed
2114 // Line to send to players
2116 // Whether to send to the player that sent the line
2117 bool send_to_sender_only = false;
2119 // Commands are implemented in Lua, so only catch invalid
2120 // commands that were not "eaten" and send an error back
2121 if(message[0] == L'/')
2123 message = message.substr(1);
2124 send_to_sender_only = true;
2125 if(message.length() == 0)
2126 line += L"-!- Empty command";
2128 line += L"-!- Invalid command: " + str_split(message, L' ')[0];
2132 if(checkPriv(player->getName(), "shout")){
2138 line += L"-!- You don't have permission to shout.";
2139 send_to_sender_only = true;
2146 Send the message to sender
2148 if (send_to_sender_only)
2150 SendChatMessage(peer_id, line);
2153 Send the message to others
2157 actionstream<<"CHAT: "<<wide_to_narrow(line)<<std::endl;
2159 std::list<u16> clients = m_clients.getClientIDs();
2161 for(std::list<u16>::iterator
2162 i = clients.begin();
2163 i != clients.end(); ++i)
2166 SendChatMessage(*i, line);
2171 else if(command == TOSERVER_DAMAGE)
2173 std::string datastring((char*)&data[2], datasize-2);
2174 std::istringstream is(datastring, std::ios_base::binary);
2175 u8 damage = readU8(is);
2177 if(g_settings->getBool("enable_damage"))
2179 actionstream<<player->getName()<<" damaged by "
2180 <<(int)damage<<" hp at "<<PP(player->getPosition()/BS)
2183 playersao->setHP(playersao->getHP() - damage);
2185 if(playersao->getHP() == 0 && playersao->m_hp_not_sent)
2188 if(playersao->m_hp_not_sent)
2189 SendPlayerHP(peer_id);
2192 else if(command == TOSERVER_BREATH)
2194 std::string datastring((char*)&data[2], datasize-2);
2195 std::istringstream is(datastring, std::ios_base::binary);
2196 u16 breath = readU16(is);
2197 playersao->setBreath(breath);
2198 m_script->player_event(playersao,"breath_changed");
2200 else if(command == TOSERVER_PASSWORD)
2203 [0] u16 TOSERVER_PASSWORD
2204 [2] u8[28] old password
2205 [30] u8[28] new password
2208 if(datasize != 2+PASSWORD_SIZE*2)
2210 /*char password[PASSWORD_SIZE];
2211 for(u32 i=0; i<PASSWORD_SIZE-1; i++)
2212 password[i] = data[2+i];
2213 password[PASSWORD_SIZE-1] = 0;*/
2215 for(u32 i=0; i<PASSWORD_SIZE-1; i++)
2223 for(u32 i=0; i<PASSWORD_SIZE-1; i++)
2225 char c = data[2+PASSWORD_SIZE+i];
2231 if(!base64_is_valid(newpwd)){
2232 infostream<<"Server: "<<player->getName()<<" supplied invalid password hash"<<std::endl;
2233 // Wrong old password supplied!!
2234 SendChatMessage(peer_id, L"Invalid new password hash supplied. Password NOT changed.");
2238 infostream<<"Server: Client requests a password change from "
2239 <<"'"<<oldpwd<<"' to '"<<newpwd<<"'"<<std::endl;
2241 std::string playername = player->getName();
2243 std::string checkpwd;
2244 m_script->getAuth(playername, &checkpwd, NULL);
2246 if(oldpwd != checkpwd)
2248 infostream<<"Server: invalid old password"<<std::endl;
2249 // Wrong old password supplied!!
2250 SendChatMessage(peer_id, L"Invalid old password supplied. Password NOT changed.");
2254 bool success = m_script->setPassword(playername, newpwd);
2256 actionstream<<player->getName()<<" changes password"<<std::endl;
2257 SendChatMessage(peer_id, L"Password change successful.");
2259 actionstream<<player->getName()<<" tries to change password but "
2260 <<"it fails"<<std::endl;
2261 SendChatMessage(peer_id, L"Password change failed or inavailable.");
2264 else if(command == TOSERVER_PLAYERITEM)
2269 u16 item = readU16(&data[2]);
2270 playersao->setWieldIndex(item);
2272 else if(command == TOSERVER_RESPAWN)
2274 if(player->hp != 0 || !g_settings->getBool("enable_damage"))
2277 RespawnPlayer(peer_id);
2279 actionstream<<player->getName()<<" respawns at "
2280 <<PP(player->getPosition()/BS)<<std::endl;
2282 // ActiveObject is added to environment in AsyncRunStep after
2283 // the previous addition has been succesfully removed
2285 else if(command == TOSERVER_INTERACT)
2287 std::string datastring((char*)&data[2], datasize-2);
2288 std::istringstream is(datastring, std::ios_base::binary);
2294 [5] u32 length of the next item
2295 [9] serialized PointedThing
2297 0: start digging (from undersurface) or use
2298 1: stop digging (all parameters ignored)
2299 2: digging completed
2300 3: place block or item (to abovesurface)
2303 u8 action = readU8(is);
2304 u16 item_i = readU16(is);
2305 std::istringstream tmp_is(deSerializeLongString(is), std::ios::binary);
2306 PointedThing pointed;
2307 pointed.deSerialize(tmp_is);
2309 verbosestream<<"TOSERVER_INTERACT: action="<<(int)action<<", item="
2310 <<item_i<<", pointed="<<pointed.dump()<<std::endl;
2314 verbosestream<<"TOSERVER_INTERACT: "<<player->getName()
2315 <<" tried to interact, but is dead!"<<std::endl;
2319 v3f player_pos = playersao->getLastGoodPosition();
2321 // Update wielded item
2322 playersao->setWieldIndex(item_i);
2324 // Get pointed to node (undefined if not POINTEDTYPE_NODE)
2325 v3s16 p_under = pointed.node_undersurface;
2326 v3s16 p_above = pointed.node_abovesurface;
2328 // Get pointed to object (NULL if not POINTEDTYPE_OBJECT)
2329 ServerActiveObject *pointed_object = NULL;
2330 if(pointed.type == POINTEDTHING_OBJECT)
2332 pointed_object = m_env->getActiveObject(pointed.object_id);
2333 if(pointed_object == NULL)
2335 verbosestream<<"TOSERVER_INTERACT: "
2336 "pointed object is NULL"<<std::endl;
2342 v3f pointed_pos_under = player_pos;
2343 v3f pointed_pos_above = player_pos;
2344 if(pointed.type == POINTEDTHING_NODE)
2346 pointed_pos_under = intToFloat(p_under, BS);
2347 pointed_pos_above = intToFloat(p_above, BS);
2349 else if(pointed.type == POINTEDTHING_OBJECT)
2351 pointed_pos_under = pointed_object->getBasePosition();
2352 pointed_pos_above = pointed_pos_under;
2356 Check that target is reasonably close
2357 (only when digging or placing things)
2359 if(action == 0 || action == 2 || action == 3)
2361 float d = player_pos.getDistanceFrom(pointed_pos_under);
2362 float max_d = BS * 14; // Just some large enough value
2364 actionstream<<"Player "<<player->getName()
2365 <<" tried to access "<<pointed.dump()
2367 <<"d="<<d<<", max_d="<<max_d
2368 <<". ignoring."<<std::endl;
2369 // Re-send block to revert change on client-side
2370 RemoteClient *client = getClient(peer_id);
2371 v3s16 blockpos = getNodeBlockPos(floatToInt(pointed_pos_under, BS));
2372 client->SetBlockNotSent(blockpos);
2374 m_script->on_cheat(playersao, "interacted_too_far");
2381 Make sure the player is allowed to do it
2383 if(!checkPriv(player->getName(), "interact"))
2385 actionstream<<player->getName()<<" attempted to interact with "
2386 <<pointed.dump()<<" without 'interact' privilege"
2388 // Re-send block to revert change on client-side
2389 RemoteClient *client = getClient(peer_id);
2390 // Digging completed -> under
2392 v3s16 blockpos = getNodeBlockPos(floatToInt(pointed_pos_under, BS));
2393 client->SetBlockNotSent(blockpos);
2395 // Placement -> above
2397 v3s16 blockpos = getNodeBlockPos(floatToInt(pointed_pos_above, BS));
2398 client->SetBlockNotSent(blockpos);
2404 If something goes wrong, this player is to blame
2406 RollbackScopeActor rollback_scope(m_rollback,
2407 std::string("player:")+player->getName());
2410 0: start digging or punch object
2414 if(pointed.type == POINTEDTHING_NODE)
2417 NOTE: This can be used in the future to check if
2418 somebody is cheating, by checking the timing.
2420 MapNode n(CONTENT_IGNORE);
2422 n = m_env->getMap().getNodeNoEx(p_under, &pos_ok);
2424 n = m_env->getMap().getNodeNoEx(p_under, &pos_ok);
2427 infostream<<"Server: Not punching: Node not found."
2428 <<" Adding block to emerge queue."
2430 m_emerge->enqueueBlockEmerge(peer_id, getNodeBlockPos(p_above), false);
2433 if(n.getContent() != CONTENT_IGNORE)
2434 m_script->node_on_punch(p_under, n, playersao, pointed);
2436 playersao->noCheatDigStart(p_under);
2438 else if(pointed.type == POINTEDTHING_OBJECT)
2440 // Skip if object has been removed
2441 if(pointed_object->m_removed)
2444 actionstream<<player->getName()<<" punches object "
2445 <<pointed.object_id<<": "
2446 <<pointed_object->getDescription()<<std::endl;
2448 ItemStack punchitem = playersao->getWieldedItem();
2449 ToolCapabilities toolcap =
2450 punchitem.getToolCapabilities(m_itemdef);
2451 v3f dir = (pointed_object->getBasePosition() -
2452 (player->getPosition() + player->getEyeOffset())
2454 float time_from_last_punch =
2455 playersao->resetTimeFromLastPunch();
2456 pointed_object->punch(dir, &toolcap, playersao,
2457 time_from_last_punch);
2465 else if(action == 1)
2470 2: Digging completed
2472 else if(action == 2)
2474 // Only digging of nodes
2475 if(pointed.type == POINTEDTHING_NODE)
2478 MapNode n = m_env->getMap().getNodeNoEx(p_under, &pos_ok);
2480 infostream << "Server: Not finishing digging: Node not found."
2481 << " Adding block to emerge queue."
2483 m_emerge->enqueueBlockEmerge(peer_id, getNodeBlockPos(p_above), false);
2486 /* Cheat prevention */
2487 bool is_valid_dig = true;
2488 if(!isSingleplayer() && !g_settings->getBool("disable_anticheat"))
2490 v3s16 nocheat_p = playersao->getNoCheatDigPos();
2491 float nocheat_t = playersao->getNoCheatDigTime();
2492 playersao->noCheatDigEnd();
2493 // If player didn't start digging this, ignore dig
2494 if(nocheat_p != p_under){
2495 infostream<<"Server: NoCheat: "<<player->getName()
2496 <<" started digging "
2497 <<PP(nocheat_p)<<" and completed digging "
2498 <<PP(p_under)<<"; not digging."<<std::endl;
2499 is_valid_dig = false;
2501 m_script->on_cheat(playersao, "finished_unknown_dig");
2503 // Get player's wielded item
2504 ItemStack playeritem;
2505 InventoryList *mlist = playersao->getInventory()->getList("main");
2507 playeritem = mlist->getItem(playersao->getWieldIndex());
2508 ToolCapabilities playeritem_toolcap =
2509 playeritem.getToolCapabilities(m_itemdef);
2510 // Get diggability and expected digging time
2511 DigParams params = getDigParams(m_nodedef->get(n).groups,
2512 &playeritem_toolcap);
2513 // If can't dig, try hand
2514 if(!params.diggable){
2515 const ItemDefinition &hand = m_itemdef->get("");
2516 const ToolCapabilities *tp = hand.tool_capabilities;
2518 params = getDigParams(m_nodedef->get(n).groups, tp);
2520 // If can't dig, ignore dig
2521 if(!params.diggable){
2522 infostream<<"Server: NoCheat: "<<player->getName()
2523 <<" completed digging "<<PP(p_under)
2524 <<", which is not diggable with tool. not digging."
2526 is_valid_dig = false;
2528 m_script->on_cheat(playersao, "dug_unbreakable");
2530 // Check digging time
2531 // If already invalidated, we don't have to
2533 // Well not our problem then
2535 // Clean and long dig
2536 else if(params.time > 2.0 && nocheat_t * 1.2 > params.time){
2537 // All is good, but grab time from pool; don't care if
2538 // it's actually available
2539 playersao->getDigPool().grab(params.time);
2541 // Short or laggy dig
2542 // Try getting the time from pool
2543 else if(playersao->getDigPool().grab(params.time)){
2548 infostream<<"Server: NoCheat: "<<player->getName()
2549 <<" completed digging "<<PP(p_under)
2550 <<"too fast; not digging."<<std::endl;
2551 is_valid_dig = false;
2553 m_script->on_cheat(playersao, "dug_too_fast");
2557 /* Actually dig node */
2559 if(is_valid_dig && n.getContent() != CONTENT_IGNORE)
2560 m_script->node_on_dig(p_under, n, playersao);
2562 v3s16 blockpos = getNodeBlockPos(floatToInt(pointed_pos_under, BS));
2563 RemoteClient *client = getClient(peer_id);
2564 // Send unusual result (that is, node not being removed)
2565 if(m_env->getMap().getNodeNoEx(p_under).getContent() != CONTENT_AIR)
2567 // Re-send block to revert change on client-side
2568 client->SetBlockNotSent(blockpos);
2571 client->ResendBlockIfOnWire(blockpos);
2577 3: place block or right-click object
2579 else if(action == 3)
2581 ItemStack item = playersao->getWieldedItem();
2583 // Reset build time counter
2584 if(pointed.type == POINTEDTHING_NODE &&
2585 item.getDefinition(m_itemdef).type == ITEM_NODE)
2586 getClient(peer_id)->m_time_from_building = 0.0;
2588 if(pointed.type == POINTEDTHING_OBJECT)
2590 // Right click object
2592 // Skip if object has been removed
2593 if(pointed_object->m_removed)
2596 actionstream<<player->getName()<<" right-clicks object "
2597 <<pointed.object_id<<": "
2598 <<pointed_object->getDescription()<<std::endl;
2601 pointed_object->rightClick(playersao);
2603 else if(m_script->item_OnPlace(
2604 item, playersao, pointed))
2606 // Placement was handled in lua
2608 // Apply returned ItemStack
2609 playersao->setWieldedItem(item);
2612 // If item has node placement prediction, always send the
2613 // blocks to make sure the client knows what exactly happened
2614 RemoteClient *client = getClient(peer_id);
2615 v3s16 blockpos = getNodeBlockPos(floatToInt(pointed_pos_above, BS));
2616 v3s16 blockpos2 = getNodeBlockPos(floatToInt(pointed_pos_under, BS));
2617 if(item.getDefinition(m_itemdef).node_placement_prediction != "") {
2618 client->SetBlockNotSent(blockpos);
2619 if(blockpos2 != blockpos) {
2620 client->SetBlockNotSent(blockpos2);
2624 client->ResendBlockIfOnWire(blockpos);
2625 if(blockpos2 != blockpos) {
2626 client->ResendBlockIfOnWire(blockpos2);
2634 else if(action == 4)
2636 ItemStack item = playersao->getWieldedItem();
2638 actionstream<<player->getName()<<" uses "<<item.name
2639 <<", pointing at "<<pointed.dump()<<std::endl;
2641 if(m_script->item_OnUse(
2642 item, playersao, pointed))
2644 // Apply returned ItemStack
2645 playersao->setWieldedItem(item);
2652 Catch invalid actions
2656 infostream<<"WARNING: Server: Invalid action "
2657 <<action<<std::endl;
2660 else if(command == TOSERVER_REMOVED_SOUNDS)
2662 std::string datastring((char*)&data[2], datasize-2);
2663 std::istringstream is(datastring, std::ios_base::binary);
2665 int num = readU16(is);
2666 for(int k=0; k<num; k++){
2667 s32 id = readS32(is);
2668 std::map<s32, ServerPlayingSound>::iterator i =
2669 m_playing_sounds.find(id);
2670 if(i == m_playing_sounds.end())
2672 ServerPlayingSound &psound = i->second;
2673 psound.clients.erase(peer_id);
2674 if(psound.clients.empty())
2675 m_playing_sounds.erase(i++);
2678 else if(command == TOSERVER_NODEMETA_FIELDS)
2680 std::string datastring((char*)&data[2], datasize-2);
2681 std::istringstream is(datastring, std::ios_base::binary);
2683 v3s16 p = readV3S16(is);
2684 std::string formname = deSerializeString(is);
2685 int num = readU16(is);
2686 std::map<std::string, std::string> fields;
2687 for(int k=0; k<num; k++){
2688 std::string fieldname = deSerializeString(is);
2689 std::string fieldvalue = deSerializeLongString(is);
2690 fields[fieldname] = fieldvalue;
2693 // If something goes wrong, this player is to blame
2694 RollbackScopeActor rollback_scope(m_rollback,
2695 std::string("player:")+player->getName());
2697 // Check the target node for rollback data; leave others unnoticed
2698 RollbackNode rn_old(&m_env->getMap(), p, this);
2700 m_script->node_on_receive_fields(p, formname, fields,playersao);
2702 // Report rollback data
2703 RollbackNode rn_new(&m_env->getMap(), p, this);
2704 if(rollback() && rn_new != rn_old){
2705 RollbackAction action;
2706 action.setSetNode(p, rn_old, rn_new);
2707 rollback()->reportAction(action);
2710 else if(command == TOSERVER_INVENTORY_FIELDS)
2712 std::string datastring((char*)&data[2], datasize-2);
2713 std::istringstream is(datastring, std::ios_base::binary);
2715 std::string formname = deSerializeString(is);
2716 int num = readU16(is);
2717 std::map<std::string, std::string> fields;
2718 for(int k=0; k<num; k++){
2719 std::string fieldname = deSerializeString(is);
2720 std::string fieldvalue = deSerializeLongString(is);
2721 fields[fieldname] = fieldvalue;
2724 m_script->on_playerReceiveFields(playersao, formname, fields);
2728 infostream<<"Server::ProcessData(): Ignoring "
2729 "unknown command "<<command<<std::endl;
2733 catch(SendFailedException &e)
2735 errorstream<<"Server::ProcessData(): SendFailedException: "
2741 void Server::setTimeOfDay(u32 time)
2743 m_env->setTimeOfDay(time);
2744 m_time_of_day_send_timer = 0;
2747 void Server::onMapEditEvent(MapEditEvent *event)
2749 //infostream<<"Server::onMapEditEvent()"<<std::endl;
2750 if(m_ignore_map_edit_events)
2752 if(m_ignore_map_edit_events_area.contains(event->getArea()))
2754 MapEditEvent *e = event->clone();
2755 m_unsent_map_edit_queue.push_back(e);
2758 Inventory* Server::getInventory(const InventoryLocation &loc)
2761 case InventoryLocation::UNDEFINED:
2764 case InventoryLocation::CURRENT_PLAYER:
2767 case InventoryLocation::PLAYER:
2769 Player *player = m_env->getPlayer(loc.name.c_str());
2772 PlayerSAO *playersao = player->getPlayerSAO();
2775 return playersao->getInventory();
2778 case InventoryLocation::NODEMETA:
2780 NodeMetadata *meta = m_env->getMap().getNodeMetadata(loc.p);
2783 return meta->getInventory();
2786 case InventoryLocation::DETACHED:
2788 if(m_detached_inventories.count(loc.name) == 0)
2790 return m_detached_inventories[loc.name];
2798 void Server::setInventoryModified(const InventoryLocation &loc)
2801 case InventoryLocation::UNDEFINED:
2804 case InventoryLocation::PLAYER:
2806 Player *player = m_env->getPlayer(loc.name.c_str());
2809 PlayerSAO *playersao = player->getPlayerSAO();
2812 playersao->m_inventory_not_sent = true;
2813 playersao->m_wielded_item_not_sent = true;
2816 case InventoryLocation::NODEMETA:
2818 v3s16 blockpos = getNodeBlockPos(loc.p);
2820 MapBlock *block = m_env->getMap().getBlockNoCreateNoEx(blockpos);
2822 block->raiseModified(MOD_STATE_WRITE_NEEDED);
2824 setBlockNotSent(blockpos);
2827 case InventoryLocation::DETACHED:
2829 sendDetachedInventory(loc.name,PEER_ID_INEXISTENT);
2837 void Server::SetBlocksNotSent(std::map<v3s16, MapBlock *>& block)
2839 std::list<u16> clients = m_clients.getClientIDs();
2841 // Set the modified blocks unsent for all the clients
2842 for (std::list<u16>::iterator
2843 i = clients.begin();
2844 i != clients.end(); ++i) {
2845 RemoteClient *client = m_clients.lockedGetClientNoEx(*i);
2847 client->SetBlocksNotSent(block);
2852 void Server::peerAdded(con::Peer *peer)
2854 DSTACK(__FUNCTION_NAME);
2855 verbosestream<<"Server::peerAdded(): peer->id="
2856 <<peer->id<<std::endl;
2859 c.type = con::PEER_ADDED;
2860 c.peer_id = peer->id;
2862 m_peer_change_queue.push_back(c);
2865 void Server::deletingPeer(con::Peer *peer, bool timeout)
2867 DSTACK(__FUNCTION_NAME);
2868 verbosestream<<"Server::deletingPeer(): peer->id="
2869 <<peer->id<<", timeout="<<timeout<<std::endl;
2871 m_clients.event(peer->id, CSE_Disconnect);
2873 c.type = con::PEER_REMOVED;
2874 c.peer_id = peer->id;
2875 c.timeout = timeout;
2876 m_peer_change_queue.push_back(c);
2879 bool Server::getClientConInfo(u16 peer_id, con::rtt_stat_type type, float* retval)
2881 *retval = m_con.getPeerStat(peer_id,type);
2882 if (*retval == -1) return false;
2886 bool Server::getClientInfo(
2895 std::string* vers_string
2898 *state = m_clients.getClientState(peer_id);
2900 RemoteClient* client = m_clients.lockedGetClientNoEx(peer_id, CS_Invalid);
2902 if (client == NULL) {
2907 *uptime = client->uptime();
2908 *ser_vers = client->serialization_version;
2909 *prot_vers = client->net_proto_version;
2911 *major = client->getMajor();
2912 *minor = client->getMinor();
2913 *patch = client->getPatch();
2914 *vers_string = client->getPatch();
2921 void Server::handlePeerChanges()
2923 while(m_peer_change_queue.size() > 0)
2925 con::PeerChange c = m_peer_change_queue.pop_front();
2927 verbosestream<<"Server: Handling peer change: "
2928 <<"id="<<c.peer_id<<", timeout="<<c.timeout
2933 case con::PEER_ADDED:
2934 m_clients.CreateClient(c.peer_id);
2937 case con::PEER_REMOVED:
2938 DeleteClient(c.peer_id, c.timeout?CDR_TIMEOUT:CDR_LEAVE);
2942 assert("Invalid peer change event received!" == 0);
2948 void Server::SendMovement(u16 peer_id)
2950 DSTACK(__FUNCTION_NAME);
2951 std::ostringstream os(std::ios_base::binary);
2953 writeU16(os, TOCLIENT_MOVEMENT);
2954 writeF1000(os, g_settings->getFloat("movement_acceleration_default"));
2955 writeF1000(os, g_settings->getFloat("movement_acceleration_air"));
2956 writeF1000(os, g_settings->getFloat("movement_acceleration_fast"));
2957 writeF1000(os, g_settings->getFloat("movement_speed_walk"));
2958 writeF1000(os, g_settings->getFloat("movement_speed_crouch"));
2959 writeF1000(os, g_settings->getFloat("movement_speed_fast"));
2960 writeF1000(os, g_settings->getFloat("movement_speed_climb"));
2961 writeF1000(os, g_settings->getFloat("movement_speed_jump"));
2962 writeF1000(os, g_settings->getFloat("movement_liquid_fluidity"));
2963 writeF1000(os, g_settings->getFloat("movement_liquid_fluidity_smooth"));
2964 writeF1000(os, g_settings->getFloat("movement_liquid_sink"));
2965 writeF1000(os, g_settings->getFloat("movement_gravity"));
2968 std::string s = os.str();
2969 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
2971 m_clients.send(peer_id, 0, data, true);
2974 void Server::SendHP(u16 peer_id, u8 hp)
2976 DSTACK(__FUNCTION_NAME);
2977 std::ostringstream os(std::ios_base::binary);
2979 writeU16(os, TOCLIENT_HP);
2983 std::string s = os.str();
2984 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
2986 m_clients.send(peer_id, 0, data, true);
2989 void Server::SendBreath(u16 peer_id, u16 breath)
2991 DSTACK(__FUNCTION_NAME);
2992 std::ostringstream os(std::ios_base::binary);
2994 writeU16(os, TOCLIENT_BREATH);
2995 writeU16(os, breath);
2998 std::string s = os.str();
2999 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3001 m_clients.send(peer_id, 0, data, true);
3004 void Server::SendAccessDenied(u16 peer_id,const std::wstring &reason)
3006 DSTACK(__FUNCTION_NAME);
3007 std::ostringstream os(std::ios_base::binary);
3009 writeU16(os, TOCLIENT_ACCESS_DENIED);
3010 os<<serializeWideString(reason);
3013 std::string s = os.str();
3014 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3016 m_clients.send(peer_id, 0, data, true);
3019 void Server::SendDeathscreen(u16 peer_id,bool set_camera_point_target,
3020 v3f camera_point_target)
3022 DSTACK(__FUNCTION_NAME);
3023 std::ostringstream os(std::ios_base::binary);
3025 writeU16(os, TOCLIENT_DEATHSCREEN);
3026 writeU8(os, set_camera_point_target);
3027 writeV3F1000(os, camera_point_target);
3030 std::string s = os.str();
3031 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3033 m_clients.send(peer_id, 0, data, true);
3036 void Server::SendItemDef(u16 peer_id,
3037 IItemDefManager *itemdef, u16 protocol_version)
3039 DSTACK(__FUNCTION_NAME);
3040 std::ostringstream os(std::ios_base::binary);
3044 u32 length of the next item
3045 zlib-compressed serialized ItemDefManager
3047 writeU16(os, TOCLIENT_ITEMDEF);
3048 std::ostringstream tmp_os(std::ios::binary);
3049 itemdef->serialize(tmp_os, protocol_version);
3050 std::ostringstream tmp_os2(std::ios::binary);
3051 compressZlib(tmp_os.str(), tmp_os2);
3052 os<<serializeLongString(tmp_os2.str());
3055 std::string s = os.str();
3056 verbosestream<<"Server: Sending item definitions to id("<<peer_id
3057 <<"): size="<<s.size()<<std::endl;
3058 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3060 m_clients.send(peer_id, 0, data, true);
3063 void Server::SendNodeDef(u16 peer_id,
3064 INodeDefManager *nodedef, u16 protocol_version)
3066 DSTACK(__FUNCTION_NAME);
3067 std::ostringstream os(std::ios_base::binary);
3071 u32 length of the next item
3072 zlib-compressed serialized NodeDefManager
3074 writeU16(os, TOCLIENT_NODEDEF);
3075 std::ostringstream tmp_os(std::ios::binary);
3076 nodedef->serialize(tmp_os, protocol_version);
3077 std::ostringstream tmp_os2(std::ios::binary);
3078 compressZlib(tmp_os.str(), tmp_os2);
3079 os<<serializeLongString(tmp_os2.str());
3082 std::string s = os.str();
3083 verbosestream<<"Server: Sending node definitions to id("<<peer_id
3084 <<"): size="<<s.size()<<std::endl;
3085 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3087 m_clients.send(peer_id, 0, data, true);
3091 Non-static send methods
3094 void Server::SendInventory(u16 peer_id)
3096 DSTACK(__FUNCTION_NAME);
3098 PlayerSAO *playersao = getPlayerSAO(peer_id);
3101 playersao->m_inventory_not_sent = false;
3107 std::ostringstream os;
3108 playersao->getInventory()->serialize(os);
3110 std::string s = os.str();
3112 SharedBuffer<u8> data(s.size()+2);
3113 writeU16(&data[0], TOCLIENT_INVENTORY);
3114 memcpy(&data[2], s.c_str(), s.size());
3117 m_clients.send(peer_id, 0, data, true);
3120 void Server::SendChatMessage(u16 peer_id, const std::wstring &message)
3122 DSTACK(__FUNCTION_NAME);
3124 std::ostringstream os(std::ios_base::binary);
3128 writeU16(buf, TOCLIENT_CHAT_MESSAGE);
3129 os.write((char*)buf, 2);
3132 writeU16(buf, message.size());
3133 os.write((char*)buf, 2);
3136 for(u32 i=0; i<message.size(); i++)
3140 os.write((char*)buf, 2);
3144 std::string s = os.str();
3145 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3147 if (peer_id != PEER_ID_INEXISTENT)
3150 m_clients.send(peer_id, 0, data, true);
3154 m_clients.sendToAll(0,data,true);
3158 void Server::SendShowFormspecMessage(u16 peer_id, const std::string &formspec,
3159 const std::string &formname)
3161 DSTACK(__FUNCTION_NAME);
3163 std::ostringstream os(std::ios_base::binary);
3168 writeU16(buf, TOCLIENT_SHOW_FORMSPEC);
3169 os.write((char*)buf, 2);
3170 os<<serializeLongString(FORMSPEC_VERSION_STRING + formspec);
3171 os<<serializeString(formname);
3174 std::string s = os.str();
3175 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3177 m_clients.send(peer_id, 0, data, true);
3180 // Spawns a particle on peer with peer_id
3181 void Server::SendSpawnParticle(u16 peer_id, v3f pos, v3f velocity, v3f acceleration,
3182 float expirationtime, float size, bool collisiondetection,
3183 bool vertical, std::string texture)
3185 DSTACK(__FUNCTION_NAME);
3187 std::ostringstream os(std::ios_base::binary);
3188 writeU16(os, TOCLIENT_SPAWN_PARTICLE);
3189 writeV3F1000(os, pos);
3190 writeV3F1000(os, velocity);
3191 writeV3F1000(os, acceleration);
3192 writeF1000(os, expirationtime);
3193 writeF1000(os, size);
3194 writeU8(os, collisiondetection);
3195 os<<serializeLongString(texture);
3196 writeU8(os, vertical);
3199 std::string s = os.str();
3200 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3202 if (peer_id != PEER_ID_INEXISTENT)
3205 m_clients.send(peer_id, 0, data, true);
3209 m_clients.sendToAll(0,data,true);
3213 // Adds a ParticleSpawner on peer with peer_id
3214 void Server::SendAddParticleSpawner(u16 peer_id, u16 amount, float spawntime, v3f minpos, v3f maxpos,
3215 v3f minvel, v3f maxvel, v3f minacc, v3f maxacc, float minexptime, float maxexptime,
3216 float minsize, float maxsize, bool collisiondetection, bool vertical, std::string texture, u32 id)
3218 DSTACK(__FUNCTION_NAME);
3220 std::ostringstream os(std::ios_base::binary);
3221 writeU16(os, TOCLIENT_ADD_PARTICLESPAWNER);
3223 writeU16(os, amount);
3224 writeF1000(os, spawntime);
3225 writeV3F1000(os, minpos);
3226 writeV3F1000(os, maxpos);
3227 writeV3F1000(os, minvel);
3228 writeV3F1000(os, maxvel);
3229 writeV3F1000(os, minacc);
3230 writeV3F1000(os, maxacc);
3231 writeF1000(os, minexptime);
3232 writeF1000(os, maxexptime);
3233 writeF1000(os, minsize);
3234 writeF1000(os, maxsize);
3235 writeU8(os, collisiondetection);
3236 os<<serializeLongString(texture);
3238 writeU8(os, vertical);
3241 std::string s = os.str();
3242 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3244 if (peer_id != PEER_ID_INEXISTENT)
3247 m_clients.send(peer_id, 0, data, true);
3250 m_clients.sendToAll(0,data,true);
3254 void Server::SendDeleteParticleSpawner(u16 peer_id, u32 id)
3256 DSTACK(__FUNCTION_NAME);
3258 std::ostringstream os(std::ios_base::binary);
3259 writeU16(os, TOCLIENT_DELETE_PARTICLESPAWNER);
3264 std::string s = os.str();
3265 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3267 if (peer_id != PEER_ID_INEXISTENT) {
3269 m_clients.send(peer_id, 0, data, true);
3272 m_clients.sendToAll(0,data,true);
3277 void Server::SendHUDAdd(u16 peer_id, u32 id, HudElement *form)
3279 std::ostringstream os(std::ios_base::binary);
3282 writeU16(os, TOCLIENT_HUDADD);
3284 writeU8(os, (u8)form->type);
3285 writeV2F1000(os, form->pos);
3286 os << serializeString(form->name);
3287 writeV2F1000(os, form->scale);
3288 os << serializeString(form->text);
3289 writeU32(os, form->number);
3290 writeU32(os, form->item);
3291 writeU32(os, form->dir);
3292 writeV2F1000(os, form->align);
3293 writeV2F1000(os, form->offset);
3294 writeV3F1000(os, form->world_pos);
3295 writeV2S32(os,form->size);
3298 std::string s = os.str();
3299 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3301 m_clients.send(peer_id, 1, data, true);
3304 void Server::SendHUDRemove(u16 peer_id, u32 id)
3306 std::ostringstream os(std::ios_base::binary);
3309 writeU16(os, TOCLIENT_HUDRM);
3313 std::string s = os.str();
3314 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3317 m_clients.send(peer_id, 1, data, true);
3320 void Server::SendHUDChange(u16 peer_id, u32 id, HudElementStat stat, void *value)
3322 std::ostringstream os(std::ios_base::binary);
3325 writeU16(os, TOCLIENT_HUDCHANGE);
3327 writeU8(os, (u8)stat);
3330 case HUD_STAT_SCALE:
3331 case HUD_STAT_ALIGN:
3332 case HUD_STAT_OFFSET:
3333 writeV2F1000(os, *(v2f *)value);
3337 os << serializeString(*(std::string *)value);
3339 case HUD_STAT_WORLD_POS:
3340 writeV3F1000(os, *(v3f *)value);
3343 writeV2S32(os,*(v2s32 *)value);
3345 case HUD_STAT_NUMBER:
3349 writeU32(os, *(u32 *)value);
3354 std::string s = os.str();
3355 SharedBuffer<u8> data((u8 *)s.c_str(), s.size());
3357 m_clients.send(peer_id, 0, data, true);
3360 void Server::SendHUDSetFlags(u16 peer_id, u32 flags, u32 mask)
3362 std::ostringstream os(std::ios_base::binary);
3365 writeU16(os, TOCLIENT_HUD_SET_FLAGS);
3367 //////////////////////////// compatibility code to be removed //////////////
3368 flags &= ~(HUD_FLAG_HEALTHBAR_VISIBLE | HUD_FLAG_BREATHBAR_VISIBLE);
3369 ////////////////////////////////////////////////////////////////////////////
3370 writeU32(os, flags);
3374 std::string s = os.str();
3375 SharedBuffer<u8> data((u8 *)s.c_str(), s.size());
3377 m_clients.send(peer_id, 0, data, true);
3380 void Server::SendHUDSetParam(u16 peer_id, u16 param, const std::string &value)
3382 std::ostringstream os(std::ios_base::binary);
3385 writeU16(os, TOCLIENT_HUD_SET_PARAM);
3386 writeU16(os, param);
3387 os<<serializeString(value);
3390 std::string s = os.str();
3391 SharedBuffer<u8> data((u8 *)s.c_str(), s.size());
3393 m_clients.send(peer_id, 0, data, true);
3396 void Server::SendSetSky(u16 peer_id, const video::SColor &bgcolor,
3397 const std::string &type, const std::vector<std::string> ¶ms)
3399 std::ostringstream os(std::ios_base::binary);
3402 writeU16(os, TOCLIENT_SET_SKY);
3403 writeARGB8(os, bgcolor);
3404 os<<serializeString(type);
3405 writeU16(os, params.size());
3406 for(size_t i=0; i<params.size(); i++)
3407 os<<serializeString(params[i]);
3410 std::string s = os.str();
3411 SharedBuffer<u8> data((u8 *)s.c_str(), s.size());
3413 m_clients.send(peer_id, 0, data, true);
3416 void Server::SendOverrideDayNightRatio(u16 peer_id, bool do_override,
3419 std::ostringstream os(std::ios_base::binary);
3422 writeU16(os, TOCLIENT_OVERRIDE_DAY_NIGHT_RATIO);
3423 writeU8(os, do_override);
3424 writeU16(os, ratio*65535);
3427 std::string s = os.str();
3428 SharedBuffer<u8> data((u8 *)s.c_str(), s.size());
3430 m_clients.send(peer_id, 0, data, true);
3433 void Server::SendTimeOfDay(u16 peer_id, u16 time, f32 time_speed)
3435 DSTACK(__FUNCTION_NAME);
3438 SharedBuffer<u8> data(2+2+4);
3439 writeU16(&data[0], TOCLIENT_TIME_OF_DAY);
3440 writeU16(&data[2], time);
3441 writeF1000(&data[4], time_speed);
3443 if (peer_id == PEER_ID_INEXISTENT) {
3444 m_clients.sendToAll(0,data,true);
3448 m_clients.send(peer_id, 0, data, true);
3452 void Server::SendPlayerHP(u16 peer_id)
3454 DSTACK(__FUNCTION_NAME);
3455 PlayerSAO *playersao = getPlayerSAO(peer_id);
3457 playersao->m_hp_not_sent = false;
3458 SendHP(peer_id, playersao->getHP());
3459 m_script->player_event(playersao,"health_changed");
3461 // Send to other clients
3462 std::string str = gob_cmd_punched(playersao->readDamage(), playersao->getHP());
3463 ActiveObjectMessage aom(playersao->getId(), true, str);
3464 playersao->m_messages_out.push_back(aom);
3467 void Server::SendPlayerBreath(u16 peer_id)
3469 DSTACK(__FUNCTION_NAME);
3470 PlayerSAO *playersao = getPlayerSAO(peer_id);
3472 playersao->m_breath_not_sent = false;
3473 m_script->player_event(playersao,"breath_changed");
3474 SendBreath(peer_id, playersao->getBreath());
3477 void Server::SendMovePlayer(u16 peer_id)
3479 DSTACK(__FUNCTION_NAME);
3480 Player *player = m_env->getPlayer(peer_id);
3483 std::ostringstream os(std::ios_base::binary);
3484 writeU16(os, TOCLIENT_MOVE_PLAYER);
3485 writeV3F1000(os, player->getPosition());
3486 writeF1000(os, player->getPitch());
3487 writeF1000(os, player->getYaw());
3490 v3f pos = player->getPosition();
3491 f32 pitch = player->getPitch();
3492 f32 yaw = player->getYaw();
3493 verbosestream<<"Server: Sending TOCLIENT_MOVE_PLAYER"
3494 <<" pos=("<<pos.X<<","<<pos.Y<<","<<pos.Z<<")"
3501 std::string s = os.str();
3502 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3504 m_clients.send(peer_id, 0, data, true);
3507 void Server::SendLocalPlayerAnimations(u16 peer_id, v2s32 animation_frames[4], f32 animation_speed)
3509 std::ostringstream os(std::ios_base::binary);
3511 writeU16(os, TOCLIENT_LOCAL_PLAYER_ANIMATIONS);
3512 writeV2S32(os, animation_frames[0]);
3513 writeV2S32(os, animation_frames[1]);
3514 writeV2S32(os, animation_frames[2]);
3515 writeV2S32(os, animation_frames[3]);
3516 writeF1000(os, animation_speed);
3519 std::string s = os.str();
3520 SharedBuffer<u8> data((u8 *)s.c_str(), s.size());
3522 m_clients.send(peer_id, 0, data, true);
3525 void Server::SendEyeOffset(u16 peer_id, v3f first, v3f third)
3527 std::ostringstream os(std::ios_base::binary);
3529 writeU16(os, TOCLIENT_EYE_OFFSET);
3530 writeV3F1000(os, first);
3531 writeV3F1000(os, third);
3534 std::string s = os.str();
3535 SharedBuffer<u8> data((u8 *)s.c_str(), s.size());
3537 m_clients.send(peer_id, 0, data, true);
3539 void Server::SendPlayerPrivileges(u16 peer_id)
3541 Player *player = m_env->getPlayer(peer_id);
3543 if(player->peer_id == PEER_ID_INEXISTENT)
3546 std::set<std::string> privs;
3547 m_script->getAuth(player->getName(), NULL, &privs);
3549 std::ostringstream os(std::ios_base::binary);
3550 writeU16(os, TOCLIENT_PRIVILEGES);
3551 writeU16(os, privs.size());
3552 for(std::set<std::string>::const_iterator i = privs.begin();
3553 i != privs.end(); i++){
3554 os<<serializeString(*i);
3558 std::string s = os.str();
3559 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3561 m_clients.send(peer_id, 0, data, true);
3564 void Server::SendPlayerInventoryFormspec(u16 peer_id)
3566 Player *player = m_env->getPlayer(peer_id);
3568 if(player->peer_id == PEER_ID_INEXISTENT)
3571 std::ostringstream os(std::ios_base::binary);
3572 writeU16(os, TOCLIENT_INVENTORY_FORMSPEC);
3573 os<<serializeLongString(FORMSPEC_VERSION_STRING + player->inventory_formspec);
3576 std::string s = os.str();
3577 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3579 m_clients.send(peer_id, 0, data, true);
3582 s32 Server::playSound(const SimpleSoundSpec &spec,
3583 const ServerSoundParams ¶ms)
3585 // Find out initial position of sound
3586 bool pos_exists = false;
3587 v3f pos = params.getPos(m_env, &pos_exists);
3588 // If position is not found while it should be, cancel sound
3589 if(pos_exists != (params.type != ServerSoundParams::SSP_LOCAL))
3592 // Filter destination clients
3593 std::list<u16> dst_clients;
3594 if(params.to_player != "")
3596 Player *player = m_env->getPlayer(params.to_player.c_str());
3598 infostream<<"Server::playSound: Player \""<<params.to_player
3599 <<"\" not found"<<std::endl;
3602 if(player->peer_id == PEER_ID_INEXISTENT){
3603 infostream<<"Server::playSound: Player \""<<params.to_player
3604 <<"\" not connected"<<std::endl;
3607 dst_clients.push_back(player->peer_id);
3611 std::list<u16> clients = m_clients.getClientIDs();
3613 for(std::list<u16>::iterator
3614 i = clients.begin(); i != clients.end(); ++i)
3616 Player *player = m_env->getPlayer(*i);
3620 if(player->getPosition().getDistanceFrom(pos) >
3621 params.max_hear_distance)
3624 dst_clients.push_back(*i);
3627 if(dst_clients.empty())
3631 s32 id = m_next_sound_id++;
3632 // The sound will exist as a reference in m_playing_sounds
3633 m_playing_sounds[id] = ServerPlayingSound();
3634 ServerPlayingSound &psound = m_playing_sounds[id];
3635 psound.params = params;
3636 for(std::list<u16>::iterator i = dst_clients.begin();
3637 i != dst_clients.end(); i++)
3638 psound.clients.insert(*i);
3640 std::ostringstream os(std::ios_base::binary);
3641 writeU16(os, TOCLIENT_PLAY_SOUND);
3643 os<<serializeString(spec.name);
3644 writeF1000(os, spec.gain * params.gain);
3645 writeU8(os, params.type);
3646 writeV3F1000(os, pos);
3647 writeU16(os, params.object);
3648 writeU8(os, params.loop);
3650 std::string s = os.str();
3651 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3653 for(std::list<u16>::iterator i = dst_clients.begin();
3654 i != dst_clients.end(); i++){
3656 m_clients.send(*i, 0, data, true);
3660 void Server::stopSound(s32 handle)
3662 // Get sound reference
3663 std::map<s32, ServerPlayingSound>::iterator i =
3664 m_playing_sounds.find(handle);
3665 if(i == m_playing_sounds.end())
3667 ServerPlayingSound &psound = i->second;
3669 std::ostringstream os(std::ios_base::binary);
3670 writeU16(os, TOCLIENT_STOP_SOUND);
3671 writeS32(os, handle);
3673 std::string s = os.str();
3674 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3676 for(std::set<u16>::iterator i = psound.clients.begin();
3677 i != psound.clients.end(); i++){
3679 m_clients.send(*i, 0, data, true);
3681 // Remove sound reference
3682 m_playing_sounds.erase(i);
3685 void Server::sendRemoveNode(v3s16 p, u16 ignore_id,
3686 std::list<u16> *far_players, float far_d_nodes)
3688 float maxd = far_d_nodes*BS;
3689 v3f p_f = intToFloat(p, BS);
3693 SharedBuffer<u8> reply(replysize);
3694 writeU16(&reply[0], TOCLIENT_REMOVENODE);
3695 writeS16(&reply[2], p.X);
3696 writeS16(&reply[4], p.Y);
3697 writeS16(&reply[6], p.Z);
3699 std::list<u16> clients = m_clients.getClientIDs();
3700 for(std::list<u16>::iterator
3701 i = clients.begin();
3702 i != clients.end(); ++i)
3707 Player *player = m_env->getPlayer(*i);
3710 // If player is far away, only set modified blocks not sent
3711 v3f player_pos = player->getPosition();
3712 if(player_pos.getDistanceFrom(p_f) > maxd)
3714 far_players->push_back(*i);
3721 m_clients.send(*i, 0, reply, true);
3725 void Server::sendAddNode(v3s16 p, MapNode n, u16 ignore_id,
3726 std::list<u16> *far_players, float far_d_nodes,
3727 bool remove_metadata)
3729 float maxd = far_d_nodes*BS;
3730 v3f p_f = intToFloat(p, BS);
3732 std::list<u16> clients = m_clients.getClientIDs();
3733 for(std::list<u16>::iterator
3734 i = clients.begin();
3735 i != clients.end(); ++i)
3741 Player *player = m_env->getPlayer(*i);
3744 // If player is far away, only set modified blocks not sent
3745 v3f player_pos = player->getPosition();
3746 if(player_pos.getDistanceFrom(p_f) > maxd)
3748 far_players->push_back(*i);
3753 SharedBuffer<u8> reply(0);
3755 RemoteClient* client = m_clients.lockedGetClientNoEx(*i);
3759 u32 replysize = 9 + MapNode::serializedLength(client->serialization_version);
3760 reply = SharedBuffer<u8>(replysize);
3761 writeU16(&reply[0], TOCLIENT_ADDNODE);
3762 writeS16(&reply[2], p.X);
3763 writeS16(&reply[4], p.Y);
3764 writeS16(&reply[6], p.Z);
3765 n.serialize(&reply[8], client->serialization_version);
3766 u32 index = 8 + MapNode::serializedLength(client->serialization_version);
3767 writeU8(&reply[index], remove_metadata ? 0 : 1);
3769 if (!remove_metadata) {
3770 if (client->net_proto_version <= 21) {
3771 // Old clients always clear metadata; fix it
3772 // by sending the full block again.
3773 client->SetBlockNotSent(p);
3780 if (reply.getSize() > 0)
3781 m_clients.send(*i, 0, reply, true);
3785 void Server::setBlockNotSent(v3s16 p)
3787 std::list<u16> clients = m_clients.getClientIDs();
3789 for(std::list<u16>::iterator
3790 i = clients.begin();
3791 i != clients.end(); ++i)
3793 RemoteClient *client = m_clients.lockedGetClientNoEx(*i);
3794 client->SetBlockNotSent(p);
3799 void Server::SendBlockNoLock(u16 peer_id, MapBlock *block, u8 ver, u16 net_proto_version)
3801 DSTACK(__FUNCTION_NAME);
3803 v3s16 p = block->getPos();
3807 bool completely_air = true;
3808 for(s16 z0=0; z0<MAP_BLOCKSIZE; z0++)
3809 for(s16 x0=0; x0<MAP_BLOCKSIZE; x0++)
3810 for(s16 y0=0; y0<MAP_BLOCKSIZE; y0++)
3812 if(block->getNodeNoEx(v3s16(x0,y0,z0)).d != CONTENT_AIR)
3814 completely_air = false;
3815 x0 = y0 = z0 = MAP_BLOCKSIZE; // Break out
3820 infostream<<"Server: Sending block ("<<p.X<<","<<p.Y<<","<<p.Z<<"): ";
3822 infostream<<"[completely air] ";
3823 infostream<<std::endl;
3827 Create a packet with the block in the right format
3830 std::ostringstream os(std::ios_base::binary);
3831 block->serialize(os, ver, false);
3832 block->serializeNetworkSpecific(os, net_proto_version);
3833 std::string s = os.str();
3834 SharedBuffer<u8> blockdata((u8*)s.c_str(), s.size());
3836 u32 replysize = 8 + blockdata.getSize();
3837 SharedBuffer<u8> reply(replysize);
3838 writeU16(&reply[0], TOCLIENT_BLOCKDATA);
3839 writeS16(&reply[2], p.X);
3840 writeS16(&reply[4], p.Y);
3841 writeS16(&reply[6], p.Z);
3842 memcpy(&reply[8], *blockdata, blockdata.getSize());
3844 /*infostream<<"Server: Sending block ("<<p.X<<","<<p.Y<<","<<p.Z<<")"
3845 <<": \tpacket size: "<<replysize<<std::endl;*/
3850 m_clients.send(peer_id, 2, reply, true);
3853 void Server::SendBlocks(float dtime)
3855 DSTACK(__FUNCTION_NAME);
3857 JMutexAutoLock envlock(m_env_mutex);
3858 //TODO check if one big lock could be faster then multiple small ones
3860 ScopeProfiler sp(g_profiler, "Server: sel and send blocks to clients");
3862 std::vector<PrioritySortedBlockTransfer> queue;
3864 s32 total_sending = 0;
3867 ScopeProfiler sp(g_profiler, "Server: selecting blocks for sending");
3869 std::list<u16> clients = m_clients.getClientIDs();
3872 for(std::list<u16>::iterator
3873 i = clients.begin();
3874 i != clients.end(); ++i)
3876 RemoteClient *client = m_clients.lockedGetClientNoEx(*i, CS_Active);
3881 total_sending += client->SendingCount();
3882 client->GetNextBlocks(m_env,m_emerge, dtime, queue);
3888 // Lowest priority number comes first.
3889 // Lowest is most important.
3890 std::sort(queue.begin(), queue.end());
3893 for(u32 i=0; i<queue.size(); i++)
3895 //TODO: Calculate limit dynamically
3896 if(total_sending >= g_settings->getS32
3897 ("max_simultaneous_block_sends_server_total"))
3900 PrioritySortedBlockTransfer q = queue[i];
3902 MapBlock *block = NULL;
3905 block = m_env->getMap().getBlockNoCreate(q.pos);
3907 catch(InvalidPositionException &e)
3912 RemoteClient *client = m_clients.lockedGetClientNoEx(q.peer_id, CS_Active);
3917 SendBlockNoLock(q.peer_id, block, client->serialization_version, client->net_proto_version);
3919 client->SentBlock(q.pos);
3925 void Server::fillMediaCache()
3927 DSTACK(__FUNCTION_NAME);
3929 infostream<<"Server: Calculating media file checksums"<<std::endl;
3931 // Collect all media file paths
3932 std::list<std::string> paths;
3933 for(std::vector<ModSpec>::iterator i = m_mods.begin();
3934 i != m_mods.end(); i++){
3935 const ModSpec &mod = *i;
3936 paths.push_back(mod.path + DIR_DELIM + "textures");
3937 paths.push_back(mod.path + DIR_DELIM + "sounds");
3938 paths.push_back(mod.path + DIR_DELIM + "media");
3939 paths.push_back(mod.path + DIR_DELIM + "models");
3941 paths.push_back(porting::path_user + DIR_DELIM + "textures" + DIR_DELIM + "server");
3943 // Collect media file information from paths into cache
3944 for(std::list<std::string>::iterator i = paths.begin();
3945 i != paths.end(); i++)
3947 std::string mediapath = *i;
3948 std::vector<fs::DirListNode> dirlist = fs::GetDirListing(mediapath);
3949 for(u32 j=0; j<dirlist.size(); j++){
3950 if(dirlist[j].dir) // Ignode dirs
3952 std::string filename = dirlist[j].name;
3953 // If name contains illegal characters, ignore the file
3954 if(!string_allowed(filename, TEXTURENAME_ALLOWED_CHARS)){
3955 infostream<<"Server: ignoring illegal file name: \""
3956 <<filename<<"\""<<std::endl;
3959 // If name is not in a supported format, ignore it
3960 const char *supported_ext[] = {
3961 ".png", ".jpg", ".bmp", ".tga",
3962 ".pcx", ".ppm", ".psd", ".wal", ".rgb",
3964 ".x", ".b3d", ".md2", ".obj",
3967 if(removeStringEnd(filename, supported_ext) == ""){
3968 infostream<<"Server: ignoring unsupported file extension: \""
3969 <<filename<<"\""<<std::endl;
3972 // Ok, attempt to load the file and add to cache
3973 std::string filepath = mediapath + DIR_DELIM + filename;
3975 std::ifstream fis(filepath.c_str(), std::ios_base::binary);
3976 if(fis.good() == false){
3977 errorstream<<"Server::fillMediaCache(): Could not open \""
3978 <<filename<<"\" for reading"<<std::endl;
3981 std::ostringstream tmp_os(std::ios_base::binary);
3985 fis.read(buf, 1024);
3986 std::streamsize len = fis.gcount();
3987 tmp_os.write(buf, len);
3996 errorstream<<"Server::fillMediaCache(): Failed to read \""
3997 <<filename<<"\""<<std::endl;
4000 if(tmp_os.str().length() == 0){
4001 errorstream<<"Server::fillMediaCache(): Empty file \""
4002 <<filepath<<"\""<<std::endl;
4007 sha1.addBytes(tmp_os.str().c_str(), tmp_os.str().length());
4009 unsigned char *digest = sha1.getDigest();
4010 std::string sha1_base64 = base64_encode(digest, 20);
4011 std::string sha1_hex = hex_encode((char*)digest, 20);
4015 this->m_media[filename] = MediaInfo(filepath, sha1_base64);
4016 verbosestream<<"Server: "<<sha1_hex<<" is "<<filename<<std::endl;
4021 struct SendableMediaAnnouncement
4024 std::string sha1_digest;
4026 SendableMediaAnnouncement(const std::string &name_="",
4027 const std::string &sha1_digest_=""):
4029 sha1_digest(sha1_digest_)
4033 void Server::sendMediaAnnouncement(u16 peer_id)
4035 DSTACK(__FUNCTION_NAME);
4037 verbosestream<<"Server: Announcing files to id("<<peer_id<<")"
4040 std::list<SendableMediaAnnouncement> file_announcements;
4042 for(std::map<std::string, MediaInfo>::iterator i = m_media.begin();
4043 i != m_media.end(); i++){
4045 file_announcements.push_back(
4046 SendableMediaAnnouncement(i->first, i->second.sha1_digest));
4050 std::ostringstream os(std::ios_base::binary);
4058 u16 length of sha1_digest
4063 writeU16(os, TOCLIENT_ANNOUNCE_MEDIA);
4064 writeU16(os, file_announcements.size());
4066 for(std::list<SendableMediaAnnouncement>::iterator
4067 j = file_announcements.begin();
4068 j != file_announcements.end(); ++j){
4069 os<<serializeString(j->name);
4070 os<<serializeString(j->sha1_digest);
4072 os<<serializeString(g_settings->get("remote_media"));
4075 std::string s = os.str();
4076 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
4079 m_clients.send(peer_id, 0, data, true);
4082 struct SendableMedia
4088 SendableMedia(const std::string &name_="", const std::string &path_="",
4089 const std::string &data_=""):
4096 void Server::sendRequestedMedia(u16 peer_id,
4097 const std::list<std::string> &tosend)
4099 DSTACK(__FUNCTION_NAME);
4101 verbosestream<<"Server::sendRequestedMedia(): "
4102 <<"Sending files to client"<<std::endl;
4106 // Put 5kB in one bunch (this is not accurate)
4107 u32 bytes_per_bunch = 5000;
4109 std::vector< std::list<SendableMedia> > file_bunches;
4110 file_bunches.push_back(std::list<SendableMedia>());
4112 u32 file_size_bunch_total = 0;
4114 for(std::list<std::string>::const_iterator i = tosend.begin();
4115 i != tosend.end(); ++i)
4117 const std::string &name = *i;
4119 if(m_media.find(name) == m_media.end()){
4120 errorstream<<"Server::sendRequestedMedia(): Client asked for "
4121 <<"unknown file \""<<(name)<<"\""<<std::endl;
4125 //TODO get path + name
4126 std::string tpath = m_media[name].path;
4129 std::ifstream fis(tpath.c_str(), std::ios_base::binary);
4130 if(fis.good() == false){
4131 errorstream<<"Server::sendRequestedMedia(): Could not open \""
4132 <<tpath<<"\" for reading"<<std::endl;
4135 std::ostringstream tmp_os(std::ios_base::binary);
4139 fis.read(buf, 1024);
4140 std::streamsize len = fis.gcount();
4141 tmp_os.write(buf, len);
4142 file_size_bunch_total += len;
4151 errorstream<<"Server::sendRequestedMedia(): Failed to read \""
4152 <<name<<"\""<<std::endl;
4155 /*infostream<<"Server::sendRequestedMedia(): Loaded \""
4156 <<tname<<"\""<<std::endl;*/
4158 file_bunches[file_bunches.size()-1].push_back(
4159 SendableMedia(name, tpath, tmp_os.str()));
4161 // Start next bunch if got enough data
4162 if(file_size_bunch_total >= bytes_per_bunch){
4163 file_bunches.push_back(std::list<SendableMedia>());
4164 file_size_bunch_total = 0;
4169 /* Create and send packets */
4171 u32 num_bunches = file_bunches.size();
4172 for(u32 i=0; i<num_bunches; i++)
4174 std::ostringstream os(std::ios_base::binary);
4178 u16 total number of texture bunches
4179 u16 index of this bunch
4180 u32 number of files in this bunch
4189 writeU16(os, TOCLIENT_MEDIA);
4190 writeU16(os, num_bunches);
4192 writeU32(os, file_bunches[i].size());
4194 for(std::list<SendableMedia>::iterator
4195 j = file_bunches[i].begin();
4196 j != file_bunches[i].end(); ++j){
4197 os<<serializeString(j->name);
4198 os<<serializeLongString(j->data);
4202 std::string s = os.str();
4203 verbosestream<<"Server::sendRequestedMedia(): bunch "
4204 <<i<<"/"<<num_bunches
4205 <<" files="<<file_bunches[i].size()
4206 <<" size=" <<s.size()<<std::endl;
4207 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
4209 m_clients.send(peer_id, 2, data, true);
4213 void Server::sendDetachedInventory(const std::string &name, u16 peer_id)
4215 if(m_detached_inventories.count(name) == 0){
4216 errorstream<<__FUNCTION_NAME<<": \""<<name<<"\" not found"<<std::endl;
4219 Inventory *inv = m_detached_inventories[name];
4221 std::ostringstream os(std::ios_base::binary);
4222 writeU16(os, TOCLIENT_DETACHED_INVENTORY);
4223 os<<serializeString(name);
4227 std::string s = os.str();
4228 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
4230 if (peer_id != PEER_ID_INEXISTENT)
4233 m_clients.send(peer_id, 0, data, true);
4237 m_clients.sendToAll(0,data,true);
4241 void Server::sendDetachedInventories(u16 peer_id)
4243 DSTACK(__FUNCTION_NAME);
4245 for(std::map<std::string, Inventory*>::iterator
4246 i = m_detached_inventories.begin();
4247 i != m_detached_inventories.end(); i++){
4248 const std::string &name = i->first;
4249 //Inventory *inv = i->second;
4250 sendDetachedInventory(name, peer_id);
4258 void Server::DiePlayer(u16 peer_id)
4260 DSTACK(__FUNCTION_NAME);
4262 PlayerSAO *playersao = getPlayerSAO(peer_id);
4265 infostream<<"Server::DiePlayer(): Player "
4266 <<playersao->getPlayer()->getName()
4267 <<" dies"<<std::endl;
4269 playersao->setHP(0);
4271 // Trigger scripted stuff
4272 m_script->on_dieplayer(playersao);
4274 SendPlayerHP(peer_id);
4275 SendDeathscreen(peer_id, false, v3f(0,0,0));
4278 void Server::RespawnPlayer(u16 peer_id)
4280 DSTACK(__FUNCTION_NAME);
4282 PlayerSAO *playersao = getPlayerSAO(peer_id);
4285 infostream<<"Server::RespawnPlayer(): Player "
4286 <<playersao->getPlayer()->getName()
4287 <<" respawns"<<std::endl;
4289 playersao->setHP(PLAYER_MAX_HP);
4291 bool repositioned = m_script->on_respawnplayer(playersao);
4293 v3f pos = findSpawnPos(m_env->getServerMap());
4294 playersao->setPos(pos);
4298 void Server::DenyAccess(u16 peer_id, const std::wstring &reason)
4300 DSTACK(__FUNCTION_NAME);
4302 SendAccessDenied(peer_id, reason);
4303 m_clients.event(peer_id, CSE_SetDenied);
4304 m_con.DisconnectPeer(peer_id);
4307 void Server::DeleteClient(u16 peer_id, ClientDeletionReason reason)
4309 DSTACK(__FUNCTION_NAME);
4310 std::wstring message;
4313 Clear references to playing sounds
4315 for(std::map<s32, ServerPlayingSound>::iterator
4316 i = m_playing_sounds.begin();
4317 i != m_playing_sounds.end();)
4319 ServerPlayingSound &psound = i->second;
4320 psound.clients.erase(peer_id);
4321 if(psound.clients.empty())
4322 m_playing_sounds.erase(i++);
4327 Player *player = m_env->getPlayer(peer_id);
4329 // Collect information about leaving in chat
4331 if(player != NULL && reason != CDR_DENY)
4333 std::wstring name = narrow_to_wide(player->getName());
4336 message += L" left the game.";
4337 if(reason == CDR_TIMEOUT)
4338 message += L" (timed out)";
4342 /* Run scripts and remove from environment */
4346 PlayerSAO *playersao = player->getPlayerSAO();
4349 m_script->on_leaveplayer(playersao);
4351 playersao->disconnected();
4359 if(player != NULL && reason != CDR_DENY)
4361 std::ostringstream os(std::ios_base::binary);
4362 std::list<u16> clients = m_clients.getClientIDs();
4364 for(std::list<u16>::iterator
4365 i = clients.begin();
4366 i != clients.end(); ++i)
4369 Player *player = m_env->getPlayer(*i);
4372 // Get name of player
4373 os<<player->getName()<<" ";
4376 actionstream<<player->getName()<<" "
4377 <<(reason==CDR_TIMEOUT?"times out.":"leaves game.")
4378 <<" List of players: "<<os.str()<<std::endl;
4382 JMutexAutoLock env_lock(m_env_mutex);
4383 m_clients.DeleteClient(peer_id);
4387 // Send leave chat message to all remaining clients
4388 if(message.length() != 0)
4389 SendChatMessage(PEER_ID_INEXISTENT,message);
4392 void Server::UpdateCrafting(u16 peer_id)
4394 DSTACK(__FUNCTION_NAME);
4396 Player* player = m_env->getPlayer(peer_id);
4399 // Get a preview for crafting
4401 InventoryLocation loc;
4402 loc.setPlayer(player->getName());
4403 getCraftingResult(&player->inventory, preview, false, this);
4404 m_env->getScriptIface()->item_CraftPredict(preview, player->getPlayerSAO(), (&player->inventory)->getList("craft"), loc);
4406 // Put the new preview in
4407 InventoryList *plist = player->inventory.getList("craftpreview");
4409 assert(plist->getSize() >= 1);
4410 plist->changeItem(0, preview);
4413 RemoteClient* Server::getClient(u16 peer_id, ClientState state_min)
4415 RemoteClient *client = getClientNoEx(peer_id,state_min);
4417 throw ClientNotFoundException("Client not found");
4421 RemoteClient* Server::getClientNoEx(u16 peer_id, ClientState state_min)
4423 return m_clients.getClientNoEx(peer_id, state_min);
4426 std::string Server::getPlayerName(u16 peer_id)
4428 Player *player = m_env->getPlayer(peer_id);
4430 return "[id="+itos(peer_id)+"]";
4431 return player->getName();
4434 PlayerSAO* Server::getPlayerSAO(u16 peer_id)
4436 Player *player = m_env->getPlayer(peer_id);
4439 return player->getPlayerSAO();
4442 std::wstring Server::getStatusString()
4444 std::wostringstream os(std::ios_base::binary);
4447 os<<L"version="<<narrow_to_wide(minetest_version_simple);
4449 os<<L", uptime="<<m_uptime.get();
4451 os<<L", max_lag="<<m_env->getMaxLagEstimate();
4452 // Information about clients
4455 std::list<u16> clients = m_clients.getClientIDs();
4456 for(std::list<u16>::iterator i = clients.begin();
4457 i != clients.end(); ++i)
4460 Player *player = m_env->getPlayer(*i);
4461 // Get name of player
4462 std::wstring name = L"unknown";
4464 name = narrow_to_wide(player->getName());
4465 // Add name to information string
4473 if(((ServerMap*)(&m_env->getMap()))->isSavingEnabled() == false)
4474 os<<std::endl<<L"# Server: "<<" WARNING: Map saving is disabled.";
4475 if(g_settings->get("motd") != "")
4476 os<<std::endl<<L"# Server: "<<narrow_to_wide(g_settings->get("motd"));
4480 std::set<std::string> Server::getPlayerEffectivePrivs(const std::string &name)
4482 std::set<std::string> privs;
4483 m_script->getAuth(name, NULL, &privs);
4487 bool Server::checkPriv(const std::string &name, const std::string &priv)
4489 std::set<std::string> privs = getPlayerEffectivePrivs(name);
4490 return (privs.count(priv) != 0);
4493 void Server::reportPrivsModified(const std::string &name)
4496 std::list<u16> clients = m_clients.getClientIDs();
4497 for(std::list<u16>::iterator
4498 i = clients.begin();
4499 i != clients.end(); ++i){
4500 Player *player = m_env->getPlayer(*i);
4501 reportPrivsModified(player->getName());
4504 Player *player = m_env->getPlayer(name.c_str());
4507 SendPlayerPrivileges(player->peer_id);
4508 PlayerSAO *sao = player->getPlayerSAO();
4511 sao->updatePrivileges(
4512 getPlayerEffectivePrivs(name),
4517 void Server::reportInventoryFormspecModified(const std::string &name)
4519 Player *player = m_env->getPlayer(name.c_str());
4522 SendPlayerInventoryFormspec(player->peer_id);
4525 void Server::setIpBanned(const std::string &ip, const std::string &name)
4527 m_banmanager->add(ip, name);
4530 void Server::unsetIpBanned(const std::string &ip_or_name)
4532 m_banmanager->remove(ip_or_name);
4535 std::string Server::getBanDescription(const std::string &ip_or_name)
4537 return m_banmanager->getBanDescription(ip_or_name);
4540 void Server::notifyPlayer(const char *name, const std::wstring &msg)
4542 Player *player = m_env->getPlayer(name);
4546 if (player->peer_id == PEER_ID_INEXISTENT)
4549 SendChatMessage(player->peer_id, msg);
4552 bool Server::showFormspec(const char *playername, const std::string &formspec, const std::string &formname)
4554 Player *player = m_env->getPlayer(playername);
4558 infostream<<"showFormspec: couldn't find player:"<<playername<<std::endl;
4562 SendShowFormspecMessage(player->peer_id, formspec, formname);
4566 u32 Server::hudAdd(Player *player, HudElement *form) {
4570 u32 id = player->addHud(form);
4572 SendHUDAdd(player->peer_id, id, form);
4577 bool Server::hudRemove(Player *player, u32 id) {
4581 HudElement* todel = player->removeHud(id);
4588 SendHUDRemove(player->peer_id, id);
4592 bool Server::hudChange(Player *player, u32 id, HudElementStat stat, void *data) {
4596 SendHUDChange(player->peer_id, id, stat, data);
4600 bool Server::hudSetFlags(Player *player, u32 flags, u32 mask) {
4604 SendHUDSetFlags(player->peer_id, flags, mask);
4605 player->hud_flags = flags;
4607 PlayerSAO* playersao = player->getPlayerSAO();
4609 if (playersao == NULL)
4612 m_script->player_event(playersao, "hud_changed");
4616 bool Server::hudSetHotbarItemcount(Player *player, s32 hotbar_itemcount) {
4619 if (hotbar_itemcount <= 0 || hotbar_itemcount > HUD_HOTBAR_ITEMCOUNT_MAX)
4622 std::ostringstream os(std::ios::binary);
4623 writeS32(os, hotbar_itemcount);
4624 SendHUDSetParam(player->peer_id, HUD_PARAM_HOTBAR_ITEMCOUNT, os.str());
4628 void Server::hudSetHotbarImage(Player *player, std::string name) {
4632 SendHUDSetParam(player->peer_id, HUD_PARAM_HOTBAR_IMAGE, name);
4635 void Server::hudSetHotbarSelectedImage(Player *player, std::string name) {
4639 SendHUDSetParam(player->peer_id, HUD_PARAM_HOTBAR_SELECTED_IMAGE, name);
4642 bool Server::setLocalPlayerAnimations(Player *player, v2s32 animation_frames[4], f32 frame_speed)
4647 SendLocalPlayerAnimations(player->peer_id, animation_frames, frame_speed);
4651 bool Server::setPlayerEyeOffset(Player *player, v3f first, v3f third)
4656 SendEyeOffset(player->peer_id, first, third);
4660 bool Server::setSky(Player *player, const video::SColor &bgcolor,
4661 const std::string &type, const std::vector<std::string> ¶ms)
4666 SendSetSky(player->peer_id, bgcolor, type, params);
4670 bool Server::overrideDayNightRatio(Player *player, bool do_override,
4676 SendOverrideDayNightRatio(player->peer_id, do_override, ratio);
4680 void Server::notifyPlayers(const std::wstring &msg)
4682 SendChatMessage(PEER_ID_INEXISTENT,msg);
4685 void Server::spawnParticle(const char *playername, v3f pos,
4686 v3f velocity, v3f acceleration,
4687 float expirationtime, float size, bool
4688 collisiondetection, bool vertical, std::string texture)
4690 Player *player = m_env->getPlayer(playername);
4693 SendSpawnParticle(player->peer_id, pos, velocity, acceleration,
4694 expirationtime, size, collisiondetection, vertical, texture);
4697 void Server::spawnParticleAll(v3f pos, v3f velocity, v3f acceleration,
4698 float expirationtime, float size,
4699 bool collisiondetection, bool vertical, std::string texture)
4701 SendSpawnParticle(PEER_ID_INEXISTENT,pos, velocity, acceleration,
4702 expirationtime, size, collisiondetection, vertical, texture);
4705 u32 Server::addParticleSpawner(const char *playername,
4706 u16 amount, float spawntime,
4707 v3f minpos, v3f maxpos,
4708 v3f minvel, v3f maxvel,
4709 v3f minacc, v3f maxacc,
4710 float minexptime, float maxexptime,
4711 float minsize, float maxsize,
4712 bool collisiondetection, bool vertical, std::string texture)
4714 Player *player = m_env->getPlayer(playername);
4719 for(;;) // look for unused particlespawner id
4722 if (std::find(m_particlespawner_ids.begin(),
4723 m_particlespawner_ids.end(), id)
4724 == m_particlespawner_ids.end())
4726 m_particlespawner_ids.push_back(id);
4731 SendAddParticleSpawner(player->peer_id, amount, spawntime,
4732 minpos, maxpos, minvel, maxvel, minacc, maxacc,
4733 minexptime, maxexptime, minsize, maxsize,
4734 collisiondetection, vertical, texture, id);
4739 u32 Server::addParticleSpawnerAll(u16 amount, float spawntime,
4740 v3f minpos, v3f maxpos,
4741 v3f minvel, v3f maxvel,
4742 v3f minacc, v3f maxacc,
4743 float minexptime, float maxexptime,
4744 float minsize, float maxsize,
4745 bool collisiondetection, bool vertical, std::string texture)
4748 for(;;) // look for unused particlespawner id
4751 if (std::find(m_particlespawner_ids.begin(),
4752 m_particlespawner_ids.end(), id)
4753 == m_particlespawner_ids.end())
4755 m_particlespawner_ids.push_back(id);
4760 SendAddParticleSpawner(PEER_ID_INEXISTENT, amount, spawntime,
4761 minpos, maxpos, minvel, maxvel, minacc, maxacc,
4762 minexptime, maxexptime, minsize, maxsize,
4763 collisiondetection, vertical, texture, id);
4768 void Server::deleteParticleSpawner(const char *playername, u32 id)
4770 Player *player = m_env->getPlayer(playername);
4774 m_particlespawner_ids.erase(
4775 std::remove(m_particlespawner_ids.begin(),
4776 m_particlespawner_ids.end(), id),
4777 m_particlespawner_ids.end());
4778 SendDeleteParticleSpawner(player->peer_id, id);
4781 void Server::deleteParticleSpawnerAll(u32 id)
4783 m_particlespawner_ids.erase(
4784 std::remove(m_particlespawner_ids.begin(),
4785 m_particlespawner_ids.end(), id),
4786 m_particlespawner_ids.end());
4787 SendDeleteParticleSpawner(PEER_ID_INEXISTENT, id);
4790 Inventory* Server::createDetachedInventory(const std::string &name)
4792 if(m_detached_inventories.count(name) > 0){
4793 infostream<<"Server clearing detached inventory \""<<name<<"\""<<std::endl;
4794 delete m_detached_inventories[name];
4796 infostream<<"Server creating detached inventory \""<<name<<"\""<<std::endl;
4798 Inventory *inv = new Inventory(m_itemdef);
4800 m_detached_inventories[name] = inv;
4801 //TODO find a better way to do this
4802 sendDetachedInventory(name,PEER_ID_INEXISTENT);
4809 BoolScopeSet(bool *dst, bool val):
4812 m_orig_state = *m_dst;
4817 *m_dst = m_orig_state;
4824 // actions: time-reversed list
4825 // Return value: success/failure
4826 bool Server::rollbackRevertActions(const std::list<RollbackAction> &actions,
4827 std::list<std::string> *log)
4829 infostream<<"Server::rollbackRevertActions(len="<<actions.size()<<")"<<std::endl;
4830 ServerMap *map = (ServerMap*)(&m_env->getMap());
4832 // Fail if no actions to handle
4833 if(actions.empty()){
4834 log->push_back("Nothing to do.");
4841 for(std::list<RollbackAction>::const_iterator
4842 i = actions.begin();
4843 i != actions.end(); i++)
4845 const RollbackAction &action = *i;
4847 bool success = action.applyRevert(map, this, this);
4850 std::ostringstream os;
4851 os<<"Revert of step ("<<num_tried<<") "<<action.toString()<<" failed";
4852 infostream<<"Map::rollbackRevertActions(): "<<os.str()<<std::endl;
4854 log->push_back(os.str());
4856 std::ostringstream os;
4857 os<<"Successfully reverted step ("<<num_tried<<") "<<action.toString();
4858 infostream<<"Map::rollbackRevertActions(): "<<os.str()<<std::endl;
4860 log->push_back(os.str());
4864 infostream<<"Map::rollbackRevertActions(): "<<num_failed<<"/"<<num_tried
4865 <<" failed"<<std::endl;
4867 // Call it done if less than half failed
4868 return num_failed <= num_tried/2;
4871 // IGameDef interface
4873 IItemDefManager* Server::getItemDefManager()
4877 INodeDefManager* Server::getNodeDefManager()
4881 ICraftDefManager* Server::getCraftDefManager()
4885 ITextureSource* Server::getTextureSource()
4889 IShaderSource* Server::getShaderSource()
4893 scene::ISceneManager* Server::getSceneManager()
4898 u16 Server::allocateUnknownNodeId(const std::string &name)
4900 return m_nodedef->allocateDummy(name);
4902 ISoundManager* Server::getSoundManager()
4904 return &dummySoundManager;
4906 MtEventManager* Server::getEventManager()
4911 IWritableItemDefManager* Server::getWritableItemDefManager()
4915 IWritableNodeDefManager* Server::getWritableNodeDefManager()
4919 IWritableCraftDefManager* Server::getWritableCraftDefManager()
4924 const ModSpec* Server::getModSpec(const std::string &modname)
4926 for(std::vector<ModSpec>::iterator i = m_mods.begin();
4927 i != m_mods.end(); i++){
4928 const ModSpec &mod = *i;
4929 if(mod.name == modname)
4934 void Server::getModNames(std::list<std::string> &modlist)
4936 for(std::vector<ModSpec>::iterator i = m_mods.begin(); i != m_mods.end(); i++)
4938 modlist.push_back(i->name);
4941 std::string Server::getBuiltinLuaPath()
4943 return porting::path_share + DIR_DELIM + "builtin";
4946 v3f findSpawnPos(ServerMap &map)
4948 //return v3f(50,50,50)*BS;
4953 nodepos = v2s16(0,0);
4958 s16 water_level = map.getWaterLevel();
4960 // Try to find a good place a few times
4961 for(s32 i=0; i<1000; i++)
4964 // We're going to try to throw the player to this position
4965 v2s16 nodepos2d = v2s16(
4966 -range + (myrand() % (range * 2)),
4967 -range + (myrand() % (range * 2)));
4969 // Get ground height at point
4970 s16 groundheight = map.findGroundLevel(nodepos2d);
4971 if (groundheight <= water_level) // Don't go underwater
4973 if (groundheight > water_level + 6) // Don't go to high places
4976 nodepos = v3s16(nodepos2d.X, groundheight, nodepos2d.Y);
4977 bool is_good = false;
4979 for (s32 i = 0; i < 10; i++) {
4980 v3s16 blockpos = getNodeBlockPos(nodepos);
4981 map.emergeBlock(blockpos, true);
4982 content_t c = map.getNodeNoEx(nodepos).getContent();
4983 if (c == CONTENT_AIR || c == CONTENT_IGNORE) {
4985 if (air_count >= 2){
4993 // Found a good place
4994 //infostream<<"Searched through "<<i<<" places."<<std::endl;
5000 return intToFloat(nodepos, BS);
5003 PlayerSAO* Server::emergePlayer(const char *name, u16 peer_id)
5005 RemotePlayer *player = NULL;
5006 bool newplayer = false;
5009 Try to get an existing player
5011 player = static_cast<RemotePlayer*>(m_env->getPlayer(name));
5013 // If player is already connected, cancel
5014 if(player != NULL && player->peer_id != 0)
5016 infostream<<"emergePlayer(): Player already connected"<<std::endl;
5021 If player with the wanted peer_id already exists, cancel.
5023 if(m_env->getPlayer(peer_id) != NULL)
5025 infostream<<"emergePlayer(): Player with wrong name but same"
5026 " peer_id already exists"<<std::endl;
5030 // Load player if it isn't already loaded
5032 player = static_cast<RemotePlayer*>(m_env->loadPlayer(name));
5035 // Create player if it doesn't exist
5038 player = new RemotePlayer(this, name);
5039 // Set player position
5040 infostream<<"Server: Finding spawn place for player \""
5041 <<name<<"\""<<std::endl;
5042 v3f pos = findSpawnPos(m_env->getServerMap());
5043 player->setPosition(pos);
5045 // Make sure the player is saved
5046 player->setModified(true);
5048 // Add player to environment
5049 m_env->addPlayer(player);
5052 // Create a new player active object
5053 PlayerSAO *playersao = new PlayerSAO(m_env, player, peer_id,
5054 getPlayerEffectivePrivs(player->getName()),
5057 /* Clean up old HUD elements from previous sessions */
5060 /* Add object to environment */
5061 m_env->addActiveObject(playersao);
5065 m_script->on_newplayer(playersao);
5071 void dedicated_server_loop(Server &server, bool &kill)
5073 DSTACK(__FUNCTION_NAME);
5075 verbosestream<<"dedicated_server_loop()"<<std::endl;
5077 IntervalLimiter m_profiler_interval;
5081 float steplen = g_settings->getFloat("dedicated_server_step");
5082 // This is kind of a hack but can be done like this
5083 // because server.step() is very light
5085 ScopeProfiler sp(g_profiler, "dedicated server sleep");
5086 sleep_ms((int)(steplen*1000.0));
5088 server.step(steplen);
5090 if(server.getShutdownRequested() || kill)
5092 infostream<<"Dedicated server quitting"<<std::endl;
5094 if(g_settings->getBool("server_announce") == true)
5095 ServerList::sendAnnounce("delete");
5103 float profiler_print_interval =
5104 g_settings->getFloat("profiler_print_interval");
5105 if(profiler_print_interval != 0)
5107 if(m_profiler_interval.step(steplen, profiler_print_interval))
5109 infostream<<"Profiler:"<<std::endl;
5110 g_profiler->print(infostream);
5111 g_profiler->clear();