3 Copyright (C) 2010-2013 celeron55, Perttu Ahola <celeron55@gmail.com>
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU Lesser General Public License as published by
7 the Free Software Foundation; either version 2.1 of the License, or
8 (at your option) any later version.
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU Lesser General Public License for more details.
15 You should have received a copy of the GNU Lesser General Public License along
16 with this program; if not, write to the Free Software Foundation, Inc.,
17 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
24 #include "clientserver.h"
26 #include "environment.h"
28 #include "jthread/jmutexautolock.h"
30 #include "constants.h"
36 #include "serverobject.h"
37 #include "genericobject.h"
41 #include "scripting_game.h"
48 #include "content_mapnode.h"
49 #include "content_nodemeta.h"
50 #include "content_abm.h"
51 #include "content_sao.h"
56 #include "sound.h" // dummySoundManager
57 #include "event_manager.h"
59 #include "serverlist.h"
60 #include "util/string.h"
61 #include "util/pointedthing.h"
62 #include "util/mathconstants.h"
64 #include "util/serialize.h"
65 #include "util/thread.h"
66 #include "defaultsettings.h"
68 class ClientNotFoundException : public BaseException
71 ClientNotFoundException(const char *s):
76 class ServerThread : public JThread
82 ServerThread(Server *server):
91 void * ServerThread::Thread()
93 log_register_thread("ServerThread");
95 DSTACK(__FUNCTION_NAME);
96 BEGIN_DEBUG_EXCEPTION_HANDLER
98 m_server->AsyncRunStep(true);
102 porting::setThreadName("ServerThread");
104 while(!StopRequested())
107 //TimeTaker timer("AsyncRunStep() + Receive()");
109 m_server->AsyncRunStep();
114 catch(con::NoIncomingDataException &e)
117 catch(con::PeerNotFoundException &e)
119 infostream<<"Server: PeerNotFoundException"<<std::endl;
121 catch(ClientNotFoundException &e)
124 catch(con::ConnectionBindFailed &e)
126 m_server->setAsyncFatalError(e.what());
130 m_server->setAsyncFatalError(e.what());
134 END_DEBUG_EXCEPTION_HANDLER(errorstream)
139 v3f ServerSoundParams::getPos(ServerEnvironment *env, bool *pos_exists) const
141 if(pos_exists) *pos_exists = false;
146 if(pos_exists) *pos_exists = true;
151 ServerActiveObject *sao = env->getActiveObject(object);
154 if(pos_exists) *pos_exists = true;
155 return sao->getBasePosition(); }
167 const std::string &path_world,
168 const SubgameSpec &gamespec,
169 bool simple_singleplayer_mode,
172 m_path_world(path_world),
173 m_gamespec(gamespec),
174 m_simple_singleplayer_mode(simple_singleplayer_mode),
175 m_async_fatal_error(""),
184 m_rollback_sink_enabled(true),
185 m_enable_rollback_recording(false),
188 m_itemdef(createItemDefManager()),
189 m_nodedef(createNodeDefManager()),
190 m_craftdef(createCraftDefManager()),
191 m_event(new EventManager()),
193 m_time_of_day_send_timer(0),
196 m_shutdown_requested(false),
197 m_ignore_map_edit_events(false),
198 m_ignore_map_edit_events_peer_id(0)
201 m_liquid_transform_timer = 0.0;
202 m_liquid_transform_every = 1.0;
203 m_print_info_timer = 0.0;
204 m_masterserver_timer = 0.0;
205 m_objectdata_timer = 0.0;
206 m_emergethread_trigger_timer = 0.0;
207 m_savemap_timer = 0.0;
210 m_lag = g_settings->getFloat("dedicated_server_step");
213 throw ServerError("Supplied empty world path");
215 if(!gamespec.isValid())
216 throw ServerError("Supplied invalid gamespec");
218 infostream<<"Server created for gameid \""<<m_gamespec.id<<"\"";
219 if(m_simple_singleplayer_mode)
220 infostream<<" in simple singleplayer mode"<<std::endl;
222 infostream<<std::endl;
223 infostream<<"- world: "<<m_path_world<<std::endl;
224 infostream<<"- game: "<<m_gamespec.path<<std::endl;
226 // Initialize default settings and override defaults with those provided
228 set_default_settings(g_settings);
229 Settings gamedefaults;
230 getGameMinetestConfig(gamespec.path, gamedefaults);
231 override_default_settings(g_settings, &gamedefaults);
233 // Create server thread
234 m_thread = new ServerThread(this);
236 // Create emerge manager
237 m_emerge = new EmergeManager(this);
239 // Create world if it doesn't exist
240 if(!initializeWorld(m_path_world, m_gamespec.id))
241 throw ServerError("Failed to initialize world");
243 // Create ban manager
244 std::string ban_path = m_path_world+DIR_DELIM+"ipban.txt";
245 m_banmanager = new BanManager(ban_path);
247 // Create rollback manager
248 std::string rollback_path = m_path_world+DIR_DELIM+"rollback.txt";
249 m_rollback = createRollbackManager(rollback_path, this);
251 ModConfiguration modconf(m_path_world);
252 m_mods = modconf.getMods();
253 std::vector<ModSpec> unsatisfied_mods = modconf.getUnsatisfiedMods();
254 // complain about mods with unsatisfied dependencies
255 if(!modconf.isConsistent())
257 for(std::vector<ModSpec>::iterator it = unsatisfied_mods.begin();
258 it != unsatisfied_mods.end(); ++it)
261 errorstream << "mod \"" << mod.name << "\" has unsatisfied dependencies: ";
262 for(std::set<std::string>::iterator dep_it = mod.unsatisfied_depends.begin();
263 dep_it != mod.unsatisfied_depends.end(); ++dep_it)
264 errorstream << " \"" << *dep_it << "\"";
265 errorstream << std::endl;
269 Settings worldmt_settings;
270 std::string worldmt = m_path_world + DIR_DELIM + "world.mt";
271 worldmt_settings.readConfigFile(worldmt.c_str());
272 std::vector<std::string> names = worldmt_settings.getNames();
273 std::set<std::string> load_mod_names;
274 for(std::vector<std::string>::iterator it = names.begin();
275 it != names.end(); ++it)
277 std::string name = *it;
278 if(name.compare(0,9,"load_mod_")==0 && worldmt_settings.getBool(name))
279 load_mod_names.insert(name.substr(9));
281 // complain about mods declared to be loaded, but not found
282 for(std::vector<ModSpec>::iterator it = m_mods.begin();
283 it != m_mods.end(); ++it)
284 load_mod_names.erase((*it).name);
285 for(std::vector<ModSpec>::iterator it = unsatisfied_mods.begin();
286 it != unsatisfied_mods.end(); ++it)
287 load_mod_names.erase((*it).name);
288 if(!load_mod_names.empty())
290 errorstream << "The following mods could not be found:";
291 for(std::set<std::string>::iterator it = load_mod_names.begin();
292 it != load_mod_names.end(); ++it)
293 errorstream << " \"" << (*it) << "\"";
294 errorstream << std::endl;
298 JMutexAutoLock envlock(m_env_mutex);
300 // Initialize scripting
301 infostream<<"Server: Initializing Lua"<<std::endl;
303 m_script = new GameScripting(this);
305 std::string scriptpath = getBuiltinLuaPath() + DIR_DELIM "init.lua";
307 if (!m_script->loadScript(scriptpath)) {
308 throw ModError("Failed to load and run " + scriptpath);
313 infostream<<"Server: Loading mods: ";
314 for(std::vector<ModSpec>::iterator i = m_mods.begin();
315 i != m_mods.end(); i++){
316 const ModSpec &mod = *i;
317 infostream<<mod.name<<" ";
319 infostream<<std::endl;
320 // Load and run "mod" scripts
321 for(std::vector<ModSpec>::iterator i = m_mods.begin();
322 i != m_mods.end(); i++){
323 const ModSpec &mod = *i;
324 std::string scriptpath = mod.path + DIR_DELIM + "init.lua";
325 infostream<<" ["<<padStringRight(mod.name, 12)<<"] [\""
326 <<scriptpath<<"\"]"<<std::endl;
327 bool success = m_script->loadMod(scriptpath, mod.name);
329 errorstream<<"Server: Failed to load and run "
330 <<scriptpath<<std::endl;
331 throw ModError("Failed to load and run "+scriptpath);
335 // Read Textures and calculate sha1 sums
338 // Apply item aliases in the node definition manager
339 m_nodedef->updateAliases(m_itemdef);
341 // Load the mapgen params from global settings now after any
342 // initial overrides have been set by the mods
343 m_emerge->loadMapgenParams();
345 // Initialize Environment
346 ServerMap *servermap = new ServerMap(path_world, this, m_emerge);
347 m_env = new ServerEnvironment(servermap, m_script, this, m_path_world);
349 m_clients.setEnv(m_env);
351 // Run some callbacks after the MG params have been set up but before activation
352 m_script->environment_OnMapgenInit(&m_emerge->params);
354 // Initialize mapgens
355 m_emerge->initMapgens();
357 // Give environment reference to scripting api
358 m_script->initializeEnvironment(m_env);
360 // Register us to receive map edit events
361 servermap->addEventReceiver(this);
363 // If file exists, load environment metadata
364 if(fs::PathExists(m_path_world + DIR_DELIM "env_meta.txt"))
366 infostream<<"Server: Loading environment metadata"<<std::endl;
370 // Add some test ActiveBlockModifiers to environment
371 add_legacy_abms(m_env, m_nodedef);
373 m_liquid_transform_every = g_settings->getFloat("liquid_update");
378 infostream<<"Server destructing"<<std::endl;
380 // Send shutdown message
381 SendChatMessage(PEER_ID_INEXISTENT, L"*** Server shutting down");
384 JMutexAutoLock envlock(m_env_mutex);
386 // Execute script shutdown hooks
387 m_script->on_shutdown();
389 infostream<<"Server: Saving players"<<std::endl;
390 m_env->saveLoadedPlayers();
392 infostream<<"Server: Saving environment metadata"<<std::endl;
400 // stop all emerge threads before deleting players that may have
401 // requested blocks to be emerged
402 m_emerge->stopThreads();
404 // Delete things in the reverse order of creation
407 // N.B. the EmergeManager should be deleted after the Environment since Map
408 // depends on EmergeManager to write its current params to the map meta
417 // Deinitialize scripting
418 infostream<<"Server: Deinitializing scripting"<<std::endl;
421 // Delete detached inventories
422 for (std::map<std::string, Inventory*>::iterator
423 i = m_detached_inventories.begin();
424 i != m_detached_inventories.end(); i++) {
429 void Server::start(Address bind_addr)
431 DSTACK(__FUNCTION_NAME);
432 infostream<<"Starting server on "
433 << bind_addr.serializeString() <<"..."<<std::endl;
435 // Stop thread if already running
438 // Initialize connection
439 m_con.SetTimeoutMs(30);
440 m_con.Serve(bind_addr);
445 // ASCII art for the win!
447 <<" .__ __ __ "<<std::endl
448 <<" _____ |__| ____ _____/ |_ ____ _______/ |_ "<<std::endl
449 <<" / \\| |/ \\_/ __ \\ __\\/ __ \\ / ___/\\ __\\"<<std::endl
450 <<"| Y Y \\ | | \\ ___/| | \\ ___/ \\___ \\ | | "<<std::endl
451 <<"|__|_| /__|___| /\\___ >__| \\___ >____ > |__| "<<std::endl
452 <<" \\/ \\/ \\/ \\/ \\/ "<<std::endl;
453 actionstream<<"World at ["<<m_path_world<<"]"<<std::endl;
454 actionstream<<"Server for gameid=\""<<m_gamespec.id
455 <<"\" listening on "<<bind_addr.serializeString()<<":"
456 <<bind_addr.getPort() << "."<<std::endl;
461 DSTACK(__FUNCTION_NAME);
463 infostream<<"Server: Stopping and waiting threads"<<std::endl;
465 // Stop threads (set run=false first so both start stopping)
467 //m_emergethread.setRun(false);
469 //m_emergethread.stop();
471 infostream<<"Server: Threads stopped"<<std::endl;
474 void Server::step(float dtime)
476 DSTACK(__FUNCTION_NAME);
481 JMutexAutoLock lock(m_step_dtime_mutex);
482 m_step_dtime += dtime;
484 // Throw if fatal error occurred in thread
485 std::string async_err = m_async_fatal_error.get();
487 throw ServerError(async_err);
491 void Server::AsyncRunStep(bool initial_step)
493 DSTACK(__FUNCTION_NAME);
495 g_profiler->add("Server::AsyncRunStep (num)", 1);
499 JMutexAutoLock lock1(m_step_dtime_mutex);
500 dtime = m_step_dtime;
504 // Send blocks to clients
508 if((dtime < 0.001) && (initial_step == false))
511 g_profiler->add("Server::AsyncRunStep with dtime (num)", 1);
513 //infostream<<"Server steps "<<dtime<<std::endl;
514 //infostream<<"Server::AsyncRunStep(): dtime="<<dtime<<std::endl;
517 JMutexAutoLock lock1(m_step_dtime_mutex);
518 m_step_dtime -= dtime;
525 m_uptime.set(m_uptime.get() + dtime);
531 Update time of day and overall game time
534 JMutexAutoLock envlock(m_env_mutex);
536 m_env->setTimeOfDaySpeed(g_settings->getFloat("time_speed"));
539 Send to clients at constant intervals
542 m_time_of_day_send_timer -= dtime;
543 if(m_time_of_day_send_timer < 0.0)
545 m_time_of_day_send_timer = g_settings->getFloat("time_send_interval");
546 u16 time = m_env->getTimeOfDay();
547 float time_speed = g_settings->getFloat("time_speed");
548 SendTimeOfDay(PEER_ID_INEXISTENT, time, time_speed);
553 JMutexAutoLock lock(m_env_mutex);
554 // Figure out and report maximum lag to environment
555 float max_lag = m_env->getMaxLagEstimate();
556 max_lag *= 0.9998; // Decrease slowly (about half per 5 minutes)
558 if(dtime > 0.1 && dtime > max_lag * 2.0)
559 infostream<<"Server: Maximum lag peaked to "<<dtime
563 m_env->reportMaxLagEstimate(max_lag);
565 ScopeProfiler sp(g_profiler, "SEnv step");
566 ScopeProfiler sp2(g_profiler, "SEnv step avg", SPT_AVG);
570 const float map_timer_and_unload_dtime = 2.92;
571 if(m_map_timer_and_unload_interval.step(dtime, map_timer_and_unload_dtime))
573 JMutexAutoLock lock(m_env_mutex);
574 // Run Map's timers and unload unused data
575 ScopeProfiler sp(g_profiler, "Server: map timer and unload");
576 m_env->getMap().timerUpdate(map_timer_and_unload_dtime,
577 g_settings->getFloat("server_unload_unused_data_timeout"));
588 JMutexAutoLock lock(m_env_mutex);
590 std::list<u16> clientids = m_clients.getClientIDs();
592 ScopeProfiler sp(g_profiler, "Server: handle players");
594 for(std::list<u16>::iterator
595 i = clientids.begin();
596 i != clientids.end(); ++i)
598 PlayerSAO *playersao = getPlayerSAO(*i);
599 if(playersao == NULL)
603 Handle player HPs (die if hp=0)
605 if(playersao->m_hp_not_sent && g_settings->getBool("enable_damage"))
607 if(playersao->getHP() == 0)
614 Send player breath if changed
616 if(playersao->m_breath_not_sent) {
617 SendPlayerBreath(*i);
621 Send player inventories if necessary
623 if(playersao->m_moved){
625 playersao->m_moved = false;
627 if(playersao->m_inventory_not_sent){
634 /* Transform liquids */
635 m_liquid_transform_timer += dtime;
636 if(m_liquid_transform_timer >= m_liquid_transform_every)
638 m_liquid_transform_timer -= m_liquid_transform_every;
640 JMutexAutoLock lock(m_env_mutex);
642 ScopeProfiler sp(g_profiler, "Server: liquid transform");
644 std::map<v3s16, MapBlock*> modified_blocks;
645 m_env->getMap().transformLiquids(modified_blocks);
650 core::map<v3s16, MapBlock*> lighting_modified_blocks;
651 ServerMap &map = ((ServerMap&)m_env->getMap());
652 map.updateLighting(modified_blocks, lighting_modified_blocks);
654 // Add blocks modified by lighting to modified_blocks
655 for(core::map<v3s16, MapBlock*>::Iterator
656 i = lighting_modified_blocks.getIterator();
657 i.atEnd() == false; i++)
659 MapBlock *block = i.getNode()->getValue();
660 modified_blocks.insert(block->getPos(), block);
664 Set the modified blocks unsent for all the clients
666 if(modified_blocks.size() > 0)
668 SetBlocksNotSent(modified_blocks);
671 m_clients.step(dtime);
673 m_lag += (m_lag > dtime ? -1 : 1) * dtime/100;
675 // send masterserver announce
677 float &counter = m_masterserver_timer;
678 if(!isSingleplayer() && (!counter || counter >= 300.0) &&
679 g_settings->getBool("server_announce"))
681 ServerList::sendAnnounce(counter ? "update" : "start",
682 m_clients.getPlayerNames(),
684 m_env->getGameTime(),
695 Check added and deleted active objects
698 //infostream<<"Server: Checking added and deleted active objects"<<std::endl;
699 JMutexAutoLock envlock(m_env_mutex);
702 std::map<u16, RemoteClient*> clients = m_clients.getClientList();
703 ScopeProfiler sp(g_profiler, "Server: checking added and deleted objs");
705 // Radius inside which objects are active
706 s16 radius = g_settings->getS16("active_object_send_range_blocks");
707 radius *= MAP_BLOCKSIZE;
709 for(std::map<u16, RemoteClient*>::iterator
711 i != clients.end(); ++i)
713 RemoteClient *client = i->second;
715 // If definitions and textures have not been sent, don't
716 // send objects either
717 if (client->getState() < CS_DefinitionsSent)
720 Player *player = m_env->getPlayer(client->peer_id);
723 // This can happen if the client timeouts somehow
724 /*infostream<<"WARNING: "<<__FUNCTION_NAME<<": Client "
726 <<" has no associated player"<<std::endl;*/
729 v3s16 pos = floatToInt(player->getPosition(), BS);
731 std::set<u16> removed_objects;
732 std::set<u16> added_objects;
733 m_env->getRemovedActiveObjects(pos, radius,
734 client->m_known_objects, removed_objects);
735 m_env->getAddedActiveObjects(pos, radius,
736 client->m_known_objects, added_objects);
738 // Ignore if nothing happened
739 if(removed_objects.size() == 0 && added_objects.size() == 0)
741 //infostream<<"active objects: none changed"<<std::endl;
745 std::string data_buffer;
749 // Handle removed objects
750 writeU16((u8*)buf, removed_objects.size());
751 data_buffer.append(buf, 2);
752 for(std::set<u16>::iterator
753 i = removed_objects.begin();
754 i != removed_objects.end(); ++i)
758 ServerActiveObject* obj = m_env->getActiveObject(id);
760 // Add to data buffer for sending
761 writeU16((u8*)buf, id);
762 data_buffer.append(buf, 2);
764 // Remove from known objects
765 client->m_known_objects.erase(id);
767 if(obj && obj->m_known_by_count > 0)
768 obj->m_known_by_count--;
771 // Handle added objects
772 writeU16((u8*)buf, added_objects.size());
773 data_buffer.append(buf, 2);
774 for(std::set<u16>::iterator
775 i = added_objects.begin();
776 i != added_objects.end(); ++i)
780 ServerActiveObject* obj = m_env->getActiveObject(id);
783 u8 type = ACTIVEOBJECT_TYPE_INVALID;
785 infostream<<"WARNING: "<<__FUNCTION_NAME
786 <<": NULL object"<<std::endl;
788 type = obj->getSendType();
790 // Add to data buffer for sending
791 writeU16((u8*)buf, id);
792 data_buffer.append(buf, 2);
793 writeU8((u8*)buf, type);
794 data_buffer.append(buf, 1);
797 data_buffer.append(serializeLongString(
798 obj->getClientInitializationData(client->net_proto_version)));
800 data_buffer.append(serializeLongString(""));
802 // Add to known objects
803 client->m_known_objects.insert(id);
806 obj->m_known_by_count++;
810 SharedBuffer<u8> reply(2 + data_buffer.size());
811 writeU16(&reply[0], TOCLIENT_ACTIVE_OBJECT_REMOVE_ADD);
812 memcpy((char*)&reply[2], data_buffer.c_str(),
815 m_clients.send(client->peer_id, 0, reply, true);
817 verbosestream<<"Server: Sent object remove/add: "
818 <<removed_objects.size()<<" removed, "
819 <<added_objects.size()<<" added, "
820 <<"packet size is "<<reply.getSize()<<std::endl;
825 Collect a list of all the objects known by the clients
826 and report it back to the environment.
829 core::map<u16, bool> all_known_objects;
831 for(core::map<u16, RemoteClient*>::Iterator
832 i = m_clients.getIterator();
833 i.atEnd() == false; i++)
835 RemoteClient *client = i.getNode()->getValue();
836 // Go through all known objects of client
837 for(core::map<u16, bool>::Iterator
838 i = client->m_known_objects.getIterator();
839 i.atEnd()==false; i++)
841 u16 id = i.getNode()->getKey();
842 all_known_objects[id] = true;
846 m_env->setKnownActiveObjects(whatever);
855 JMutexAutoLock envlock(m_env_mutex);
856 ScopeProfiler sp(g_profiler, "Server: sending object messages");
859 // Value = data sent by object
860 std::map<u16, std::list<ActiveObjectMessage>* > buffered_messages;
862 // Get active object messages from environment
865 ActiveObjectMessage aom = m_env->getActiveObjectMessage();
869 std::list<ActiveObjectMessage>* message_list = NULL;
870 std::map<u16, std::list<ActiveObjectMessage>* >::iterator n;
871 n = buffered_messages.find(aom.id);
872 if(n == buffered_messages.end())
874 message_list = new std::list<ActiveObjectMessage>;
875 buffered_messages[aom.id] = message_list;
879 message_list = n->second;
881 message_list->push_back(aom);
885 std::map<u16, RemoteClient*> clients = m_clients.getClientList();
886 // Route data to every client
887 for(std::map<u16, RemoteClient*>::iterator
889 i != clients.end(); ++i)
891 RemoteClient *client = i->second;
892 std::string reliable_data;
893 std::string unreliable_data;
894 // Go through all objects in message buffer
895 for(std::map<u16, std::list<ActiveObjectMessage>* >::iterator
896 j = buffered_messages.begin();
897 j != buffered_messages.end(); ++j)
899 // If object is not known by client, skip it
901 if(client->m_known_objects.find(id) == client->m_known_objects.end())
903 // Get message list of object
904 std::list<ActiveObjectMessage>* list = j->second;
905 // Go through every message
906 for(std::list<ActiveObjectMessage>::iterator
907 k = list->begin(); k != list->end(); ++k)
909 // Compose the full new data with header
910 ActiveObjectMessage aom = *k;
911 std::string new_data;
914 writeU16((u8*)&buf[0], aom.id);
915 new_data.append(buf, 2);
917 new_data += serializeString(aom.datastring);
918 // Add data to buffer
920 reliable_data += new_data;
922 unreliable_data += new_data;
926 reliable_data and unreliable_data are now ready.
929 if(reliable_data.size() > 0)
931 SharedBuffer<u8> reply(2 + reliable_data.size());
932 writeU16(&reply[0], TOCLIENT_ACTIVE_OBJECT_MESSAGES);
933 memcpy((char*)&reply[2], reliable_data.c_str(),
934 reliable_data.size());
936 m_clients.send(client->peer_id, 0, reply, true);
938 if(unreliable_data.size() > 0)
940 SharedBuffer<u8> reply(2 + unreliable_data.size());
941 writeU16(&reply[0], TOCLIENT_ACTIVE_OBJECT_MESSAGES);
942 memcpy((char*)&reply[2], unreliable_data.c_str(),
943 unreliable_data.size());
944 // Send as unreliable
945 m_clients.send(client->peer_id, 1, reply, false);
948 /*if(reliable_data.size() > 0 || unreliable_data.size() > 0)
950 infostream<<"Server: Size of object message data: "
951 <<"reliable: "<<reliable_data.size()
952 <<", unreliable: "<<unreliable_data.size()
958 // Clear buffered_messages
959 for(std::map<u16, std::list<ActiveObjectMessage>* >::iterator
960 i = buffered_messages.begin();
961 i != buffered_messages.end(); ++i)
968 Send queued-for-sending map edit events.
971 // We will be accessing the environment
972 JMutexAutoLock lock(m_env_mutex);
974 // Don't send too many at a time
977 // Single change sending is disabled if queue size is not small
978 bool disable_single_change_sending = false;
979 if(m_unsent_map_edit_queue.size() >= 4)
980 disable_single_change_sending = true;
982 int event_count = m_unsent_map_edit_queue.size();
984 // We'll log the amount of each
987 while(m_unsent_map_edit_queue.size() != 0)
989 MapEditEvent* event = m_unsent_map_edit_queue.pop_front();
991 // Players far away from the change are stored here.
992 // Instead of sending the changes, MapBlocks are set not sent
994 std::list<u16> far_players;
996 if(event->type == MEET_ADDNODE || event->type == MEET_SWAPNODE)
998 //infostream<<"Server: MEET_ADDNODE"<<std::endl;
999 prof.add("MEET_ADDNODE", 1);
1000 if(disable_single_change_sending)
1001 sendAddNode(event->p, event->n, event->already_known_by_peer,
1002 &far_players, 5, event->type == MEET_ADDNODE);
1004 sendAddNode(event->p, event->n, event->already_known_by_peer,
1005 &far_players, 30, event->type == MEET_ADDNODE);
1007 else if(event->type == MEET_REMOVENODE)
1009 //infostream<<"Server: MEET_REMOVENODE"<<std::endl;
1010 prof.add("MEET_REMOVENODE", 1);
1011 if(disable_single_change_sending)
1012 sendRemoveNode(event->p, event->already_known_by_peer,
1015 sendRemoveNode(event->p, event->already_known_by_peer,
1018 else if(event->type == MEET_BLOCK_NODE_METADATA_CHANGED)
1020 infostream<<"Server: MEET_BLOCK_NODE_METADATA_CHANGED"<<std::endl;
1021 prof.add("MEET_BLOCK_NODE_METADATA_CHANGED", 1);
1022 setBlockNotSent(event->p);
1024 else if(event->type == MEET_OTHER)
1026 infostream<<"Server: MEET_OTHER"<<std::endl;
1027 prof.add("MEET_OTHER", 1);
1028 for(std::set<v3s16>::iterator
1029 i = event->modified_blocks.begin();
1030 i != event->modified_blocks.end(); ++i)
1032 setBlockNotSent(*i);
1037 prof.add("unknown", 1);
1038 infostream<<"WARNING: Server: Unknown MapEditEvent "
1039 <<((u32)event->type)<<std::endl;
1043 Set blocks not sent to far players
1045 if(far_players.size() > 0)
1047 // Convert list format to that wanted by SetBlocksNotSent
1048 std::map<v3s16, MapBlock*> modified_blocks2;
1049 for(std::set<v3s16>::iterator
1050 i = event->modified_blocks.begin();
1051 i != event->modified_blocks.end(); ++i)
1053 modified_blocks2[*i] =
1054 m_env->getMap().getBlockNoCreateNoEx(*i);
1056 // Set blocks not sent
1057 for(std::list<u16>::iterator
1058 i = far_players.begin();
1059 i != far_players.end(); ++i)
1062 RemoteClient *client = getClient(peer_id);
1065 client->SetBlocksNotSent(modified_blocks2);
1071 /*// Don't send too many at a time
1073 if(count >= 1 && m_unsent_map_edit_queue.size() < 100)
1077 if(event_count >= 5){
1078 infostream<<"Server: MapEditEvents:"<<std::endl;
1079 prof.print(infostream);
1080 } else if(event_count != 0){
1081 verbosestream<<"Server: MapEditEvents:"<<std::endl;
1082 prof.print(verbosestream);
1088 Trigger emergethread (it somehow gets to a non-triggered but
1089 bysy state sometimes)
1092 float &counter = m_emergethread_trigger_timer;
1098 m_emerge->startThreads();
1100 // Update m_enable_rollback_recording here too
1101 m_enable_rollback_recording =
1102 g_settings->getBool("enable_rollback_recording");
1106 // Save map, players and auth stuff
1108 float &counter = m_savemap_timer;
1110 if(counter >= g_settings->getFloat("server_map_save_interval"))
1113 JMutexAutoLock lock(m_env_mutex);
1115 ScopeProfiler sp(g_profiler, "Server: saving stuff");
1118 if (m_banmanager->isModified()) {
1119 m_banmanager->save();
1122 // Save changed parts of map
1123 m_env->getMap().save(MOD_STATE_WRITE_NEEDED);
1126 m_env->saveLoadedPlayers();
1128 // Save environment metadata
1134 void Server::Receive()
1136 DSTACK(__FUNCTION_NAME);
1137 SharedBuffer<u8> data;
1141 datasize = m_con.Receive(peer_id,data);
1142 ProcessData(*data, datasize, peer_id);
1144 catch(con::InvalidIncomingDataException &e)
1146 infostream<<"Server::Receive(): "
1147 "InvalidIncomingDataException: what()="
1148 <<e.what()<<std::endl;
1150 catch(SerializationError &e) {
1151 infostream<<"Server::Receive(): "
1152 "SerializationError: what()="
1153 <<e.what()<<std::endl;
1155 catch(ClientStateError &e)
1157 errorstream << "ProcessData: peer=" << peer_id << e.what() << std::endl;
1158 DenyAccess(peer_id, L"Your client sent something server didn't expect."
1159 L"Try reconnecting or updating your client");
1161 catch(con::PeerNotFoundException &e)
1167 PlayerSAO* Server::StageTwoClientInit(u16 peer_id)
1169 std::string playername = "";
1170 PlayerSAO *playersao = NULL;
1172 RemoteClient* client = m_clients.lockedGetClientNoEx(peer_id, CS_InitDone);
1173 if (client != NULL) {
1174 playername = client->getName();
1175 playersao = emergePlayer(playername.c_str(), peer_id);
1179 RemotePlayer *player =
1180 static_cast<RemotePlayer*>(m_env->getPlayer(playername.c_str()));
1182 // If failed, cancel
1183 if((playersao == NULL) || (player == NULL))
1185 if(player && player->peer_id != 0){
1186 errorstream<<"Server: "<<playername<<": Failed to emerge player"
1187 <<" (player allocated to an another client)"<<std::endl;
1188 DenyAccess(peer_id, L"Another client is connected with this "
1189 L"name. If your client closed unexpectedly, try again in "
1192 errorstream<<"Server: "<<playername<<": Failed to emerge player"
1194 DenyAccess(peer_id, L"Could not allocate player.");
1200 Send complete position information
1202 SendMovePlayer(peer_id);
1205 SendPlayerPrivileges(peer_id);
1207 // Send inventory formspec
1208 SendPlayerInventoryFormspec(peer_id);
1211 UpdateCrafting(peer_id);
1212 SendInventory(peer_id);
1215 if(g_settings->getBool("enable_damage"))
1216 SendPlayerHP(peer_id);
1219 SendPlayerBreath(peer_id);
1221 // Show death screen if necessary
1223 SendDeathscreen(peer_id, false, v3f(0,0,0));
1225 // Note things in chat if not in simple singleplayer mode
1226 if(!m_simple_singleplayer_mode)
1228 // Send information about server to player in chat
1229 SendChatMessage(peer_id, getStatusString());
1231 // Send information about joining in chat
1233 std::wstring name = L"unknown";
1234 Player *player = m_env->getPlayer(peer_id);
1236 name = narrow_to_wide(player->getName());
1238 std::wstring message;
1241 message += L" joined the game.";
1242 SendChatMessage(PEER_ID_INEXISTENT,message);
1245 Address addr = getPeerAddress(player->peer_id);
1246 std::string ip_str = addr.serializeString();
1247 actionstream<<player->getName() <<" [" << ip_str << "] joins game. " << std::endl;
1252 std::vector<std::string> names = m_clients.getPlayerNames();
1254 actionstream<<player->getName() <<" joins game. List of players: ";
1256 for (std::vector<std::string>::iterator i = names.begin();
1257 i != names.end(); i++)
1259 actionstream << *i << " ";
1262 actionstream << player->getName() <<std::endl;
1267 void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
1269 DSTACK(__FUNCTION_NAME);
1270 // Environment is locked first.
1271 JMutexAutoLock envlock(m_env_mutex);
1273 ScopeProfiler sp(g_profiler, "Server::ProcessData");
1277 Address address = getPeerAddress(peer_id);
1278 addr_s = address.serializeString();
1280 // drop player if is ip is banned
1281 if(m_banmanager->isIpBanned(addr_s)){
1282 std::string ban_name = m_banmanager->getBanName(addr_s);
1283 infostream<<"Server: A banned client tried to connect from "
1284 <<addr_s<<"; banned name was "
1285 <<ban_name<<std::endl;
1286 // This actually doesn't seem to transfer to the client
1287 DenyAccess(peer_id, L"Your ip is banned. Banned name was "
1288 +narrow_to_wide(ban_name));
1292 catch(con::PeerNotFoundException &e)
1295 * no peer for this packet found
1296 * most common reason is peer timeout, e.g. peer didn't
1297 * respond for some time, your server was overloaded or
1300 infostream<<"Server::ProcessData(): Cancelling: peer "
1301 <<peer_id<<" not found"<<std::endl;
1311 ToServerCommand command = (ToServerCommand)readU16(&data[0]);
1313 if(command == TOSERVER_INIT)
1315 // [0] u16 TOSERVER_INIT
1316 // [2] u8 SER_FMT_VER_HIGHEST_READ
1317 // [3] u8[20] player_name
1318 // [23] u8[28] password <--- can be sent without this, from old versions
1320 if(datasize < 2+1+PLAYERNAME_SIZE)
1323 RemoteClient* client = getClient(peer_id, CS_Created);
1325 // If net_proto_version is set, this client has already been handled
1326 if(client->getState() > CS_Created)
1328 verbosestream<<"Server: Ignoring multiple TOSERVER_INITs from "
1329 <<addr_s<<" (peer_id="<<peer_id<<")"<<std::endl;
1333 verbosestream<<"Server: Got TOSERVER_INIT from "<<addr_s<<" (peer_id="
1334 <<peer_id<<")"<<std::endl;
1336 // Do not allow multiple players in simple singleplayer mode.
1337 // This isn't a perfect way to do it, but will suffice for now
1338 if(m_simple_singleplayer_mode && m_clients.getClientIDs().size() > 1){
1339 infostream<<"Server: Not allowing another client ("<<addr_s
1340 <<") to connect in simple singleplayer mode"<<std::endl;
1341 DenyAccess(peer_id, L"Running in simple singleplayer mode.");
1345 // First byte after command is maximum supported
1346 // serialization version
1347 u8 client_max = data[2];
1348 u8 our_max = SER_FMT_VER_HIGHEST_READ;
1349 // Use the highest version supported by both
1350 u8 deployed = std::min(client_max, our_max);
1351 // If it's lower than the lowest supported, give up.
1352 if(deployed < SER_FMT_VER_LOWEST)
1353 deployed = SER_FMT_VER_INVALID;
1355 if(deployed == SER_FMT_VER_INVALID)
1357 actionstream<<"Server: A mismatched client tried to connect from "
1358 <<addr_s<<std::endl;
1359 infostream<<"Server: Cannot negotiate serialization version with "
1360 <<addr_s<<std::endl;
1361 DenyAccess(peer_id, std::wstring(
1362 L"Your client's version is not supported.\n"
1363 L"Server version is ")
1364 + narrow_to_wide(minetest_version_simple) + L"."
1369 client->setPendingSerializationVersion(deployed);
1372 Read and check network protocol version
1375 u16 min_net_proto_version = 0;
1376 if(datasize >= 2+1+PLAYERNAME_SIZE+PASSWORD_SIZE+2)
1377 min_net_proto_version = readU16(&data[2+1+PLAYERNAME_SIZE+PASSWORD_SIZE]);
1379 // Use same version as minimum and maximum if maximum version field
1380 // doesn't exist (backwards compatibility)
1381 u16 max_net_proto_version = min_net_proto_version;
1382 if(datasize >= 2+1+PLAYERNAME_SIZE+PASSWORD_SIZE+2+2)
1383 max_net_proto_version = readU16(&data[2+1+PLAYERNAME_SIZE+PASSWORD_SIZE+2]);
1385 // Start with client's maximum version
1386 u16 net_proto_version = max_net_proto_version;
1388 // Figure out a working version if it is possible at all
1389 if(max_net_proto_version >= SERVER_PROTOCOL_VERSION_MIN ||
1390 min_net_proto_version <= SERVER_PROTOCOL_VERSION_MAX)
1392 // If maximum is larger than our maximum, go with our maximum
1393 if(max_net_proto_version > SERVER_PROTOCOL_VERSION_MAX)
1394 net_proto_version = SERVER_PROTOCOL_VERSION_MAX;
1395 // Else go with client's maximum
1397 net_proto_version = max_net_proto_version;
1400 verbosestream<<"Server: "<<addr_s<<": Protocol version: min: "
1401 <<min_net_proto_version<<", max: "<<max_net_proto_version
1402 <<", chosen: "<<net_proto_version<<std::endl;
1404 client->net_proto_version = net_proto_version;
1406 if(net_proto_version < SERVER_PROTOCOL_VERSION_MIN ||
1407 net_proto_version > SERVER_PROTOCOL_VERSION_MAX)
1409 actionstream<<"Server: A mismatched client tried to connect from "
1410 <<addr_s<<std::endl;
1411 DenyAccess(peer_id, std::wstring(
1412 L"Your client's version is not supported.\n"
1413 L"Server version is ")
1414 + narrow_to_wide(minetest_version_simple) + L",\n"
1415 + L"server's PROTOCOL_VERSION is "
1416 + narrow_to_wide(itos(SERVER_PROTOCOL_VERSION_MIN))
1418 + narrow_to_wide(itos(SERVER_PROTOCOL_VERSION_MAX))
1419 + L", client's PROTOCOL_VERSION is "
1420 + narrow_to_wide(itos(min_net_proto_version))
1422 + narrow_to_wide(itos(max_net_proto_version))
1427 if(g_settings->getBool("strict_protocol_version_checking"))
1429 if(net_proto_version != LATEST_PROTOCOL_VERSION)
1431 actionstream<<"Server: A mismatched (strict) client tried to "
1432 <<"connect from "<<addr_s<<std::endl;
1433 DenyAccess(peer_id, std::wstring(
1434 L"Your client's version is not supported.\n"
1435 L"Server version is ")
1436 + narrow_to_wide(minetest_version_simple) + L",\n"
1437 + L"server's PROTOCOL_VERSION (strict) is "
1438 + narrow_to_wide(itos(LATEST_PROTOCOL_VERSION))
1439 + L", client's PROTOCOL_VERSION is "
1440 + narrow_to_wide(itos(min_net_proto_version))
1442 + narrow_to_wide(itos(max_net_proto_version))
1451 char playername[PLAYERNAME_SIZE];
1452 unsigned int playername_length = 0;
1453 for (; playername_length < PLAYERNAME_SIZE; playername_length++ ) {
1454 playername[playername_length] = data[3+playername_length];
1455 if (data[3+playername_length] == 0)
1459 if (playername_length == PLAYERNAME_SIZE) {
1460 actionstream<<"Server: Player with name exceeding max length "
1461 <<"tried to connect from "<<addr_s<<std::endl;
1462 DenyAccess(peer_id, L"Name too long");
1467 if(playername[0]=='\0')
1469 actionstream<<"Server: Player with an empty name "
1470 <<"tried to connect from "<<addr_s<<std::endl;
1471 DenyAccess(peer_id, L"Empty name");
1475 if(string_allowed(playername, PLAYERNAME_ALLOWED_CHARS)==false)
1477 actionstream<<"Server: Player with an invalid name "
1478 <<"tried to connect from "<<addr_s<<std::endl;
1479 DenyAccess(peer_id, L"Name contains unallowed characters");
1483 if(!isSingleplayer() && strcasecmp(playername, "singleplayer") == 0)
1485 actionstream<<"Server: Player with the name \"singleplayer\" "
1486 <<"tried to connect from "<<addr_s<<std::endl;
1487 DenyAccess(peer_id, L"Name is not allowed");
1493 if(m_script->on_prejoinplayer(playername, addr_s, reason))
1495 actionstream<<"Server: Player with the name \""<<playername<<"\" "
1496 <<"tried to connect from "<<addr_s<<" "
1497 <<"but it was disallowed for the following reason: "
1498 <<reason<<std::endl;
1499 DenyAccess(peer_id, narrow_to_wide(reason.c_str()));
1504 infostream<<"Server: New connection: \""<<playername<<"\" from "
1505 <<addr_s<<" (peer_id="<<peer_id<<")"<<std::endl;
1508 char given_password[PASSWORD_SIZE];
1509 if(datasize < 2+1+PLAYERNAME_SIZE+PASSWORD_SIZE)
1511 // old version - assume blank password
1512 given_password[0] = 0;
1516 for(u32 i=0; i<PASSWORD_SIZE-1; i++)
1518 given_password[i] = data[23+i];
1520 given_password[PASSWORD_SIZE-1] = 0;
1523 if(!base64_is_valid(given_password)){
1524 actionstream<<"Server: "<<playername
1525 <<" supplied invalid password hash"<<std::endl;
1526 DenyAccess(peer_id, L"Invalid password hash");
1530 // Enforce user limit.
1531 // Don't enforce for users that have some admin right
1532 if(m_clients.getClientIDs(CS_Created).size() >= g_settings->getU16("max_users") &&
1533 !checkPriv(playername, "server") &&
1534 !checkPriv(playername, "ban") &&
1535 !checkPriv(playername, "privs") &&
1536 !checkPriv(playername, "password") &&
1537 playername != g_settings->get("name"))
1539 actionstream<<"Server: "<<playername<<" tried to join, but there"
1540 <<" are already max_users="
1541 <<g_settings->getU16("max_users")<<" players."<<std::endl;
1542 DenyAccess(peer_id, L"Too many users.");
1546 std::string checkpwd; // Password hash to check against
1547 bool has_auth = m_script->getAuth(playername, &checkpwd, NULL);
1549 // If no authentication info exists for user, create it
1551 if(!isSingleplayer() &&
1552 g_settings->getBool("disallow_empty_password") &&
1553 std::string(given_password) == ""){
1554 actionstream<<"Server: "<<playername
1555 <<" supplied empty password"<<std::endl;
1556 DenyAccess(peer_id, L"Empty passwords are "
1557 L"disallowed. Set a password and try again.");
1560 std::wstring raw_default_password =
1561 narrow_to_wide(g_settings->get("default_password"));
1562 std::string initial_password =
1563 translatePassword(playername, raw_default_password);
1565 // If default_password is empty, allow any initial password
1566 if (raw_default_password.length() == 0)
1567 initial_password = given_password;
1569 m_script->createAuth(playername, initial_password);
1572 has_auth = m_script->getAuth(playername, &checkpwd, NULL);
1575 actionstream<<"Server: "<<playername<<" cannot be authenticated"
1576 <<" (auth handler does not work?)"<<std::endl;
1577 DenyAccess(peer_id, L"Not allowed to login");
1581 if(given_password != checkpwd){
1582 actionstream<<"Server: "<<playername<<" supplied wrong password"
1584 DenyAccess(peer_id, L"Wrong password");
1588 RemotePlayer *player =
1589 static_cast<RemotePlayer*>(m_env->getPlayer(playername));
1591 if(player && player->peer_id != 0){
1592 errorstream<<"Server: "<<playername<<": Failed to emerge player"
1593 <<" (player allocated to an another client)"<<std::endl;
1594 DenyAccess(peer_id, L"Another client is connected with this "
1595 L"name. If your client closed unexpectedly, try again in "
1599 m_clients.setPlayerName(peer_id,playername);
1602 Answer with a TOCLIENT_INIT
1605 SharedBuffer<u8> reply(2+1+6+8+4);
1606 writeU16(&reply[0], TOCLIENT_INIT);
1607 writeU8(&reply[2], deployed);
1608 //send dummy pos for legacy reasons only
1609 writeV3S16(&reply[2+1], floatToInt(v3f(0,0,0), BS));
1610 writeU64(&reply[2+1+6], m_env->getServerMap().getSeed());
1611 writeF1000(&reply[2+1+6+8], g_settings->getFloat("dedicated_server_step"));
1614 m_clients.send(peer_id, 0, reply, true);
1615 m_clients.event(peer_id, CSE_Init);
1621 if(command == TOSERVER_INIT2)
1624 verbosestream<<"Server: Got TOSERVER_INIT2 from "
1625 <<peer_id<<std::endl;
1627 m_clients.event(peer_id, CSE_GotInit2);
1628 u16 protocol_version = m_clients.getProtocolVersion(peer_id);
1631 ///// begin compatibility code
1632 PlayerSAO* playersao = NULL;
1633 if (protocol_version <= 22) {
1634 playersao = StageTwoClientInit(peer_id);
1636 if (playersao == NULL) {
1638 << "TOSERVER_INIT2 stage 2 client init failed for peer "
1639 << peer_id << std::endl;
1643 ///// end compatibility code
1646 Send some initialization data
1649 infostream<<"Server: Sending content to "
1650 <<getPlayerName(peer_id)<<std::endl;
1652 // Send player movement settings
1653 SendMovement(peer_id);
1655 // Send item definitions
1656 SendItemDef(peer_id, m_itemdef, protocol_version);
1658 // Send node definitions
1659 SendNodeDef(peer_id, m_nodedef, protocol_version);
1661 m_clients.event(peer_id, CSE_SetDefinitionsSent);
1663 // Send media announcement
1664 sendMediaAnnouncement(peer_id);
1666 // Send detached inventories
1667 sendDetachedInventories(peer_id);
1670 u16 time = m_env->getTimeOfDay();
1671 float time_speed = g_settings->getFloat("time_speed");
1672 SendTimeOfDay(peer_id, time, time_speed);
1674 ///// begin compatibility code
1675 if (protocol_version <= 22) {
1676 m_clients.event(peer_id, CSE_SetClientReady);
1677 m_script->on_joinplayer(playersao);
1679 ///// end compatibility code
1681 // Warnings about protocol version can be issued here
1682 if(getClient(peer_id)->net_proto_version < LATEST_PROTOCOL_VERSION)
1684 SendChatMessage(peer_id, L"# Server: WARNING: YOUR CLIENT'S "
1685 L"VERSION MAY NOT BE FULLY COMPATIBLE WITH THIS SERVER!");
1691 u8 peer_ser_ver = getClient(peer_id, CS_InitDone)->serialization_version;
1692 u16 peer_proto_ver = getClient(peer_id, CS_InitDone)->net_proto_version;
1694 if(peer_ser_ver == SER_FMT_VER_INVALID)
1696 errorstream<<"Server::ProcessData(): Cancelling: Peer"
1697 " serialization format invalid or not initialized."
1698 " Skipping incoming command="<<command<<std::endl;
1702 /* Handle commands relate to client startup */
1703 if(command == TOSERVER_REQUEST_MEDIA) {
1704 std::string datastring((char*)&data[2], datasize-2);
1705 std::istringstream is(datastring, std::ios_base::binary);
1707 std::list<std::string> tosend;
1708 u16 numfiles = readU16(is);
1710 infostream<<"Sending "<<numfiles<<" files to "
1711 <<getPlayerName(peer_id)<<std::endl;
1712 verbosestream<<"TOSERVER_REQUEST_MEDIA: "<<std::endl;
1714 for(int i = 0; i < numfiles; i++) {
1715 std::string name = deSerializeString(is);
1716 tosend.push_back(name);
1717 verbosestream<<"TOSERVER_REQUEST_MEDIA: requested file "
1721 sendRequestedMedia(peer_id, tosend);
1724 else if(command == TOSERVER_RECEIVED_MEDIA) {
1727 else if(command == TOSERVER_CLIENT_READY) {
1728 // clients <= protocol version 22 did not send ready message,
1729 // they're already initialized
1730 if (peer_proto_ver <= 22) {
1731 infostream << "Client sent message not expected by a "
1732 << "client using protocol version <= 22,"
1733 << "disconnecing peer_id: " << peer_id << std::endl;
1734 m_con.DisconnectPeer(peer_id);
1738 PlayerSAO* playersao = StageTwoClientInit(peer_id);
1740 if (playersao == NULL) {
1742 << "TOSERVER_CLIENT_READY stage 2 client init failed for peer_id: "
1743 << peer_id << std::endl;
1744 m_con.DisconnectPeer(peer_id);
1749 if(datasize < 2+8) {
1751 << "TOSERVER_CLIENT_READY client sent inconsistent data, disconnecting peer_id: "
1752 << peer_id << std::endl;
1753 m_con.DisconnectPeer(peer_id);
1757 m_clients.setClientVersion(
1759 data[2], data[3], data[4],
1760 std::string((char*) &data[8],(u16) data[6]));
1762 m_clients.event(peer_id, CSE_SetClientReady);
1763 m_script->on_joinplayer(playersao);
1766 else if(command == TOSERVER_GOTBLOCKS)
1779 u16 count = data[2];
1780 for(u16 i=0; i<count; i++)
1782 if((s16)datasize < 2+1+(i+1)*6)
1783 throw con::InvalidIncomingDataException
1784 ("GOTBLOCKS length is too short");
1785 v3s16 p = readV3S16(&data[2+1+i*6]);
1786 /*infostream<<"Server: GOTBLOCKS ("
1787 <<p.X<<","<<p.Y<<","<<p.Z<<")"<<std::endl;*/
1788 RemoteClient *client = getClient(peer_id);
1789 client->GotBlock(p);
1794 if (m_clients.getClientState(peer_id) < CS_Active)
1796 if (command == TOSERVER_PLAYERPOS) return;
1798 errorstream<<"Got packet command: " << command << " for peer id "
1799 << peer_id << " but client isn't active yet. Dropping packet "
1804 Player *player = m_env->getPlayer(peer_id);
1805 if(player == NULL) {
1806 errorstream<<"Server::ProcessData(): Cancelling: "
1807 "No player for peer_id="<<peer_id
1808 << " disconnecting peer!" <<std::endl;
1809 m_con.DisconnectPeer(peer_id);
1813 PlayerSAO *playersao = player->getPlayerSAO();
1814 if(playersao == NULL) {
1815 errorstream<<"Server::ProcessData(): Cancelling: "
1816 "No player object for peer_id="<<peer_id
1817 << " disconnecting peer!" <<std::endl;
1818 m_con.DisconnectPeer(peer_id);
1822 if(command == TOSERVER_PLAYERPOS)
1824 if(datasize < 2+12+12+4+4)
1828 v3s32 ps = readV3S32(&data[start+2]);
1829 v3s32 ss = readV3S32(&data[start+2+12]);
1830 f32 pitch = (f32)readS32(&data[2+12+12]) / 100.0;
1831 f32 yaw = (f32)readS32(&data[2+12+12+4]) / 100.0;
1833 if(datasize >= 2+12+12+4+4+4)
1834 keyPressed = (u32)readU32(&data[2+12+12+4+4]);
1835 v3f position((f32)ps.X/100., (f32)ps.Y/100., (f32)ps.Z/100.);
1836 v3f speed((f32)ss.X/100., (f32)ss.Y/100., (f32)ss.Z/100.);
1837 pitch = wrapDegrees(pitch);
1838 yaw = wrapDegrees(yaw);
1840 player->setPosition(position);
1841 player->setSpeed(speed);
1842 player->setPitch(pitch);
1843 player->setYaw(yaw);
1844 player->keyPressed=keyPressed;
1845 player->control.up = (bool)(keyPressed&1);
1846 player->control.down = (bool)(keyPressed&2);
1847 player->control.left = (bool)(keyPressed&4);
1848 player->control.right = (bool)(keyPressed&8);
1849 player->control.jump = (bool)(keyPressed&16);
1850 player->control.aux1 = (bool)(keyPressed&32);
1851 player->control.sneak = (bool)(keyPressed&64);
1852 player->control.LMB = (bool)(keyPressed&128);
1853 player->control.RMB = (bool)(keyPressed&256);
1855 bool cheated = playersao->checkMovementCheat();
1858 m_script->on_cheat(playersao, "moved_too_fast");
1861 /*infostream<<"Server::ProcessData(): Moved player "<<peer_id<<" to "
1862 <<"("<<position.X<<","<<position.Y<<","<<position.Z<<")"
1863 <<" pitch="<<pitch<<" yaw="<<yaw<<std::endl;*/
1865 else if(command == TOSERVER_DELETEDBLOCKS)
1878 u16 count = data[2];
1879 for(u16 i=0; i<count; i++)
1881 if((s16)datasize < 2+1+(i+1)*6)
1882 throw con::InvalidIncomingDataException
1883 ("DELETEDBLOCKS length is too short");
1884 v3s16 p = readV3S16(&data[2+1+i*6]);
1885 /*infostream<<"Server: DELETEDBLOCKS ("
1886 <<p.X<<","<<p.Y<<","<<p.Z<<")"<<std::endl;*/
1887 RemoteClient *client = getClient(peer_id);
1888 client->SetBlockNotSent(p);
1891 else if(command == TOSERVER_CLICK_OBJECT)
1893 infostream<<"Server: CLICK_OBJECT not supported anymore"<<std::endl;
1896 else if(command == TOSERVER_CLICK_ACTIVEOBJECT)
1898 infostream<<"Server: CLICK_ACTIVEOBJECT not supported anymore"<<std::endl;
1901 else if(command == TOSERVER_GROUND_ACTION)
1903 infostream<<"Server: GROUND_ACTION not supported anymore"<<std::endl;
1907 else if(command == TOSERVER_RELEASE)
1909 infostream<<"Server: RELEASE not supported anymore"<<std::endl;
1912 else if(command == TOSERVER_SIGNTEXT)
1914 infostream<<"Server: SIGNTEXT not supported anymore"
1918 else if(command == TOSERVER_SIGNNODETEXT)
1920 infostream<<"Server: SIGNNODETEXT not supported anymore"
1924 else if(command == TOSERVER_INVENTORY_ACTION)
1926 // Strip command and create a stream
1927 std::string datastring((char*)&data[2], datasize-2);
1928 verbosestream<<"TOSERVER_INVENTORY_ACTION: data="<<datastring<<std::endl;
1929 std::istringstream is(datastring, std::ios_base::binary);
1931 InventoryAction *a = InventoryAction::deSerialize(is);
1934 infostream<<"TOSERVER_INVENTORY_ACTION: "
1935 <<"InventoryAction::deSerialize() returned NULL"
1940 // If something goes wrong, this player is to blame
1941 RollbackScopeActor rollback_scope(m_rollback,
1942 std::string("player:")+player->getName());
1945 Note: Always set inventory not sent, to repair cases
1946 where the client made a bad prediction.
1950 Handle restrictions and special cases of the move action
1952 if(a->getType() == IACTION_MOVE)
1954 IMoveAction *ma = (IMoveAction*)a;
1956 ma->from_inv.applyCurrentPlayer(player->getName());
1957 ma->to_inv.applyCurrentPlayer(player->getName());
1959 setInventoryModified(ma->from_inv);
1960 setInventoryModified(ma->to_inv);
1962 bool from_inv_is_current_player =
1963 (ma->from_inv.type == InventoryLocation::PLAYER) &&
1964 (ma->from_inv.name == player->getName());
1966 bool to_inv_is_current_player =
1967 (ma->to_inv.type == InventoryLocation::PLAYER) &&
1968 (ma->to_inv.name == player->getName());
1971 Disable moving items out of craftpreview
1973 if(ma->from_list == "craftpreview")
1975 infostream<<"Ignoring IMoveAction from "
1976 <<(ma->from_inv.dump())<<":"<<ma->from_list
1977 <<" to "<<(ma->to_inv.dump())<<":"<<ma->to_list
1978 <<" because src is "<<ma->from_list<<std::endl;
1984 Disable moving items into craftresult and craftpreview
1986 if(ma->to_list == "craftpreview" || ma->to_list == "craftresult")
1988 infostream<<"Ignoring IMoveAction from "
1989 <<(ma->from_inv.dump())<<":"<<ma->from_list
1990 <<" to "<<(ma->to_inv.dump())<<":"<<ma->to_list
1991 <<" because dst is "<<ma->to_list<<std::endl;
1996 // Disallow moving items in elsewhere than player's inventory
1997 // if not allowed to interact
1998 if(!checkPriv(player->getName(), "interact") &&
1999 (!from_inv_is_current_player ||
2000 !to_inv_is_current_player))
2002 infostream<<"Cannot move outside of player's inventory: "
2003 <<"No interact privilege"<<std::endl;
2009 Handle restrictions and special cases of the drop action
2011 else if(a->getType() == IACTION_DROP)
2013 IDropAction *da = (IDropAction*)a;
2015 da->from_inv.applyCurrentPlayer(player->getName());
2017 setInventoryModified(da->from_inv);
2020 Disable dropping items out of craftpreview
2022 if(da->from_list == "craftpreview")
2024 infostream<<"Ignoring IDropAction from "
2025 <<(da->from_inv.dump())<<":"<<da->from_list
2026 <<" because src is "<<da->from_list<<std::endl;
2031 // Disallow dropping items if not allowed to interact
2032 if(!checkPriv(player->getName(), "interact"))
2039 Handle restrictions and special cases of the craft action
2041 else if(a->getType() == IACTION_CRAFT)
2043 ICraftAction *ca = (ICraftAction*)a;
2045 ca->craft_inv.applyCurrentPlayer(player->getName());
2047 setInventoryModified(ca->craft_inv);
2049 //bool craft_inv_is_current_player =
2050 // (ca->craft_inv.type == InventoryLocation::PLAYER) &&
2051 // (ca->craft_inv.name == player->getName());
2053 // Disallow crafting if not allowed to interact
2054 if(!checkPriv(player->getName(), "interact"))
2056 infostream<<"Cannot craft: "
2057 <<"No interact privilege"<<std::endl;
2064 a->apply(this, playersao, this);
2068 else if(command == TOSERVER_CHAT_MESSAGE)
2076 std::string datastring((char*)&data[2], datasize-2);
2077 std::istringstream is(datastring, std::ios_base::binary);
2080 is.read((char*)buf, 2);
2081 u16 len = readU16(buf);
2083 std::wstring message;
2084 for(u16 i=0; i<len; i++)
2086 is.read((char*)buf, 2);
2087 message += (wchar_t)readU16(buf);
2090 // If something goes wrong, this player is to blame
2091 RollbackScopeActor rollback_scope(m_rollback,
2092 std::string("player:")+player->getName());
2094 // Get player name of this client
2095 std::wstring name = narrow_to_wide(player->getName());
2098 bool ate = m_script->on_chat_message(player->getName(),
2099 wide_to_narrow(message));
2100 // If script ate the message, don't proceed
2104 // Line to send to players
2106 // Whether to send to the player that sent the line
2107 bool send_to_sender_only = false;
2109 // Commands are implemented in Lua, so only catch invalid
2110 // commands that were not "eaten" and send an error back
2111 if(message[0] == L'/')
2113 message = message.substr(1);
2114 send_to_sender_only = true;
2115 if(message.length() == 0)
2116 line += L"-!- Empty command";
2118 line += L"-!- Invalid command: " + str_split(message, L' ')[0];
2122 if(checkPriv(player->getName(), "shout")){
2128 line += L"-!- You don't have permission to shout.";
2129 send_to_sender_only = true;
2136 Send the message to sender
2138 if (send_to_sender_only)
2140 SendChatMessage(peer_id, line);
2143 Send the message to others
2147 actionstream<<"CHAT: "<<wide_to_narrow(line)<<std::endl;
2149 std::list<u16> clients = m_clients.getClientIDs();
2151 for(std::list<u16>::iterator
2152 i = clients.begin();
2153 i != clients.end(); ++i)
2156 SendChatMessage(*i, line);
2161 else if(command == TOSERVER_DAMAGE)
2163 std::string datastring((char*)&data[2], datasize-2);
2164 std::istringstream is(datastring, std::ios_base::binary);
2165 u8 damage = readU8(is);
2167 if(g_settings->getBool("enable_damage"))
2169 actionstream<<player->getName()<<" damaged by "
2170 <<(int)damage<<" hp at "<<PP(player->getPosition()/BS)
2173 playersao->setHP(playersao->getHP() - damage);
2175 if(playersao->getHP() == 0 && playersao->m_hp_not_sent)
2178 if(playersao->m_hp_not_sent)
2179 SendPlayerHP(peer_id);
2182 else if(command == TOSERVER_BREATH)
2184 std::string datastring((char*)&data[2], datasize-2);
2185 std::istringstream is(datastring, std::ios_base::binary);
2186 u16 breath = readU16(is);
2187 playersao->setBreath(breath);
2188 m_script->player_event(playersao,"breath_changed");
2190 else if(command == TOSERVER_PASSWORD)
2193 [0] u16 TOSERVER_PASSWORD
2194 [2] u8[28] old password
2195 [30] u8[28] new password
2198 if(datasize != 2+PASSWORD_SIZE*2)
2200 /*char password[PASSWORD_SIZE];
2201 for(u32 i=0; i<PASSWORD_SIZE-1; i++)
2202 password[i] = data[2+i];
2203 password[PASSWORD_SIZE-1] = 0;*/
2205 for(u32 i=0; i<PASSWORD_SIZE-1; i++)
2213 for(u32 i=0; i<PASSWORD_SIZE-1; i++)
2215 char c = data[2+PASSWORD_SIZE+i];
2221 if(!base64_is_valid(newpwd)){
2222 infostream<<"Server: "<<player->getName()<<" supplied invalid password hash"<<std::endl;
2223 // Wrong old password supplied!!
2224 SendChatMessage(peer_id, L"Invalid new password hash supplied. Password NOT changed.");
2228 infostream<<"Server: Client requests a password change from "
2229 <<"'"<<oldpwd<<"' to '"<<newpwd<<"'"<<std::endl;
2231 std::string playername = player->getName();
2233 std::string checkpwd;
2234 m_script->getAuth(playername, &checkpwd, NULL);
2236 if(oldpwd != checkpwd)
2238 infostream<<"Server: invalid old password"<<std::endl;
2239 // Wrong old password supplied!!
2240 SendChatMessage(peer_id, L"Invalid old password supplied. Password NOT changed.");
2244 bool success = m_script->setPassword(playername, newpwd);
2246 actionstream<<player->getName()<<" changes password"<<std::endl;
2247 SendChatMessage(peer_id, L"Password change successful.");
2249 actionstream<<player->getName()<<" tries to change password but "
2250 <<"it fails"<<std::endl;
2251 SendChatMessage(peer_id, L"Password change failed or inavailable.");
2254 else if(command == TOSERVER_PLAYERITEM)
2259 u16 item = readU16(&data[2]);
2260 playersao->setWieldIndex(item);
2262 else if(command == TOSERVER_RESPAWN)
2264 if(player->hp != 0 || !g_settings->getBool("enable_damage"))
2267 RespawnPlayer(peer_id);
2269 actionstream<<player->getName()<<" respawns at "
2270 <<PP(player->getPosition()/BS)<<std::endl;
2272 // ActiveObject is added to environment in AsyncRunStep after
2273 // the previous addition has been succesfully removed
2275 else if(command == TOSERVER_INTERACT)
2277 std::string datastring((char*)&data[2], datasize-2);
2278 std::istringstream is(datastring, std::ios_base::binary);
2284 [5] u32 length of the next item
2285 [9] serialized PointedThing
2287 0: start digging (from undersurface) or use
2288 1: stop digging (all parameters ignored)
2289 2: digging completed
2290 3: place block or item (to abovesurface)
2293 u8 action = readU8(is);
2294 u16 item_i = readU16(is);
2295 std::istringstream tmp_is(deSerializeLongString(is), std::ios::binary);
2296 PointedThing pointed;
2297 pointed.deSerialize(tmp_is);
2299 verbosestream<<"TOSERVER_INTERACT: action="<<(int)action<<", item="
2300 <<item_i<<", pointed="<<pointed.dump()<<std::endl;
2304 verbosestream<<"TOSERVER_INTERACT: "<<player->getName()
2305 <<" tried to interact, but is dead!"<<std::endl;
2309 v3f player_pos = playersao->getLastGoodPosition();
2311 // Update wielded item
2312 playersao->setWieldIndex(item_i);
2314 // Get pointed to node (undefined if not POINTEDTYPE_NODE)
2315 v3s16 p_under = pointed.node_undersurface;
2316 v3s16 p_above = pointed.node_abovesurface;
2318 // Get pointed to object (NULL if not POINTEDTYPE_OBJECT)
2319 ServerActiveObject *pointed_object = NULL;
2320 if(pointed.type == POINTEDTHING_OBJECT)
2322 pointed_object = m_env->getActiveObject(pointed.object_id);
2323 if(pointed_object == NULL)
2325 verbosestream<<"TOSERVER_INTERACT: "
2326 "pointed object is NULL"<<std::endl;
2332 v3f pointed_pos_under = player_pos;
2333 v3f pointed_pos_above = player_pos;
2334 if(pointed.type == POINTEDTHING_NODE)
2336 pointed_pos_under = intToFloat(p_under, BS);
2337 pointed_pos_above = intToFloat(p_above, BS);
2339 else if(pointed.type == POINTEDTHING_OBJECT)
2341 pointed_pos_under = pointed_object->getBasePosition();
2342 pointed_pos_above = pointed_pos_under;
2346 Check that target is reasonably close
2347 (only when digging or placing things)
2349 if(action == 0 || action == 2 || action == 3)
2351 float d = player_pos.getDistanceFrom(pointed_pos_under);
2352 float max_d = BS * 14; // Just some large enough value
2354 actionstream<<"Player "<<player->getName()
2355 <<" tried to access "<<pointed.dump()
2357 <<"d="<<d<<", max_d="<<max_d
2358 <<". ignoring."<<std::endl;
2359 // Re-send block to revert change on client-side
2360 RemoteClient *client = getClient(peer_id);
2361 v3s16 blockpos = getNodeBlockPos(floatToInt(pointed_pos_under, BS));
2362 client->SetBlockNotSent(blockpos);
2364 m_script->on_cheat(playersao, "interacted_too_far");
2371 Make sure the player is allowed to do it
2373 if(!checkPriv(player->getName(), "interact"))
2375 actionstream<<player->getName()<<" attempted to interact with "
2376 <<pointed.dump()<<" without 'interact' privilege"
2378 // Re-send block to revert change on client-side
2379 RemoteClient *client = getClient(peer_id);
2380 // Digging completed -> under
2382 v3s16 blockpos = getNodeBlockPos(floatToInt(pointed_pos_under, BS));
2383 client->SetBlockNotSent(blockpos);
2385 // Placement -> above
2387 v3s16 blockpos = getNodeBlockPos(floatToInt(pointed_pos_above, BS));
2388 client->SetBlockNotSent(blockpos);
2394 If something goes wrong, this player is to blame
2396 RollbackScopeActor rollback_scope(m_rollback,
2397 std::string("player:")+player->getName());
2400 0: start digging or punch object
2404 if(pointed.type == POINTEDTHING_NODE)
2407 NOTE: This can be used in the future to check if
2408 somebody is cheating, by checking the timing.
2410 MapNode n(CONTENT_IGNORE);
2413 n = m_env->getMap().getNode(p_under);
2415 catch(InvalidPositionException &e)
2417 infostream<<"Server: Not punching: Node not found."
2418 <<" Adding block to emerge queue."
2420 m_emerge->enqueueBlockEmerge(peer_id, getNodeBlockPos(p_above), false);
2422 if(n.getContent() != CONTENT_IGNORE)
2423 m_script->node_on_punch(p_under, n, playersao, pointed);
2425 playersao->noCheatDigStart(p_under);
2427 else if(pointed.type == POINTEDTHING_OBJECT)
2429 // Skip if object has been removed
2430 if(pointed_object->m_removed)
2433 actionstream<<player->getName()<<" punches object "
2434 <<pointed.object_id<<": "
2435 <<pointed_object->getDescription()<<std::endl;
2437 ItemStack punchitem = playersao->getWieldedItem();
2438 ToolCapabilities toolcap =
2439 punchitem.getToolCapabilities(m_itemdef);
2440 v3f dir = (pointed_object->getBasePosition() -
2441 (player->getPosition() + player->getEyeOffset())
2443 float time_from_last_punch =
2444 playersao->resetTimeFromLastPunch();
2445 pointed_object->punch(dir, &toolcap, playersao,
2446 time_from_last_punch);
2454 else if(action == 1)
2459 2: Digging completed
2461 else if(action == 2)
2463 // Only digging of nodes
2464 if(pointed.type == POINTEDTHING_NODE)
2466 MapNode n(CONTENT_IGNORE);
2469 n = m_env->getMap().getNode(p_under);
2471 catch(InvalidPositionException &e)
2473 infostream<<"Server: Not finishing digging: Node not found."
2474 <<" Adding block to emerge queue."
2476 m_emerge->enqueueBlockEmerge(peer_id, getNodeBlockPos(p_above), false);
2479 /* Cheat prevention */
2480 bool is_valid_dig = true;
2481 if(!isSingleplayer() && !g_settings->getBool("disable_anticheat"))
2483 v3s16 nocheat_p = playersao->getNoCheatDigPos();
2484 float nocheat_t = playersao->getNoCheatDigTime();
2485 playersao->noCheatDigEnd();
2486 // If player didn't start digging this, ignore dig
2487 if(nocheat_p != p_under){
2488 infostream<<"Server: NoCheat: "<<player->getName()
2489 <<" started digging "
2490 <<PP(nocheat_p)<<" and completed digging "
2491 <<PP(p_under)<<"; not digging."<<std::endl;
2492 is_valid_dig = false;
2494 m_script->on_cheat(playersao, "finished_unknown_dig");
2496 // Get player's wielded item
2497 ItemStack playeritem;
2498 InventoryList *mlist = playersao->getInventory()->getList("main");
2500 playeritem = mlist->getItem(playersao->getWieldIndex());
2501 ToolCapabilities playeritem_toolcap =
2502 playeritem.getToolCapabilities(m_itemdef);
2503 // Get diggability and expected digging time
2504 DigParams params = getDigParams(m_nodedef->get(n).groups,
2505 &playeritem_toolcap);
2506 // If can't dig, try hand
2507 if(!params.diggable){
2508 const ItemDefinition &hand = m_itemdef->get("");
2509 const ToolCapabilities *tp = hand.tool_capabilities;
2511 params = getDigParams(m_nodedef->get(n).groups, tp);
2513 // If can't dig, ignore dig
2514 if(!params.diggable){
2515 infostream<<"Server: NoCheat: "<<player->getName()
2516 <<" completed digging "<<PP(p_under)
2517 <<", which is not diggable with tool. not digging."
2519 is_valid_dig = false;
2521 m_script->on_cheat(playersao, "dug_unbreakable");
2523 // Check digging time
2524 // If already invalidated, we don't have to
2526 // Well not our problem then
2528 // Clean and long dig
2529 else if(params.time > 2.0 && nocheat_t * 1.2 > params.time){
2530 // All is good, but grab time from pool; don't care if
2531 // it's actually available
2532 playersao->getDigPool().grab(params.time);
2534 // Short or laggy dig
2535 // Try getting the time from pool
2536 else if(playersao->getDigPool().grab(params.time)){
2541 infostream<<"Server: NoCheat: "<<player->getName()
2542 <<" completed digging "<<PP(p_under)
2543 <<"too fast; not digging."<<std::endl;
2544 is_valid_dig = false;
2546 m_script->on_cheat(playersao, "dug_too_fast");
2550 /* Actually dig node */
2552 if(is_valid_dig && n.getContent() != CONTENT_IGNORE)
2553 m_script->node_on_dig(p_under, n, playersao);
2555 v3s16 blockpos = getNodeBlockPos(floatToInt(pointed_pos_under, BS));
2556 RemoteClient *client = getClient(peer_id);
2557 // Send unusual result (that is, node not being removed)
2558 if(m_env->getMap().getNodeNoEx(p_under).getContent() != CONTENT_AIR)
2560 // Re-send block to revert change on client-side
2561 client->SetBlockNotSent(blockpos);
2564 client->ResendBlockIfOnWire(blockpos);
2570 3: place block or right-click object
2572 else if(action == 3)
2574 ItemStack item = playersao->getWieldedItem();
2576 // Reset build time counter
2577 if(pointed.type == POINTEDTHING_NODE &&
2578 item.getDefinition(m_itemdef).type == ITEM_NODE)
2579 getClient(peer_id)->m_time_from_building = 0.0;
2581 if(pointed.type == POINTEDTHING_OBJECT)
2583 // Right click object
2585 // Skip if object has been removed
2586 if(pointed_object->m_removed)
2589 actionstream<<player->getName()<<" right-clicks object "
2590 <<pointed.object_id<<": "
2591 <<pointed_object->getDescription()<<std::endl;
2594 pointed_object->rightClick(playersao);
2596 else if(m_script->item_OnPlace(
2597 item, playersao, pointed))
2599 // Placement was handled in lua
2601 // Apply returned ItemStack
2602 playersao->setWieldedItem(item);
2605 // If item has node placement prediction, always send the
2606 // blocks to make sure the client knows what exactly happened
2607 RemoteClient *client = getClient(peer_id);
2608 v3s16 blockpos = getNodeBlockPos(floatToInt(pointed_pos_above, BS));
2609 v3s16 blockpos2 = getNodeBlockPos(floatToInt(pointed_pos_under, BS));
2610 if(item.getDefinition(m_itemdef).node_placement_prediction != "") {
2611 client->SetBlockNotSent(blockpos);
2612 if(blockpos2 != blockpos) {
2613 client->SetBlockNotSent(blockpos2);
2617 client->ResendBlockIfOnWire(blockpos);
2618 if(blockpos2 != blockpos) {
2619 client->ResendBlockIfOnWire(blockpos2);
2627 else if(action == 4)
2629 ItemStack item = playersao->getWieldedItem();
2631 actionstream<<player->getName()<<" uses "<<item.name
2632 <<", pointing at "<<pointed.dump()<<std::endl;
2634 if(m_script->item_OnUse(
2635 item, playersao, pointed))
2637 // Apply returned ItemStack
2638 playersao->setWieldedItem(item);
2645 Catch invalid actions
2649 infostream<<"WARNING: Server: Invalid action "
2650 <<action<<std::endl;
2653 else if(command == TOSERVER_REMOVED_SOUNDS)
2655 std::string datastring((char*)&data[2], datasize-2);
2656 std::istringstream is(datastring, std::ios_base::binary);
2658 int num = readU16(is);
2659 for(int k=0; k<num; k++){
2660 s32 id = readS32(is);
2661 std::map<s32, ServerPlayingSound>::iterator i =
2662 m_playing_sounds.find(id);
2663 if(i == m_playing_sounds.end())
2665 ServerPlayingSound &psound = i->second;
2666 psound.clients.erase(peer_id);
2667 if(psound.clients.size() == 0)
2668 m_playing_sounds.erase(i++);
2671 else if(command == TOSERVER_NODEMETA_FIELDS)
2673 std::string datastring((char*)&data[2], datasize-2);
2674 std::istringstream is(datastring, std::ios_base::binary);
2676 v3s16 p = readV3S16(is);
2677 std::string formname = deSerializeString(is);
2678 int num = readU16(is);
2679 std::map<std::string, std::string> fields;
2680 for(int k=0; k<num; k++){
2681 std::string fieldname = deSerializeString(is);
2682 std::string fieldvalue = deSerializeLongString(is);
2683 fields[fieldname] = fieldvalue;
2686 // If something goes wrong, this player is to blame
2687 RollbackScopeActor rollback_scope(m_rollback,
2688 std::string("player:")+player->getName());
2690 // Check the target node for rollback data; leave others unnoticed
2691 RollbackNode rn_old(&m_env->getMap(), p, this);
2693 m_script->node_on_receive_fields(p, formname, fields,playersao);
2695 // Report rollback data
2696 RollbackNode rn_new(&m_env->getMap(), p, this);
2697 if(rollback() && rn_new != rn_old){
2698 RollbackAction action;
2699 action.setSetNode(p, rn_old, rn_new);
2700 rollback()->reportAction(action);
2703 else if(command == TOSERVER_INVENTORY_FIELDS)
2705 std::string datastring((char*)&data[2], datasize-2);
2706 std::istringstream is(datastring, std::ios_base::binary);
2708 std::string formname = deSerializeString(is);
2709 int num = readU16(is);
2710 std::map<std::string, std::string> fields;
2711 for(int k=0; k<num; k++){
2712 std::string fieldname = deSerializeString(is);
2713 std::string fieldvalue = deSerializeLongString(is);
2714 fields[fieldname] = fieldvalue;
2717 m_script->on_playerReceiveFields(playersao, formname, fields);
2721 infostream<<"Server::ProcessData(): Ignoring "
2722 "unknown command "<<command<<std::endl;
2726 catch(SendFailedException &e)
2728 errorstream<<"Server::ProcessData(): SendFailedException: "
2734 void Server::setTimeOfDay(u32 time)
2736 m_env->setTimeOfDay(time);
2737 m_time_of_day_send_timer = 0;
2740 void Server::onMapEditEvent(MapEditEvent *event)
2742 //infostream<<"Server::onMapEditEvent()"<<std::endl;
2743 if(m_ignore_map_edit_events)
2745 if(m_ignore_map_edit_events_area.contains(event->getArea()))
2747 MapEditEvent *e = event->clone();
2748 m_unsent_map_edit_queue.push_back(e);
2751 Inventory* Server::getInventory(const InventoryLocation &loc)
2754 case InventoryLocation::UNDEFINED:
2757 case InventoryLocation::CURRENT_PLAYER:
2760 case InventoryLocation::PLAYER:
2762 Player *player = m_env->getPlayer(loc.name.c_str());
2765 PlayerSAO *playersao = player->getPlayerSAO();
2768 return playersao->getInventory();
2771 case InventoryLocation::NODEMETA:
2773 NodeMetadata *meta = m_env->getMap().getNodeMetadata(loc.p);
2776 return meta->getInventory();
2779 case InventoryLocation::DETACHED:
2781 if(m_detached_inventories.count(loc.name) == 0)
2783 return m_detached_inventories[loc.name];
2791 void Server::setInventoryModified(const InventoryLocation &loc)
2794 case InventoryLocation::UNDEFINED:
2797 case InventoryLocation::PLAYER:
2799 Player *player = m_env->getPlayer(loc.name.c_str());
2802 PlayerSAO *playersao = player->getPlayerSAO();
2805 playersao->m_inventory_not_sent = true;
2806 playersao->m_wielded_item_not_sent = true;
2809 case InventoryLocation::NODEMETA:
2811 v3s16 blockpos = getNodeBlockPos(loc.p);
2813 MapBlock *block = m_env->getMap().getBlockNoCreateNoEx(blockpos);
2815 block->raiseModified(MOD_STATE_WRITE_NEEDED);
2817 setBlockNotSent(blockpos);
2820 case InventoryLocation::DETACHED:
2822 sendDetachedInventory(loc.name,PEER_ID_INEXISTENT);
2830 void Server::SetBlocksNotSent(std::map<v3s16, MapBlock *>& block)
2832 std::list<u16> clients = m_clients.getClientIDs();
2834 // Set the modified blocks unsent for all the clients
2835 for (std::list<u16>::iterator
2836 i = clients.begin();
2837 i != clients.end(); ++i) {
2838 RemoteClient *client = m_clients.lockedGetClientNoEx(*i);
2840 client->SetBlocksNotSent(block);
2845 void Server::peerAdded(con::Peer *peer)
2847 DSTACK(__FUNCTION_NAME);
2848 verbosestream<<"Server::peerAdded(): peer->id="
2849 <<peer->id<<std::endl;
2852 c.type = con::PEER_ADDED;
2853 c.peer_id = peer->id;
2855 m_peer_change_queue.push_back(c);
2858 void Server::deletingPeer(con::Peer *peer, bool timeout)
2860 DSTACK(__FUNCTION_NAME);
2861 verbosestream<<"Server::deletingPeer(): peer->id="
2862 <<peer->id<<", timeout="<<timeout<<std::endl;
2864 m_clients.event(peer->id, CSE_Disconnect);
2866 c.type = con::PEER_REMOVED;
2867 c.peer_id = peer->id;
2868 c.timeout = timeout;
2869 m_peer_change_queue.push_back(c);
2872 bool Server::getClientConInfo(u16 peer_id, con::rtt_stat_type type, float* retval)
2874 *retval = m_con.getPeerStat(peer_id,type);
2875 if (*retval == -1) return false;
2879 bool Server::getClientInfo(
2888 std::string* vers_string
2891 *state = m_clients.getClientState(peer_id);
2893 RemoteClient* client = m_clients.lockedGetClientNoEx(peer_id, CS_Invalid);
2895 if (client == NULL) {
2900 *uptime = client->uptime();
2901 *ser_vers = client->serialization_version;
2902 *prot_vers = client->net_proto_version;
2904 *major = client->getMajor();
2905 *minor = client->getMinor();
2906 *patch = client->getPatch();
2907 *vers_string = client->getPatch();
2914 void Server::handlePeerChanges()
2916 while(m_peer_change_queue.size() > 0)
2918 con::PeerChange c = m_peer_change_queue.pop_front();
2920 verbosestream<<"Server: Handling peer change: "
2921 <<"id="<<c.peer_id<<", timeout="<<c.timeout
2926 case con::PEER_ADDED:
2927 m_clients.CreateClient(c.peer_id);
2930 case con::PEER_REMOVED:
2931 DeleteClient(c.peer_id, c.timeout?CDR_TIMEOUT:CDR_LEAVE);
2935 assert("Invalid peer change event received!" == 0);
2941 void Server::SendMovement(u16 peer_id)
2943 DSTACK(__FUNCTION_NAME);
2944 std::ostringstream os(std::ios_base::binary);
2946 writeU16(os, TOCLIENT_MOVEMENT);
2947 writeF1000(os, g_settings->getFloat("movement_acceleration_default"));
2948 writeF1000(os, g_settings->getFloat("movement_acceleration_air"));
2949 writeF1000(os, g_settings->getFloat("movement_acceleration_fast"));
2950 writeF1000(os, g_settings->getFloat("movement_speed_walk"));
2951 writeF1000(os, g_settings->getFloat("movement_speed_crouch"));
2952 writeF1000(os, g_settings->getFloat("movement_speed_fast"));
2953 writeF1000(os, g_settings->getFloat("movement_speed_climb"));
2954 writeF1000(os, g_settings->getFloat("movement_speed_jump"));
2955 writeF1000(os, g_settings->getFloat("movement_liquid_fluidity"));
2956 writeF1000(os, g_settings->getFloat("movement_liquid_fluidity_smooth"));
2957 writeF1000(os, g_settings->getFloat("movement_liquid_sink"));
2958 writeF1000(os, g_settings->getFloat("movement_gravity"));
2961 std::string s = os.str();
2962 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
2964 m_clients.send(peer_id, 0, data, true);
2967 void Server::SendHP(u16 peer_id, u8 hp)
2969 DSTACK(__FUNCTION_NAME);
2970 std::ostringstream os(std::ios_base::binary);
2972 writeU16(os, TOCLIENT_HP);
2976 std::string s = os.str();
2977 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
2979 m_clients.send(peer_id, 0, data, true);
2982 void Server::SendBreath(u16 peer_id, u16 breath)
2984 DSTACK(__FUNCTION_NAME);
2985 std::ostringstream os(std::ios_base::binary);
2987 writeU16(os, TOCLIENT_BREATH);
2988 writeU16(os, breath);
2991 std::string s = os.str();
2992 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
2994 m_clients.send(peer_id, 0, data, true);
2997 void Server::SendAccessDenied(u16 peer_id,const std::wstring &reason)
2999 DSTACK(__FUNCTION_NAME);
3000 std::ostringstream os(std::ios_base::binary);
3002 writeU16(os, TOCLIENT_ACCESS_DENIED);
3003 os<<serializeWideString(reason);
3006 std::string s = os.str();
3007 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3009 m_clients.send(peer_id, 0, data, true);
3012 void Server::SendDeathscreen(u16 peer_id,bool set_camera_point_target,
3013 v3f camera_point_target)
3015 DSTACK(__FUNCTION_NAME);
3016 std::ostringstream os(std::ios_base::binary);
3018 writeU16(os, TOCLIENT_DEATHSCREEN);
3019 writeU8(os, set_camera_point_target);
3020 writeV3F1000(os, camera_point_target);
3023 std::string s = os.str();
3024 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3026 m_clients.send(peer_id, 0, data, true);
3029 void Server::SendItemDef(u16 peer_id,
3030 IItemDefManager *itemdef, u16 protocol_version)
3032 DSTACK(__FUNCTION_NAME);
3033 std::ostringstream os(std::ios_base::binary);
3037 u32 length of the next item
3038 zlib-compressed serialized ItemDefManager
3040 writeU16(os, TOCLIENT_ITEMDEF);
3041 std::ostringstream tmp_os(std::ios::binary);
3042 itemdef->serialize(tmp_os, protocol_version);
3043 std::ostringstream tmp_os2(std::ios::binary);
3044 compressZlib(tmp_os.str(), tmp_os2);
3045 os<<serializeLongString(tmp_os2.str());
3048 std::string s = os.str();
3049 verbosestream<<"Server: Sending item definitions to id("<<peer_id
3050 <<"): size="<<s.size()<<std::endl;
3051 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3053 m_clients.send(peer_id, 0, data, true);
3056 void Server::SendNodeDef(u16 peer_id,
3057 INodeDefManager *nodedef, u16 protocol_version)
3059 DSTACK(__FUNCTION_NAME);
3060 std::ostringstream os(std::ios_base::binary);
3064 u32 length of the next item
3065 zlib-compressed serialized NodeDefManager
3067 writeU16(os, TOCLIENT_NODEDEF);
3068 std::ostringstream tmp_os(std::ios::binary);
3069 nodedef->serialize(tmp_os, protocol_version);
3070 std::ostringstream tmp_os2(std::ios::binary);
3071 compressZlib(tmp_os.str(), tmp_os2);
3072 os<<serializeLongString(tmp_os2.str());
3075 std::string s = os.str();
3076 verbosestream<<"Server: Sending node definitions to id("<<peer_id
3077 <<"): size="<<s.size()<<std::endl;
3078 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3080 m_clients.send(peer_id, 0, data, true);
3084 Non-static send methods
3087 void Server::SendInventory(u16 peer_id)
3089 DSTACK(__FUNCTION_NAME);
3091 PlayerSAO *playersao = getPlayerSAO(peer_id);
3094 playersao->m_inventory_not_sent = false;
3100 std::ostringstream os;
3101 playersao->getInventory()->serialize(os);
3103 std::string s = os.str();
3105 SharedBuffer<u8> data(s.size()+2);
3106 writeU16(&data[0], TOCLIENT_INVENTORY);
3107 memcpy(&data[2], s.c_str(), s.size());
3110 m_clients.send(peer_id, 0, data, true);
3113 void Server::SendChatMessage(u16 peer_id, const std::wstring &message)
3115 DSTACK(__FUNCTION_NAME);
3117 std::ostringstream os(std::ios_base::binary);
3121 writeU16(buf, TOCLIENT_CHAT_MESSAGE);
3122 os.write((char*)buf, 2);
3125 writeU16(buf, message.size());
3126 os.write((char*)buf, 2);
3129 for(u32 i=0; i<message.size(); i++)
3133 os.write((char*)buf, 2);
3137 std::string s = os.str();
3138 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3140 if (peer_id != PEER_ID_INEXISTENT)
3143 m_clients.send(peer_id, 0, data, true);
3147 m_clients.sendToAll(0,data,true);
3151 void Server::SendShowFormspecMessage(u16 peer_id, const std::string &formspec,
3152 const std::string &formname)
3154 DSTACK(__FUNCTION_NAME);
3156 std::ostringstream os(std::ios_base::binary);
3161 writeU16(buf, TOCLIENT_SHOW_FORMSPEC);
3162 os.write((char*)buf, 2);
3163 os<<serializeLongString(FORMSPEC_VERSION_STRING + formspec);
3164 os<<serializeString(formname);
3167 std::string s = os.str();
3168 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3170 m_clients.send(peer_id, 0, data, true);
3173 // Spawns a particle on peer with peer_id
3174 void Server::SendSpawnParticle(u16 peer_id, v3f pos, v3f velocity, v3f acceleration,
3175 float expirationtime, float size, bool collisiondetection,
3176 bool vertical, std::string texture)
3178 DSTACK(__FUNCTION_NAME);
3180 std::ostringstream os(std::ios_base::binary);
3181 writeU16(os, TOCLIENT_SPAWN_PARTICLE);
3182 writeV3F1000(os, pos);
3183 writeV3F1000(os, velocity);
3184 writeV3F1000(os, acceleration);
3185 writeF1000(os, expirationtime);
3186 writeF1000(os, size);
3187 writeU8(os, collisiondetection);
3188 os<<serializeLongString(texture);
3189 writeU8(os, vertical);
3192 std::string s = os.str();
3193 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3195 if (peer_id != PEER_ID_INEXISTENT)
3198 m_clients.send(peer_id, 0, data, true);
3202 m_clients.sendToAll(0,data,true);
3206 // Adds a ParticleSpawner on peer with peer_id
3207 void Server::SendAddParticleSpawner(u16 peer_id, u16 amount, float spawntime, v3f minpos, v3f maxpos,
3208 v3f minvel, v3f maxvel, v3f minacc, v3f maxacc, float minexptime, float maxexptime,
3209 float minsize, float maxsize, bool collisiondetection, bool vertical, std::string texture, u32 id)
3211 DSTACK(__FUNCTION_NAME);
3213 std::ostringstream os(std::ios_base::binary);
3214 writeU16(os, TOCLIENT_ADD_PARTICLESPAWNER);
3216 writeU16(os, amount);
3217 writeF1000(os, spawntime);
3218 writeV3F1000(os, minpos);
3219 writeV3F1000(os, maxpos);
3220 writeV3F1000(os, minvel);
3221 writeV3F1000(os, maxvel);
3222 writeV3F1000(os, minacc);
3223 writeV3F1000(os, maxacc);
3224 writeF1000(os, minexptime);
3225 writeF1000(os, maxexptime);
3226 writeF1000(os, minsize);
3227 writeF1000(os, maxsize);
3228 writeU8(os, collisiondetection);
3229 os<<serializeLongString(texture);
3231 writeU8(os, vertical);
3234 std::string s = os.str();
3235 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3237 if (peer_id != PEER_ID_INEXISTENT)
3240 m_clients.send(peer_id, 0, data, true);
3243 m_clients.sendToAll(0,data,true);
3247 void Server::SendDeleteParticleSpawner(u16 peer_id, u32 id)
3249 DSTACK(__FUNCTION_NAME);
3251 std::ostringstream os(std::ios_base::binary);
3252 writeU16(os, TOCLIENT_DELETE_PARTICLESPAWNER);
3257 std::string s = os.str();
3258 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3260 if (peer_id != PEER_ID_INEXISTENT) {
3262 m_clients.send(peer_id, 0, data, true);
3265 m_clients.sendToAll(0,data,true);
3270 void Server::SendHUDAdd(u16 peer_id, u32 id, HudElement *form)
3272 std::ostringstream os(std::ios_base::binary);
3275 writeU16(os, TOCLIENT_HUDADD);
3277 writeU8(os, (u8)form->type);
3278 writeV2F1000(os, form->pos);
3279 os << serializeString(form->name);
3280 writeV2F1000(os, form->scale);
3281 os << serializeString(form->text);
3282 writeU32(os, form->number);
3283 writeU32(os, form->item);
3284 writeU32(os, form->dir);
3285 writeV2F1000(os, form->align);
3286 writeV2F1000(os, form->offset);
3287 writeV3F1000(os, form->world_pos);
3288 writeV2S32(os,form->size);
3291 std::string s = os.str();
3292 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3294 m_clients.send(peer_id, 1, data, true);
3297 void Server::SendHUDRemove(u16 peer_id, u32 id)
3299 std::ostringstream os(std::ios_base::binary);
3302 writeU16(os, TOCLIENT_HUDRM);
3306 std::string s = os.str();
3307 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3310 m_clients.send(peer_id, 1, data, true);
3313 void Server::SendHUDChange(u16 peer_id, u32 id, HudElementStat stat, void *value)
3315 std::ostringstream os(std::ios_base::binary);
3318 writeU16(os, TOCLIENT_HUDCHANGE);
3320 writeU8(os, (u8)stat);
3323 case HUD_STAT_SCALE:
3324 case HUD_STAT_ALIGN:
3325 case HUD_STAT_OFFSET:
3326 writeV2F1000(os, *(v2f *)value);
3330 os << serializeString(*(std::string *)value);
3332 case HUD_STAT_WORLD_POS:
3333 writeV3F1000(os, *(v3f *)value);
3336 writeV2S32(os,*(v2s32 *)value);
3338 case HUD_STAT_NUMBER:
3342 writeU32(os, *(u32 *)value);
3347 std::string s = os.str();
3348 SharedBuffer<u8> data((u8 *)s.c_str(), s.size());
3350 m_clients.send(peer_id, 0, data, true);
3353 void Server::SendHUDSetFlags(u16 peer_id, u32 flags, u32 mask)
3355 std::ostringstream os(std::ios_base::binary);
3358 writeU16(os, TOCLIENT_HUD_SET_FLAGS);
3360 //////////////////////////// compatibility code to be removed //////////////
3361 flags &= ~(HUD_FLAG_HEALTHBAR_VISIBLE | HUD_FLAG_BREATHBAR_VISIBLE);
3362 ////////////////////////////////////////////////////////////////////////////
3363 writeU32(os, flags);
3367 std::string s = os.str();
3368 SharedBuffer<u8> data((u8 *)s.c_str(), s.size());
3370 m_clients.send(peer_id, 0, data, true);
3373 void Server::SendHUDSetParam(u16 peer_id, u16 param, const std::string &value)
3375 std::ostringstream os(std::ios_base::binary);
3378 writeU16(os, TOCLIENT_HUD_SET_PARAM);
3379 writeU16(os, param);
3380 os<<serializeString(value);
3383 std::string s = os.str();
3384 SharedBuffer<u8> data((u8 *)s.c_str(), s.size());
3386 m_clients.send(peer_id, 0, data, true);
3389 void Server::SendSetSky(u16 peer_id, const video::SColor &bgcolor,
3390 const std::string &type, const std::vector<std::string> ¶ms)
3392 std::ostringstream os(std::ios_base::binary);
3395 writeU16(os, TOCLIENT_SET_SKY);
3396 writeARGB8(os, bgcolor);
3397 os<<serializeString(type);
3398 writeU16(os, params.size());
3399 for(size_t i=0; i<params.size(); i++)
3400 os<<serializeString(params[i]);
3403 std::string s = os.str();
3404 SharedBuffer<u8> data((u8 *)s.c_str(), s.size());
3406 m_clients.send(peer_id, 0, data, true);
3409 void Server::SendOverrideDayNightRatio(u16 peer_id, bool do_override,
3412 std::ostringstream os(std::ios_base::binary);
3415 writeU16(os, TOCLIENT_OVERRIDE_DAY_NIGHT_RATIO);
3416 writeU8(os, do_override);
3417 writeU16(os, ratio*65535);
3420 std::string s = os.str();
3421 SharedBuffer<u8> data((u8 *)s.c_str(), s.size());
3423 m_clients.send(peer_id, 0, data, true);
3426 void Server::SendTimeOfDay(u16 peer_id, u16 time, f32 time_speed)
3428 DSTACK(__FUNCTION_NAME);
3431 SharedBuffer<u8> data(2+2+4);
3432 writeU16(&data[0], TOCLIENT_TIME_OF_DAY);
3433 writeU16(&data[2], time);
3434 writeF1000(&data[4], time_speed);
3436 if (peer_id == PEER_ID_INEXISTENT) {
3437 m_clients.sendToAll(0,data,true);
3441 m_clients.send(peer_id, 0, data, true);
3445 void Server::SendPlayerHP(u16 peer_id)
3447 DSTACK(__FUNCTION_NAME);
3448 PlayerSAO *playersao = getPlayerSAO(peer_id);
3450 playersao->m_hp_not_sent = false;
3451 SendHP(peer_id, playersao->getHP());
3452 m_script->player_event(playersao,"health_changed");
3454 // Send to other clients
3455 std::string str = gob_cmd_punched(playersao->readDamage(), playersao->getHP());
3456 ActiveObjectMessage aom(playersao->getId(), true, str);
3457 playersao->m_messages_out.push_back(aom);
3460 void Server::SendPlayerBreath(u16 peer_id)
3462 DSTACK(__FUNCTION_NAME);
3463 PlayerSAO *playersao = getPlayerSAO(peer_id);
3465 playersao->m_breath_not_sent = false;
3466 m_script->player_event(playersao,"breath_changed");
3467 SendBreath(peer_id, playersao->getBreath());
3470 void Server::SendMovePlayer(u16 peer_id)
3472 DSTACK(__FUNCTION_NAME);
3473 Player *player = m_env->getPlayer(peer_id);
3476 std::ostringstream os(std::ios_base::binary);
3477 writeU16(os, TOCLIENT_MOVE_PLAYER);
3478 writeV3F1000(os, player->getPosition());
3479 writeF1000(os, player->getPitch());
3480 writeF1000(os, player->getYaw());
3483 v3f pos = player->getPosition();
3484 f32 pitch = player->getPitch();
3485 f32 yaw = player->getYaw();
3486 verbosestream<<"Server: Sending TOCLIENT_MOVE_PLAYER"
3487 <<" pos=("<<pos.X<<","<<pos.Y<<","<<pos.Z<<")"
3494 std::string s = os.str();
3495 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3497 m_clients.send(peer_id, 0, data, true);
3500 void Server::SendLocalPlayerAnimations(u16 peer_id, v2s32 animation_frames[4], f32 animation_speed)
3502 std::ostringstream os(std::ios_base::binary);
3504 writeU16(os, TOCLIENT_LOCAL_PLAYER_ANIMATIONS);
3505 writeV2S32(os, animation_frames[0]);
3506 writeV2S32(os, animation_frames[1]);
3507 writeV2S32(os, animation_frames[2]);
3508 writeV2S32(os, animation_frames[3]);
3509 writeF1000(os, animation_speed);
3512 std::string s = os.str();
3513 SharedBuffer<u8> data((u8 *)s.c_str(), s.size());
3515 m_clients.send(peer_id, 0, data, true);
3518 void Server::SendEyeOffset(u16 peer_id, v3f first, v3f third)
3520 std::ostringstream os(std::ios_base::binary);
3522 writeU16(os, TOCLIENT_EYE_OFFSET);
3523 writeV3F1000(os, first);
3524 writeV3F1000(os, third);
3527 std::string s = os.str();
3528 SharedBuffer<u8> data((u8 *)s.c_str(), s.size());
3530 m_clients.send(peer_id, 0, data, true);
3532 void Server::SendPlayerPrivileges(u16 peer_id)
3534 Player *player = m_env->getPlayer(peer_id);
3536 if(player->peer_id == PEER_ID_INEXISTENT)
3539 std::set<std::string> privs;
3540 m_script->getAuth(player->getName(), NULL, &privs);
3542 std::ostringstream os(std::ios_base::binary);
3543 writeU16(os, TOCLIENT_PRIVILEGES);
3544 writeU16(os, privs.size());
3545 for(std::set<std::string>::const_iterator i = privs.begin();
3546 i != privs.end(); i++){
3547 os<<serializeString(*i);
3551 std::string s = os.str();
3552 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3554 m_clients.send(peer_id, 0, data, true);
3557 void Server::SendPlayerInventoryFormspec(u16 peer_id)
3559 Player *player = m_env->getPlayer(peer_id);
3561 if(player->peer_id == PEER_ID_INEXISTENT)
3564 std::ostringstream os(std::ios_base::binary);
3565 writeU16(os, TOCLIENT_INVENTORY_FORMSPEC);
3566 os<<serializeLongString(FORMSPEC_VERSION_STRING + player->inventory_formspec);
3569 std::string s = os.str();
3570 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3572 m_clients.send(peer_id, 0, data, true);
3575 s32 Server::playSound(const SimpleSoundSpec &spec,
3576 const ServerSoundParams ¶ms)
3578 // Find out initial position of sound
3579 bool pos_exists = false;
3580 v3f pos = params.getPos(m_env, &pos_exists);
3581 // If position is not found while it should be, cancel sound
3582 if(pos_exists != (params.type != ServerSoundParams::SSP_LOCAL))
3585 // Filter destination clients
3586 std::list<u16> dst_clients;
3587 if(params.to_player != "")
3589 Player *player = m_env->getPlayer(params.to_player.c_str());
3591 infostream<<"Server::playSound: Player \""<<params.to_player
3592 <<"\" not found"<<std::endl;
3595 if(player->peer_id == PEER_ID_INEXISTENT){
3596 infostream<<"Server::playSound: Player \""<<params.to_player
3597 <<"\" not connected"<<std::endl;
3600 dst_clients.push_back(player->peer_id);
3604 std::list<u16> clients = m_clients.getClientIDs();
3606 for(std::list<u16>::iterator
3607 i = clients.begin(); i != clients.end(); ++i)
3609 Player *player = m_env->getPlayer(*i);
3613 if(player->getPosition().getDistanceFrom(pos) >
3614 params.max_hear_distance)
3617 dst_clients.push_back(*i);
3620 if(dst_clients.size() == 0)
3624 s32 id = m_next_sound_id++;
3625 // The sound will exist as a reference in m_playing_sounds
3626 m_playing_sounds[id] = ServerPlayingSound();
3627 ServerPlayingSound &psound = m_playing_sounds[id];
3628 psound.params = params;
3629 for(std::list<u16>::iterator i = dst_clients.begin();
3630 i != dst_clients.end(); i++)
3631 psound.clients.insert(*i);
3633 std::ostringstream os(std::ios_base::binary);
3634 writeU16(os, TOCLIENT_PLAY_SOUND);
3636 os<<serializeString(spec.name);
3637 writeF1000(os, spec.gain * params.gain);
3638 writeU8(os, params.type);
3639 writeV3F1000(os, pos);
3640 writeU16(os, params.object);
3641 writeU8(os, params.loop);
3643 std::string s = os.str();
3644 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3646 for(std::list<u16>::iterator i = dst_clients.begin();
3647 i != dst_clients.end(); i++){
3649 m_clients.send(*i, 0, data, true);
3653 void Server::stopSound(s32 handle)
3655 // Get sound reference
3656 std::map<s32, ServerPlayingSound>::iterator i =
3657 m_playing_sounds.find(handle);
3658 if(i == m_playing_sounds.end())
3660 ServerPlayingSound &psound = i->second;
3662 std::ostringstream os(std::ios_base::binary);
3663 writeU16(os, TOCLIENT_STOP_SOUND);
3664 writeS32(os, handle);
3666 std::string s = os.str();
3667 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3669 for(std::set<u16>::iterator i = psound.clients.begin();
3670 i != psound.clients.end(); i++){
3672 m_clients.send(*i, 0, data, true);
3674 // Remove sound reference
3675 m_playing_sounds.erase(i);
3678 void Server::sendRemoveNode(v3s16 p, u16 ignore_id,
3679 std::list<u16> *far_players, float far_d_nodes)
3681 float maxd = far_d_nodes*BS;
3682 v3f p_f = intToFloat(p, BS);
3686 SharedBuffer<u8> reply(replysize);
3687 writeU16(&reply[0], TOCLIENT_REMOVENODE);
3688 writeS16(&reply[2], p.X);
3689 writeS16(&reply[4], p.Y);
3690 writeS16(&reply[6], p.Z);
3692 std::list<u16> clients = m_clients.getClientIDs();
3693 for(std::list<u16>::iterator
3694 i = clients.begin();
3695 i != clients.end(); ++i)
3700 Player *player = m_env->getPlayer(*i);
3703 // If player is far away, only set modified blocks not sent
3704 v3f player_pos = player->getPosition();
3705 if(player_pos.getDistanceFrom(p_f) > maxd)
3707 far_players->push_back(*i);
3714 m_clients.send(*i, 0, reply, true);
3718 void Server::sendAddNode(v3s16 p, MapNode n, u16 ignore_id,
3719 std::list<u16> *far_players, float far_d_nodes,
3720 bool remove_metadata)
3722 float maxd = far_d_nodes*BS;
3723 v3f p_f = intToFloat(p, BS);
3725 std::list<u16> clients = m_clients.getClientIDs();
3726 for(std::list<u16>::iterator
3727 i = clients.begin();
3728 i != clients.end(); ++i)
3734 Player *player = m_env->getPlayer(*i);
3737 // If player is far away, only set modified blocks not sent
3738 v3f player_pos = player->getPosition();
3739 if(player_pos.getDistanceFrom(p_f) > maxd)
3741 far_players->push_back(*i);
3746 SharedBuffer<u8> reply(0);
3748 RemoteClient* client = m_clients.lockedGetClientNoEx(*i);
3752 u32 replysize = 9 + MapNode::serializedLength(client->serialization_version);
3753 reply = SharedBuffer<u8>(replysize);
3754 writeU16(&reply[0], TOCLIENT_ADDNODE);
3755 writeS16(&reply[2], p.X);
3756 writeS16(&reply[4], p.Y);
3757 writeS16(&reply[6], p.Z);
3758 n.serialize(&reply[8], client->serialization_version);
3759 u32 index = 8 + MapNode::serializedLength(client->serialization_version);
3760 writeU8(&reply[index], remove_metadata ? 0 : 1);
3762 if (!remove_metadata) {
3763 if (client->net_proto_version <= 21) {
3764 // Old clients always clear metadata; fix it
3765 // by sending the full block again.
3766 client->SetBlockNotSent(p);
3773 if (reply.getSize() > 0)
3774 m_clients.send(*i, 0, reply, true);
3778 void Server::setBlockNotSent(v3s16 p)
3780 std::list<u16> clients = m_clients.getClientIDs();
3782 for(std::list<u16>::iterator
3783 i = clients.begin();
3784 i != clients.end(); ++i)
3786 RemoteClient *client = m_clients.lockedGetClientNoEx(*i);
3787 client->SetBlockNotSent(p);
3792 void Server::SendBlockNoLock(u16 peer_id, MapBlock *block, u8 ver, u16 net_proto_version)
3794 DSTACK(__FUNCTION_NAME);
3796 v3s16 p = block->getPos();
3800 bool completely_air = true;
3801 for(s16 z0=0; z0<MAP_BLOCKSIZE; z0++)
3802 for(s16 x0=0; x0<MAP_BLOCKSIZE; x0++)
3803 for(s16 y0=0; y0<MAP_BLOCKSIZE; y0++)
3805 if(block->getNodeNoEx(v3s16(x0,y0,z0)).d != CONTENT_AIR)
3807 completely_air = false;
3808 x0 = y0 = z0 = MAP_BLOCKSIZE; // Break out
3813 infostream<<"Server: Sending block ("<<p.X<<","<<p.Y<<","<<p.Z<<"): ";
3815 infostream<<"[completely air] ";
3816 infostream<<std::endl;
3820 Create a packet with the block in the right format
3823 std::ostringstream os(std::ios_base::binary);
3824 block->serialize(os, ver, false);
3825 block->serializeNetworkSpecific(os, net_proto_version);
3826 std::string s = os.str();
3827 SharedBuffer<u8> blockdata((u8*)s.c_str(), s.size());
3829 u32 replysize = 8 + blockdata.getSize();
3830 SharedBuffer<u8> reply(replysize);
3831 writeU16(&reply[0], TOCLIENT_BLOCKDATA);
3832 writeS16(&reply[2], p.X);
3833 writeS16(&reply[4], p.Y);
3834 writeS16(&reply[6], p.Z);
3835 memcpy(&reply[8], *blockdata, blockdata.getSize());
3837 /*infostream<<"Server: Sending block ("<<p.X<<","<<p.Y<<","<<p.Z<<")"
3838 <<": \tpacket size: "<<replysize<<std::endl;*/
3843 m_clients.send(peer_id, 2, reply, true);
3846 void Server::SendBlocks(float dtime)
3848 DSTACK(__FUNCTION_NAME);
3850 JMutexAutoLock envlock(m_env_mutex);
3851 //TODO check if one big lock could be faster then multiple small ones
3853 ScopeProfiler sp(g_profiler, "Server: sel and send blocks to clients");
3855 std::vector<PrioritySortedBlockTransfer> queue;
3857 s32 total_sending = 0;
3860 ScopeProfiler sp(g_profiler, "Server: selecting blocks for sending");
3862 std::list<u16> clients = m_clients.getClientIDs();
3865 for(std::list<u16>::iterator
3866 i = clients.begin();
3867 i != clients.end(); ++i)
3869 RemoteClient *client = m_clients.lockedGetClientNoEx(*i, CS_Active);
3874 total_sending += client->SendingCount();
3875 client->GetNextBlocks(m_env,m_emerge, dtime, queue);
3881 // Lowest priority number comes first.
3882 // Lowest is most important.
3883 std::sort(queue.begin(), queue.end());
3886 for(u32 i=0; i<queue.size(); i++)
3888 //TODO: Calculate limit dynamically
3889 if(total_sending >= g_settings->getS32
3890 ("max_simultaneous_block_sends_server_total"))
3893 PrioritySortedBlockTransfer q = queue[i];
3895 MapBlock *block = NULL;
3898 block = m_env->getMap().getBlockNoCreate(q.pos);
3900 catch(InvalidPositionException &e)
3905 RemoteClient *client = m_clients.lockedGetClientNoEx(q.peer_id, CS_Active);
3910 SendBlockNoLock(q.peer_id, block, client->serialization_version, client->net_proto_version);
3912 client->SentBlock(q.pos);
3918 void Server::fillMediaCache()
3920 DSTACK(__FUNCTION_NAME);
3922 infostream<<"Server: Calculating media file checksums"<<std::endl;
3924 // Collect all media file paths
3925 std::list<std::string> paths;
3926 for(std::vector<ModSpec>::iterator i = m_mods.begin();
3927 i != m_mods.end(); i++){
3928 const ModSpec &mod = *i;
3929 paths.push_back(mod.path + DIR_DELIM + "textures");
3930 paths.push_back(mod.path + DIR_DELIM + "sounds");
3931 paths.push_back(mod.path + DIR_DELIM + "media");
3932 paths.push_back(mod.path + DIR_DELIM + "models");
3934 paths.push_back(porting::path_user + DIR_DELIM + "textures" + DIR_DELIM + "server");
3936 // Collect media file information from paths into cache
3937 for(std::list<std::string>::iterator i = paths.begin();
3938 i != paths.end(); i++)
3940 std::string mediapath = *i;
3941 std::vector<fs::DirListNode> dirlist = fs::GetDirListing(mediapath);
3942 for(u32 j=0; j<dirlist.size(); j++){
3943 if(dirlist[j].dir) // Ignode dirs
3945 std::string filename = dirlist[j].name;
3946 // If name contains illegal characters, ignore the file
3947 if(!string_allowed(filename, TEXTURENAME_ALLOWED_CHARS)){
3948 infostream<<"Server: ignoring illegal file name: \""
3949 <<filename<<"\""<<std::endl;
3952 // If name is not in a supported format, ignore it
3953 const char *supported_ext[] = {
3954 ".png", ".jpg", ".bmp", ".tga",
3955 ".pcx", ".ppm", ".psd", ".wal", ".rgb",
3957 ".x", ".b3d", ".md2", ".obj",
3960 if(removeStringEnd(filename, supported_ext) == ""){
3961 infostream<<"Server: ignoring unsupported file extension: \""
3962 <<filename<<"\""<<std::endl;
3965 // Ok, attempt to load the file and add to cache
3966 std::string filepath = mediapath + DIR_DELIM + filename;
3968 std::ifstream fis(filepath.c_str(), std::ios_base::binary);
3969 if(fis.good() == false){
3970 errorstream<<"Server::fillMediaCache(): Could not open \""
3971 <<filename<<"\" for reading"<<std::endl;
3974 std::ostringstream tmp_os(std::ios_base::binary);
3978 fis.read(buf, 1024);
3979 std::streamsize len = fis.gcount();
3980 tmp_os.write(buf, len);
3989 errorstream<<"Server::fillMediaCache(): Failed to read \""
3990 <<filename<<"\""<<std::endl;
3993 if(tmp_os.str().length() == 0){
3994 errorstream<<"Server::fillMediaCache(): Empty file \""
3995 <<filepath<<"\""<<std::endl;
4000 sha1.addBytes(tmp_os.str().c_str(), tmp_os.str().length());
4002 unsigned char *digest = sha1.getDigest();
4003 std::string sha1_base64 = base64_encode(digest, 20);
4004 std::string sha1_hex = hex_encode((char*)digest, 20);
4008 this->m_media[filename] = MediaInfo(filepath, sha1_base64);
4009 verbosestream<<"Server: "<<sha1_hex<<" is "<<filename<<std::endl;
4014 struct SendableMediaAnnouncement
4017 std::string sha1_digest;
4019 SendableMediaAnnouncement(const std::string &name_="",
4020 const std::string &sha1_digest_=""):
4022 sha1_digest(sha1_digest_)
4026 void Server::sendMediaAnnouncement(u16 peer_id)
4028 DSTACK(__FUNCTION_NAME);
4030 verbosestream<<"Server: Announcing files to id("<<peer_id<<")"
4033 std::list<SendableMediaAnnouncement> file_announcements;
4035 for(std::map<std::string, MediaInfo>::iterator i = m_media.begin();
4036 i != m_media.end(); i++){
4038 file_announcements.push_back(
4039 SendableMediaAnnouncement(i->first, i->second.sha1_digest));
4043 std::ostringstream os(std::ios_base::binary);
4051 u16 length of sha1_digest
4056 writeU16(os, TOCLIENT_ANNOUNCE_MEDIA);
4057 writeU16(os, file_announcements.size());
4059 for(std::list<SendableMediaAnnouncement>::iterator
4060 j = file_announcements.begin();
4061 j != file_announcements.end(); ++j){
4062 os<<serializeString(j->name);
4063 os<<serializeString(j->sha1_digest);
4065 os<<serializeString(g_settings->get("remote_media"));
4068 std::string s = os.str();
4069 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
4072 m_clients.send(peer_id, 0, data, true);
4075 struct SendableMedia
4081 SendableMedia(const std::string &name_="", const std::string &path_="",
4082 const std::string &data_=""):
4089 void Server::sendRequestedMedia(u16 peer_id,
4090 const std::list<std::string> &tosend)
4092 DSTACK(__FUNCTION_NAME);
4094 verbosestream<<"Server::sendRequestedMedia(): "
4095 <<"Sending files to client"<<std::endl;
4099 // Put 5kB in one bunch (this is not accurate)
4100 u32 bytes_per_bunch = 5000;
4102 std::vector< std::list<SendableMedia> > file_bunches;
4103 file_bunches.push_back(std::list<SendableMedia>());
4105 u32 file_size_bunch_total = 0;
4107 for(std::list<std::string>::const_iterator i = tosend.begin();
4108 i != tosend.end(); ++i)
4110 const std::string &name = *i;
4112 if(m_media.find(name) == m_media.end()){
4113 errorstream<<"Server::sendRequestedMedia(): Client asked for "
4114 <<"unknown file \""<<(name)<<"\""<<std::endl;
4118 //TODO get path + name
4119 std::string tpath = m_media[name].path;
4122 std::ifstream fis(tpath.c_str(), std::ios_base::binary);
4123 if(fis.good() == false){
4124 errorstream<<"Server::sendRequestedMedia(): Could not open \""
4125 <<tpath<<"\" for reading"<<std::endl;
4128 std::ostringstream tmp_os(std::ios_base::binary);
4132 fis.read(buf, 1024);
4133 std::streamsize len = fis.gcount();
4134 tmp_os.write(buf, len);
4135 file_size_bunch_total += len;
4144 errorstream<<"Server::sendRequestedMedia(): Failed to read \""
4145 <<name<<"\""<<std::endl;
4148 /*infostream<<"Server::sendRequestedMedia(): Loaded \""
4149 <<tname<<"\""<<std::endl;*/
4151 file_bunches[file_bunches.size()-1].push_back(
4152 SendableMedia(name, tpath, tmp_os.str()));
4154 // Start next bunch if got enough data
4155 if(file_size_bunch_total >= bytes_per_bunch){
4156 file_bunches.push_back(std::list<SendableMedia>());
4157 file_size_bunch_total = 0;
4162 /* Create and send packets */
4164 u32 num_bunches = file_bunches.size();
4165 for(u32 i=0; i<num_bunches; i++)
4167 std::ostringstream os(std::ios_base::binary);
4171 u16 total number of texture bunches
4172 u16 index of this bunch
4173 u32 number of files in this bunch
4182 writeU16(os, TOCLIENT_MEDIA);
4183 writeU16(os, num_bunches);
4185 writeU32(os, file_bunches[i].size());
4187 for(std::list<SendableMedia>::iterator
4188 j = file_bunches[i].begin();
4189 j != file_bunches[i].end(); ++j){
4190 os<<serializeString(j->name);
4191 os<<serializeLongString(j->data);
4195 std::string s = os.str();
4196 verbosestream<<"Server::sendRequestedMedia(): bunch "
4197 <<i<<"/"<<num_bunches
4198 <<" files="<<file_bunches[i].size()
4199 <<" size=" <<s.size()<<std::endl;
4200 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
4202 m_clients.send(peer_id, 2, data, true);
4206 void Server::sendDetachedInventory(const std::string &name, u16 peer_id)
4208 if(m_detached_inventories.count(name) == 0){
4209 errorstream<<__FUNCTION_NAME<<": \""<<name<<"\" not found"<<std::endl;
4212 Inventory *inv = m_detached_inventories[name];
4214 std::ostringstream os(std::ios_base::binary);
4215 writeU16(os, TOCLIENT_DETACHED_INVENTORY);
4216 os<<serializeString(name);
4220 std::string s = os.str();
4221 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
4223 if (peer_id != PEER_ID_INEXISTENT)
4226 m_clients.send(peer_id, 0, data, true);
4230 m_clients.sendToAll(0,data,true);
4234 void Server::sendDetachedInventories(u16 peer_id)
4236 DSTACK(__FUNCTION_NAME);
4238 for(std::map<std::string, Inventory*>::iterator
4239 i = m_detached_inventories.begin();
4240 i != m_detached_inventories.end(); i++){
4241 const std::string &name = i->first;
4242 //Inventory *inv = i->second;
4243 sendDetachedInventory(name, peer_id);
4251 void Server::DiePlayer(u16 peer_id)
4253 DSTACK(__FUNCTION_NAME);
4255 PlayerSAO *playersao = getPlayerSAO(peer_id);
4258 infostream<<"Server::DiePlayer(): Player "
4259 <<playersao->getPlayer()->getName()
4260 <<" dies"<<std::endl;
4262 playersao->setHP(0);
4264 // Trigger scripted stuff
4265 m_script->on_dieplayer(playersao);
4267 SendPlayerHP(peer_id);
4268 SendDeathscreen(peer_id, false, v3f(0,0,0));
4271 void Server::RespawnPlayer(u16 peer_id)
4273 DSTACK(__FUNCTION_NAME);
4275 PlayerSAO *playersao = getPlayerSAO(peer_id);
4278 infostream<<"Server::RespawnPlayer(): Player "
4279 <<playersao->getPlayer()->getName()
4280 <<" respawns"<<std::endl;
4282 playersao->setHP(PLAYER_MAX_HP);
4284 bool repositioned = m_script->on_respawnplayer(playersao);
4286 v3f pos = findSpawnPos(m_env->getServerMap());
4287 playersao->setPos(pos);
4291 void Server::DenyAccess(u16 peer_id, const std::wstring &reason)
4293 DSTACK(__FUNCTION_NAME);
4295 SendAccessDenied(peer_id, reason);
4296 m_clients.event(peer_id, CSE_SetDenied);
4297 m_con.DisconnectPeer(peer_id);
4300 void Server::DeleteClient(u16 peer_id, ClientDeletionReason reason)
4302 DSTACK(__FUNCTION_NAME);
4303 std::wstring message;
4306 Clear references to playing sounds
4308 for(std::map<s32, ServerPlayingSound>::iterator
4309 i = m_playing_sounds.begin();
4310 i != m_playing_sounds.end();)
4312 ServerPlayingSound &psound = i->second;
4313 psound.clients.erase(peer_id);
4314 if(psound.clients.size() == 0)
4315 m_playing_sounds.erase(i++);
4320 Player *player = m_env->getPlayer(peer_id);
4322 // Collect information about leaving in chat
4324 if(player != NULL && reason != CDR_DENY)
4326 std::wstring name = narrow_to_wide(player->getName());
4329 message += L" left the game.";
4330 if(reason == CDR_TIMEOUT)
4331 message += L" (timed out)";
4335 /* Run scripts and remove from environment */
4339 PlayerSAO *playersao = player->getPlayerSAO();
4342 m_script->on_leaveplayer(playersao);
4344 playersao->disconnected();
4352 if(player != NULL && reason != CDR_DENY)
4354 std::ostringstream os(std::ios_base::binary);
4355 std::list<u16> clients = m_clients.getClientIDs();
4357 for(std::list<u16>::iterator
4358 i = clients.begin();
4359 i != clients.end(); ++i)
4362 Player *player = m_env->getPlayer(*i);
4365 // Get name of player
4366 os<<player->getName()<<" ";
4369 actionstream<<player->getName()<<" "
4370 <<(reason==CDR_TIMEOUT?"times out.":"leaves game.")
4371 <<" List of players: "<<os.str()<<std::endl;
4375 JMutexAutoLock env_lock(m_env_mutex);
4376 m_clients.DeleteClient(peer_id);
4380 // Send leave chat message to all remaining clients
4381 if(message.length() != 0)
4382 SendChatMessage(PEER_ID_INEXISTENT,message);
4385 void Server::UpdateCrafting(u16 peer_id)
4387 DSTACK(__FUNCTION_NAME);
4389 Player* player = m_env->getPlayer(peer_id);
4392 // Get a preview for crafting
4394 InventoryLocation loc;
4395 loc.setPlayer(player->getName());
4396 getCraftingResult(&player->inventory, preview, false, this);
4397 m_env->getScriptIface()->item_CraftPredict(preview, player->getPlayerSAO(), (&player->inventory)->getList("craft"), loc);
4399 // Put the new preview in
4400 InventoryList *plist = player->inventory.getList("craftpreview");
4402 assert(plist->getSize() >= 1);
4403 plist->changeItem(0, preview);
4406 RemoteClient* Server::getClient(u16 peer_id, ClientState state_min)
4408 RemoteClient *client = getClientNoEx(peer_id,state_min);
4410 throw ClientNotFoundException("Client not found");
4414 RemoteClient* Server::getClientNoEx(u16 peer_id, ClientState state_min)
4416 return m_clients.getClientNoEx(peer_id, state_min);
4419 std::string Server::getPlayerName(u16 peer_id)
4421 Player *player = m_env->getPlayer(peer_id);
4423 return "[id="+itos(peer_id)+"]";
4424 return player->getName();
4427 PlayerSAO* Server::getPlayerSAO(u16 peer_id)
4429 Player *player = m_env->getPlayer(peer_id);
4432 return player->getPlayerSAO();
4435 std::wstring Server::getStatusString()
4437 std::wostringstream os(std::ios_base::binary);
4440 os<<L"version="<<narrow_to_wide(minetest_version_simple);
4442 os<<L", uptime="<<m_uptime.get();
4444 os<<L", max_lag="<<m_env->getMaxLagEstimate();
4445 // Information about clients
4448 std::list<u16> clients = m_clients.getClientIDs();
4449 for(std::list<u16>::iterator i = clients.begin();
4450 i != clients.end(); ++i)
4453 Player *player = m_env->getPlayer(*i);
4454 // Get name of player
4455 std::wstring name = L"unknown";
4457 name = narrow_to_wide(player->getName());
4458 // Add name to information string
4466 if(((ServerMap*)(&m_env->getMap()))->isSavingEnabled() == false)
4467 os<<std::endl<<L"# Server: "<<" WARNING: Map saving is disabled.";
4468 if(g_settings->get("motd") != "")
4469 os<<std::endl<<L"# Server: "<<narrow_to_wide(g_settings->get("motd"));
4473 std::set<std::string> Server::getPlayerEffectivePrivs(const std::string &name)
4475 std::set<std::string> privs;
4476 m_script->getAuth(name, NULL, &privs);
4480 bool Server::checkPriv(const std::string &name, const std::string &priv)
4482 std::set<std::string> privs = getPlayerEffectivePrivs(name);
4483 return (privs.count(priv) != 0);
4486 void Server::reportPrivsModified(const std::string &name)
4489 std::list<u16> clients = m_clients.getClientIDs();
4490 for(std::list<u16>::iterator
4491 i = clients.begin();
4492 i != clients.end(); ++i){
4493 Player *player = m_env->getPlayer(*i);
4494 reportPrivsModified(player->getName());
4497 Player *player = m_env->getPlayer(name.c_str());
4500 SendPlayerPrivileges(player->peer_id);
4501 PlayerSAO *sao = player->getPlayerSAO();
4504 sao->updatePrivileges(
4505 getPlayerEffectivePrivs(name),
4510 void Server::reportInventoryFormspecModified(const std::string &name)
4512 Player *player = m_env->getPlayer(name.c_str());
4515 SendPlayerInventoryFormspec(player->peer_id);
4518 void Server::setIpBanned(const std::string &ip, const std::string &name)
4520 m_banmanager->add(ip, name);
4523 void Server::unsetIpBanned(const std::string &ip_or_name)
4525 m_banmanager->remove(ip_or_name);
4528 std::string Server::getBanDescription(const std::string &ip_or_name)
4530 return m_banmanager->getBanDescription(ip_or_name);
4533 void Server::notifyPlayer(const char *name, const std::wstring &msg)
4535 Player *player = m_env->getPlayer(name);
4539 if (player->peer_id == PEER_ID_INEXISTENT)
4542 SendChatMessage(player->peer_id, msg);
4545 bool Server::showFormspec(const char *playername, const std::string &formspec, const std::string &formname)
4547 Player *player = m_env->getPlayer(playername);
4551 infostream<<"showFormspec: couldn't find player:"<<playername<<std::endl;
4555 SendShowFormspecMessage(player->peer_id, formspec, formname);
4559 u32 Server::hudAdd(Player *player, HudElement *form) {
4563 u32 id = player->addHud(form);
4565 SendHUDAdd(player->peer_id, id, form);
4570 bool Server::hudRemove(Player *player, u32 id) {
4574 HudElement* todel = player->removeHud(id);
4581 SendHUDRemove(player->peer_id, id);
4585 bool Server::hudChange(Player *player, u32 id, HudElementStat stat, void *data) {
4589 SendHUDChange(player->peer_id, id, stat, data);
4593 bool Server::hudSetFlags(Player *player, u32 flags, u32 mask) {
4597 SendHUDSetFlags(player->peer_id, flags, mask);
4598 player->hud_flags = flags;
4600 PlayerSAO* playersao = player->getPlayerSAO();
4602 if (playersao == NULL)
4605 m_script->player_event(playersao, "hud_changed");
4609 bool Server::hudSetHotbarItemcount(Player *player, s32 hotbar_itemcount) {
4612 if (hotbar_itemcount <= 0 || hotbar_itemcount > HUD_HOTBAR_ITEMCOUNT_MAX)
4615 std::ostringstream os(std::ios::binary);
4616 writeS32(os, hotbar_itemcount);
4617 SendHUDSetParam(player->peer_id, HUD_PARAM_HOTBAR_ITEMCOUNT, os.str());
4621 void Server::hudSetHotbarImage(Player *player, std::string name) {
4625 SendHUDSetParam(player->peer_id, HUD_PARAM_HOTBAR_IMAGE, name);
4628 void Server::hudSetHotbarSelectedImage(Player *player, std::string name) {
4632 SendHUDSetParam(player->peer_id, HUD_PARAM_HOTBAR_SELECTED_IMAGE, name);
4635 bool Server::setLocalPlayerAnimations(Player *player, v2s32 animation_frames[4], f32 frame_speed)
4640 SendLocalPlayerAnimations(player->peer_id, animation_frames, frame_speed);
4644 bool Server::setPlayerEyeOffset(Player *player, v3f first, v3f third)
4649 SendEyeOffset(player->peer_id, first, third);
4653 bool Server::setSky(Player *player, const video::SColor &bgcolor,
4654 const std::string &type, const std::vector<std::string> ¶ms)
4659 SendSetSky(player->peer_id, bgcolor, type, params);
4663 bool Server::overrideDayNightRatio(Player *player, bool do_override,
4669 SendOverrideDayNightRatio(player->peer_id, do_override, ratio);
4673 void Server::notifyPlayers(const std::wstring &msg)
4675 SendChatMessage(PEER_ID_INEXISTENT,msg);
4678 void Server::spawnParticle(const char *playername, v3f pos,
4679 v3f velocity, v3f acceleration,
4680 float expirationtime, float size, bool
4681 collisiondetection, bool vertical, std::string texture)
4683 Player *player = m_env->getPlayer(playername);
4686 SendSpawnParticle(player->peer_id, pos, velocity, acceleration,
4687 expirationtime, size, collisiondetection, vertical, texture);
4690 void Server::spawnParticleAll(v3f pos, v3f velocity, v3f acceleration,
4691 float expirationtime, float size,
4692 bool collisiondetection, bool vertical, std::string texture)
4694 SendSpawnParticle(PEER_ID_INEXISTENT,pos, velocity, acceleration,
4695 expirationtime, size, collisiondetection, vertical, texture);
4698 u32 Server::addParticleSpawner(const char *playername,
4699 u16 amount, float spawntime,
4700 v3f minpos, v3f maxpos,
4701 v3f minvel, v3f maxvel,
4702 v3f minacc, v3f maxacc,
4703 float minexptime, float maxexptime,
4704 float minsize, float maxsize,
4705 bool collisiondetection, bool vertical, std::string texture)
4707 Player *player = m_env->getPlayer(playername);
4712 for(;;) // look for unused particlespawner id
4715 if (std::find(m_particlespawner_ids.begin(),
4716 m_particlespawner_ids.end(), id)
4717 == m_particlespawner_ids.end())
4719 m_particlespawner_ids.push_back(id);
4724 SendAddParticleSpawner(player->peer_id, amount, spawntime,
4725 minpos, maxpos, minvel, maxvel, minacc, maxacc,
4726 minexptime, maxexptime, minsize, maxsize,
4727 collisiondetection, vertical, texture, id);
4732 u32 Server::addParticleSpawnerAll(u16 amount, float spawntime,
4733 v3f minpos, v3f maxpos,
4734 v3f minvel, v3f maxvel,
4735 v3f minacc, v3f maxacc,
4736 float minexptime, float maxexptime,
4737 float minsize, float maxsize,
4738 bool collisiondetection, bool vertical, std::string texture)
4741 for(;;) // look for unused particlespawner id
4744 if (std::find(m_particlespawner_ids.begin(),
4745 m_particlespawner_ids.end(), id)
4746 == m_particlespawner_ids.end())
4748 m_particlespawner_ids.push_back(id);
4753 SendAddParticleSpawner(PEER_ID_INEXISTENT, amount, spawntime,
4754 minpos, maxpos, minvel, maxvel, minacc, maxacc,
4755 minexptime, maxexptime, minsize, maxsize,
4756 collisiondetection, vertical, texture, id);
4761 void Server::deleteParticleSpawner(const char *playername, u32 id)
4763 Player *player = m_env->getPlayer(playername);
4767 m_particlespawner_ids.erase(
4768 std::remove(m_particlespawner_ids.begin(),
4769 m_particlespawner_ids.end(), id),
4770 m_particlespawner_ids.end());
4771 SendDeleteParticleSpawner(player->peer_id, id);
4774 void Server::deleteParticleSpawnerAll(u32 id)
4776 m_particlespawner_ids.erase(
4777 std::remove(m_particlespawner_ids.begin(),
4778 m_particlespawner_ids.end(), id),
4779 m_particlespawner_ids.end());
4780 SendDeleteParticleSpawner(PEER_ID_INEXISTENT, id);
4783 Inventory* Server::createDetachedInventory(const std::string &name)
4785 if(m_detached_inventories.count(name) > 0){
4786 infostream<<"Server clearing detached inventory \""<<name<<"\""<<std::endl;
4787 delete m_detached_inventories[name];
4789 infostream<<"Server creating detached inventory \""<<name<<"\""<<std::endl;
4791 Inventory *inv = new Inventory(m_itemdef);
4793 m_detached_inventories[name] = inv;
4794 //TODO find a better way to do this
4795 sendDetachedInventory(name,PEER_ID_INEXISTENT);
4802 BoolScopeSet(bool *dst, bool val):
4805 m_orig_state = *m_dst;
4810 *m_dst = m_orig_state;
4817 // actions: time-reversed list
4818 // Return value: success/failure
4819 bool Server::rollbackRevertActions(const std::list<RollbackAction> &actions,
4820 std::list<std::string> *log)
4822 infostream<<"Server::rollbackRevertActions(len="<<actions.size()<<")"<<std::endl;
4823 ServerMap *map = (ServerMap*)(&m_env->getMap());
4824 // Disable rollback report sink while reverting
4825 BoolScopeSet rollback_scope_disable(&m_rollback_sink_enabled, false);
4827 // Fail if no actions to handle
4828 if(actions.empty()){
4829 log->push_back("Nothing to do.");
4836 for(std::list<RollbackAction>::const_iterator
4837 i = actions.begin();
4838 i != actions.end(); i++)
4840 const RollbackAction &action = *i;
4842 bool success = action.applyRevert(map, this, this);
4845 std::ostringstream os;
4846 os<<"Revert of step ("<<num_tried<<") "<<action.toString()<<" failed";
4847 infostream<<"Map::rollbackRevertActions(): "<<os.str()<<std::endl;
4849 log->push_back(os.str());
4851 std::ostringstream os;
4852 os<<"Successfully reverted step ("<<num_tried<<") "<<action.toString();
4853 infostream<<"Map::rollbackRevertActions(): "<<os.str()<<std::endl;
4855 log->push_back(os.str());
4859 infostream<<"Map::rollbackRevertActions(): "<<num_failed<<"/"<<num_tried
4860 <<" failed"<<std::endl;
4862 // Call it done if less than half failed
4863 return num_failed <= num_tried/2;
4866 // IGameDef interface
4868 IItemDefManager* Server::getItemDefManager()
4872 INodeDefManager* Server::getNodeDefManager()
4876 ICraftDefManager* Server::getCraftDefManager()
4880 ITextureSource* Server::getTextureSource()
4884 IShaderSource* Server::getShaderSource()
4888 u16 Server::allocateUnknownNodeId(const std::string &name)
4890 return m_nodedef->allocateDummy(name);
4892 ISoundManager* Server::getSoundManager()
4894 return &dummySoundManager;
4896 MtEventManager* Server::getEventManager()
4900 IRollbackReportSink* Server::getRollbackReportSink()
4902 if(!m_enable_rollback_recording)
4904 if(!m_rollback_sink_enabled)
4909 IWritableItemDefManager* Server::getWritableItemDefManager()
4913 IWritableNodeDefManager* Server::getWritableNodeDefManager()
4917 IWritableCraftDefManager* Server::getWritableCraftDefManager()
4922 const ModSpec* Server::getModSpec(const std::string &modname)
4924 for(std::vector<ModSpec>::iterator i = m_mods.begin();
4925 i != m_mods.end(); i++){
4926 const ModSpec &mod = *i;
4927 if(mod.name == modname)
4932 void Server::getModNames(std::list<std::string> &modlist)
4934 for(std::vector<ModSpec>::iterator i = m_mods.begin(); i != m_mods.end(); i++)
4936 modlist.push_back(i->name);
4939 std::string Server::getBuiltinLuaPath()
4941 return porting::path_share + DIR_DELIM + "builtin";
4944 v3f findSpawnPos(ServerMap &map)
4946 //return v3f(50,50,50)*BS;
4951 nodepos = v2s16(0,0);
4956 s16 water_level = map.getWaterLevel();
4958 // Try to find a good place a few times
4959 for(s32 i=0; i<1000; i++)
4962 // We're going to try to throw the player to this position
4963 v2s16 nodepos2d = v2s16(
4964 -range + (myrand() % (range * 2)),
4965 -range + (myrand() % (range * 2)));
4967 // Get ground height at point
4968 s16 groundheight = map.findGroundLevel(nodepos2d);
4969 if (groundheight <= water_level) // Don't go underwater
4971 if (groundheight > water_level + 6) // Don't go to high places
4974 nodepos = v3s16(nodepos2d.X, groundheight, nodepos2d.Y);
4975 bool is_good = false;
4977 for (s32 i = 0; i < 10; i++) {
4978 v3s16 blockpos = getNodeBlockPos(nodepos);
4979 map.emergeBlock(blockpos, true);
4980 content_t c = map.getNodeNoEx(nodepos).getContent();
4981 if (c == CONTENT_AIR || c == CONTENT_IGNORE) {
4983 if (air_count >= 2){
4991 // Found a good place
4992 //infostream<<"Searched through "<<i<<" places."<<std::endl;
4998 return intToFloat(nodepos, BS);
5001 PlayerSAO* Server::emergePlayer(const char *name, u16 peer_id)
5003 RemotePlayer *player = NULL;
5004 bool newplayer = false;
5007 Try to get an existing player
5009 player = static_cast<RemotePlayer*>(m_env->getPlayer(name));
5011 // If player is already connected, cancel
5012 if(player != NULL && player->peer_id != 0)
5014 infostream<<"emergePlayer(): Player already connected"<<std::endl;
5019 If player with the wanted peer_id already exists, cancel.
5021 if(m_env->getPlayer(peer_id) != NULL)
5023 infostream<<"emergePlayer(): Player with wrong name but same"
5024 " peer_id already exists"<<std::endl;
5028 // Load player if it isn't already loaded
5030 player = static_cast<RemotePlayer*>(m_env->loadPlayer(name));
5033 // Create player if it doesn't exist
5036 player = new RemotePlayer(this);
5037 player->updateName(name);
5038 /* Set player position */
5039 infostream<<"Server: Finding spawn place for player \""
5040 <<name<<"\""<<std::endl;
5041 v3f pos = findSpawnPos(m_env->getServerMap());
5042 player->setPosition(pos);
5044 /* Add player to environment */
5045 m_env->addPlayer(player);
5048 // Create a new player active object
5049 PlayerSAO *playersao = new PlayerSAO(m_env, player, peer_id,
5050 getPlayerEffectivePrivs(player->getName()),
5053 /* Clean up old HUD elements from previous sessions */
5056 /* Add object to environment */
5057 m_env->addActiveObject(playersao);
5061 m_script->on_newplayer(playersao);
5067 void dedicated_server_loop(Server &server, bool &kill)
5069 DSTACK(__FUNCTION_NAME);
5071 verbosestream<<"dedicated_server_loop()"<<std::endl;
5073 IntervalLimiter m_profiler_interval;
5077 float steplen = g_settings->getFloat("dedicated_server_step");
5078 // This is kind of a hack but can be done like this
5079 // because server.step() is very light
5081 ScopeProfiler sp(g_profiler, "dedicated server sleep");
5082 sleep_ms((int)(steplen*1000.0));
5084 server.step(steplen);
5086 if(server.getShutdownRequested() || kill)
5088 infostream<<"Dedicated server quitting"<<std::endl;
5090 if(g_settings->getBool("server_announce") == true)
5091 ServerList::sendAnnounce("delete");
5099 float profiler_print_interval =
5100 g_settings->getFloat("profiler_print_interval");
5101 if(profiler_print_interval != 0)
5103 if(m_profiler_interval.step(steplen, profiler_print_interval))
5105 infostream<<"Profiler:"<<std::endl;
5106 g_profiler->print(infostream);
5107 g_profiler->clear();