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))
1453 char playername[PLAYERNAME_SIZE];
1454 for(u32 i=0; i<PLAYERNAME_SIZE-1; i++)
1456 playername[i] = data[3+i];
1458 playername[PLAYERNAME_SIZE-1] = 0;
1460 if(playername[0]=='\0')
1462 actionstream<<"Server: Player with an empty name "
1463 <<"tried to connect from "<<addr_s<<std::endl;
1464 DenyAccess(peer_id, L"Empty name");
1468 if(string_allowed(playername, PLAYERNAME_ALLOWED_CHARS)==false)
1470 actionstream<<"Server: Player with an invalid name "
1471 <<"tried to connect from "<<addr_s<<std::endl;
1472 DenyAccess(peer_id, L"Name contains unallowed characters");
1476 if(!isSingleplayer() && strcasecmp(playername, "singleplayer") == 0)
1478 actionstream<<"Server: Player with the name \"singleplayer\" "
1479 <<"tried to connect from "<<addr_s<<std::endl;
1480 DenyAccess(peer_id, L"Name is not allowed");
1486 if(m_script->on_prejoinplayer(playername, addr_s, reason))
1488 actionstream<<"Server: Player with the name \""<<playername<<"\" "
1489 <<"tried to connect from "<<addr_s<<" "
1490 <<"but it was disallowed for the following reason: "
1491 <<reason<<std::endl;
1492 DenyAccess(peer_id, narrow_to_wide(reason.c_str()));
1497 infostream<<"Server: New connection: \""<<playername<<"\" from "
1498 <<addr_s<<" (peer_id="<<peer_id<<")"<<std::endl;
1501 char given_password[PASSWORD_SIZE];
1502 if(datasize < 2+1+PLAYERNAME_SIZE+PASSWORD_SIZE)
1504 // old version - assume blank password
1505 given_password[0] = 0;
1509 for(u32 i=0; i<PASSWORD_SIZE-1; i++)
1511 given_password[i] = data[23+i];
1513 given_password[PASSWORD_SIZE-1] = 0;
1516 if(!base64_is_valid(given_password)){
1517 actionstream<<"Server: "<<playername
1518 <<" supplied invalid password hash"<<std::endl;
1519 DenyAccess(peer_id, L"Invalid password hash");
1523 // Enforce user limit.
1524 // Don't enforce for users that have some admin right
1525 if(m_clients.getClientIDs(CS_Created).size() >= g_settings->getU16("max_users") &&
1526 !checkPriv(playername, "server") &&
1527 !checkPriv(playername, "ban") &&
1528 !checkPriv(playername, "privs") &&
1529 !checkPriv(playername, "password") &&
1530 playername != g_settings->get("name"))
1532 actionstream<<"Server: "<<playername<<" tried to join, but there"
1533 <<" are already max_users="
1534 <<g_settings->getU16("max_users")<<" players."<<std::endl;
1535 DenyAccess(peer_id, L"Too many users.");
1539 std::string checkpwd; // Password hash to check against
1540 bool has_auth = m_script->getAuth(playername, &checkpwd, NULL);
1542 // If no authentication info exists for user, create it
1544 if(!isSingleplayer() &&
1545 g_settings->getBool("disallow_empty_password") &&
1546 std::string(given_password) == ""){
1547 actionstream<<"Server: "<<playername
1548 <<" supplied empty password"<<std::endl;
1549 DenyAccess(peer_id, L"Empty passwords are "
1550 L"disallowed. Set a password and try again.");
1553 std::wstring raw_default_password =
1554 narrow_to_wide(g_settings->get("default_password"));
1555 std::string initial_password =
1556 translatePassword(playername, raw_default_password);
1558 // If default_password is empty, allow any initial password
1559 if (raw_default_password.length() == 0)
1560 initial_password = given_password;
1562 m_script->createAuth(playername, initial_password);
1565 has_auth = m_script->getAuth(playername, &checkpwd, NULL);
1568 actionstream<<"Server: "<<playername<<" cannot be authenticated"
1569 <<" (auth handler does not work?)"<<std::endl;
1570 DenyAccess(peer_id, L"Not allowed to login");
1574 if(given_password != checkpwd){
1575 actionstream<<"Server: "<<playername<<" supplied wrong password"
1577 DenyAccess(peer_id, L"Wrong password");
1581 RemotePlayer *player =
1582 static_cast<RemotePlayer*>(m_env->getPlayer(playername));
1584 if(player && player->peer_id != 0){
1585 errorstream<<"Server: "<<playername<<": Failed to emerge player"
1586 <<" (player allocated to an another client)"<<std::endl;
1587 DenyAccess(peer_id, L"Another client is connected with this "
1588 L"name. If your client closed unexpectedly, try again in "
1592 m_clients.setPlayerName(peer_id,playername);
1595 Answer with a TOCLIENT_INIT
1598 SharedBuffer<u8> reply(2+1+6+8+4);
1599 writeU16(&reply[0], TOCLIENT_INIT);
1600 writeU8(&reply[2], deployed);
1601 //send dummy pos for legacy reasons only
1602 writeV3S16(&reply[2+1], floatToInt(v3f(0,0,0), BS));
1603 writeU64(&reply[2+1+6], m_env->getServerMap().getSeed());
1604 writeF1000(&reply[2+1+6+8], g_settings->getFloat("dedicated_server_step"));
1607 m_clients.send(peer_id, 0, reply, true);
1608 m_clients.event(peer_id, CSE_Init);
1614 if(command == TOSERVER_INIT2)
1617 verbosestream<<"Server: Got TOSERVER_INIT2 from "
1618 <<peer_id<<std::endl;
1620 m_clients.event(peer_id, CSE_GotInit2);
1621 u16 protocol_version = m_clients.getProtocolVersion(peer_id);
1624 ///// begin compatibility code
1625 PlayerSAO* playersao = NULL;
1626 if (protocol_version <= 22) {
1627 playersao = StageTwoClientInit(peer_id);
1629 if (playersao == NULL) {
1631 << "TOSERVER_INIT2 stage 2 client init failed for peer "
1632 << peer_id << std::endl;
1636 ///// end compatibility code
1639 Send some initialization data
1642 infostream<<"Server: Sending content to "
1643 <<getPlayerName(peer_id)<<std::endl;
1645 // Send player movement settings
1646 SendMovement(peer_id);
1648 // Send item definitions
1649 SendItemDef(peer_id, m_itemdef, protocol_version);
1651 // Send node definitions
1652 SendNodeDef(peer_id, m_nodedef, protocol_version);
1654 m_clients.event(peer_id, CSE_SetDefinitionsSent);
1656 // Send media announcement
1657 sendMediaAnnouncement(peer_id);
1659 // Send detached inventories
1660 sendDetachedInventories(peer_id);
1663 u16 time = m_env->getTimeOfDay();
1664 float time_speed = g_settings->getFloat("time_speed");
1665 SendTimeOfDay(peer_id, time, time_speed);
1667 ///// begin compatibility code
1668 if (protocol_version <= 22) {
1669 m_clients.event(peer_id, CSE_SetClientReady);
1670 m_script->on_joinplayer(playersao);
1672 ///// end compatibility code
1674 // Warnings about protocol version can be issued here
1675 if(getClient(peer_id)->net_proto_version < LATEST_PROTOCOL_VERSION)
1677 SendChatMessage(peer_id, L"# Server: WARNING: YOUR CLIENT'S "
1678 L"VERSION MAY NOT BE FULLY COMPATIBLE WITH THIS SERVER!");
1684 u8 peer_ser_ver = getClient(peer_id, CS_InitDone)->serialization_version;
1685 u16 peer_proto_ver = getClient(peer_id, CS_InitDone)->net_proto_version;
1687 if(peer_ser_ver == SER_FMT_VER_INVALID)
1689 errorstream<<"Server::ProcessData(): Cancelling: Peer"
1690 " serialization format invalid or not initialized."
1691 " Skipping incoming command="<<command<<std::endl;
1695 /* Handle commands relate to client startup */
1696 if(command == TOSERVER_REQUEST_MEDIA) {
1697 std::string datastring((char*)&data[2], datasize-2);
1698 std::istringstream is(datastring, std::ios_base::binary);
1700 std::list<std::string> tosend;
1701 u16 numfiles = readU16(is);
1703 infostream<<"Sending "<<numfiles<<" files to "
1704 <<getPlayerName(peer_id)<<std::endl;
1705 verbosestream<<"TOSERVER_REQUEST_MEDIA: "<<std::endl;
1707 for(int i = 0; i < numfiles; i++) {
1708 std::string name = deSerializeString(is);
1709 tosend.push_back(name);
1710 verbosestream<<"TOSERVER_REQUEST_MEDIA: requested file "
1714 sendRequestedMedia(peer_id, tosend);
1717 else if(command == TOSERVER_RECEIVED_MEDIA) {
1720 else if(command == TOSERVER_CLIENT_READY) {
1721 // clients <= protocol version 22 did not send ready message,
1722 // they're already initialized
1723 if (peer_proto_ver <= 22) {
1724 infostream << "Client sent message not expected by a "
1725 << "client using protocol version <= 22,"
1726 << "disconnecing peer_id: " << peer_id << std::endl;
1727 m_con.DisconnectPeer(peer_id);
1731 PlayerSAO* playersao = StageTwoClientInit(peer_id);
1733 if (playersao == NULL) {
1735 << "TOSERVER_CLIENT_READY stage 2 client init failed for peer_id: "
1736 << peer_id << std::endl;
1737 m_con.DisconnectPeer(peer_id);
1742 if(datasize < 2+8) {
1744 << "TOSERVER_CLIENT_READY client sent inconsistent data, disconnecting peer_id: "
1745 << peer_id << std::endl;
1746 m_con.DisconnectPeer(peer_id);
1750 m_clients.setClientVersion(
1752 data[2], data[3], data[4],
1753 std::string((char*) &data[8],(u16) data[6]));
1755 m_clients.event(peer_id, CSE_SetClientReady);
1756 m_script->on_joinplayer(playersao);
1759 else if(command == TOSERVER_GOTBLOCKS)
1772 u16 count = data[2];
1773 for(u16 i=0; i<count; i++)
1775 if((s16)datasize < 2+1+(i+1)*6)
1776 throw con::InvalidIncomingDataException
1777 ("GOTBLOCKS length is too short");
1778 v3s16 p = readV3S16(&data[2+1+i*6]);
1779 /*infostream<<"Server: GOTBLOCKS ("
1780 <<p.X<<","<<p.Y<<","<<p.Z<<")"<<std::endl;*/
1781 RemoteClient *client = getClient(peer_id);
1782 client->GotBlock(p);
1787 if (m_clients.getClientState(peer_id) < CS_Active)
1789 if (command == TOSERVER_PLAYERPOS) return;
1791 errorstream<<"Got packet command: " << command << " for peer id "
1792 << peer_id << " but client isn't active yet. Dropping packet "
1797 Player *player = m_env->getPlayer(peer_id);
1798 if(player == NULL) {
1799 errorstream<<"Server::ProcessData(): Cancelling: "
1800 "No player for peer_id="<<peer_id
1801 << " disconnecting peer!" <<std::endl;
1802 m_con.DisconnectPeer(peer_id);
1806 PlayerSAO *playersao = player->getPlayerSAO();
1807 if(playersao == NULL) {
1808 errorstream<<"Server::ProcessData(): Cancelling: "
1809 "No player object for peer_id="<<peer_id
1810 << " disconnecting peer!" <<std::endl;
1811 m_con.DisconnectPeer(peer_id);
1815 if(command == TOSERVER_PLAYERPOS)
1817 if(datasize < 2+12+12+4+4)
1821 v3s32 ps = readV3S32(&data[start+2]);
1822 v3s32 ss = readV3S32(&data[start+2+12]);
1823 f32 pitch = (f32)readS32(&data[2+12+12]) / 100.0;
1824 f32 yaw = (f32)readS32(&data[2+12+12+4]) / 100.0;
1826 if(datasize >= 2+12+12+4+4+4)
1827 keyPressed = (u32)readU32(&data[2+12+12+4+4]);
1828 v3f position((f32)ps.X/100., (f32)ps.Y/100., (f32)ps.Z/100.);
1829 v3f speed((f32)ss.X/100., (f32)ss.Y/100., (f32)ss.Z/100.);
1830 pitch = wrapDegrees(pitch);
1831 yaw = wrapDegrees(yaw);
1833 player->setPosition(position);
1834 player->setSpeed(speed);
1835 player->setPitch(pitch);
1836 player->setYaw(yaw);
1837 player->keyPressed=keyPressed;
1838 player->control.up = (bool)(keyPressed&1);
1839 player->control.down = (bool)(keyPressed&2);
1840 player->control.left = (bool)(keyPressed&4);
1841 player->control.right = (bool)(keyPressed&8);
1842 player->control.jump = (bool)(keyPressed&16);
1843 player->control.aux1 = (bool)(keyPressed&32);
1844 player->control.sneak = (bool)(keyPressed&64);
1845 player->control.LMB = (bool)(keyPressed&128);
1846 player->control.RMB = (bool)(keyPressed&256);
1848 bool cheated = playersao->checkMovementCheat();
1851 m_script->on_cheat(playersao, "moved_too_fast");
1854 /*infostream<<"Server::ProcessData(): Moved player "<<peer_id<<" to "
1855 <<"("<<position.X<<","<<position.Y<<","<<position.Z<<")"
1856 <<" pitch="<<pitch<<" yaw="<<yaw<<std::endl;*/
1858 else if(command == TOSERVER_DELETEDBLOCKS)
1871 u16 count = data[2];
1872 for(u16 i=0; i<count; i++)
1874 if((s16)datasize < 2+1+(i+1)*6)
1875 throw con::InvalidIncomingDataException
1876 ("DELETEDBLOCKS length is too short");
1877 v3s16 p = readV3S16(&data[2+1+i*6]);
1878 /*infostream<<"Server: DELETEDBLOCKS ("
1879 <<p.X<<","<<p.Y<<","<<p.Z<<")"<<std::endl;*/
1880 RemoteClient *client = getClient(peer_id);
1881 client->SetBlockNotSent(p);
1884 else if(command == TOSERVER_CLICK_OBJECT)
1886 infostream<<"Server: CLICK_OBJECT not supported anymore"<<std::endl;
1889 else if(command == TOSERVER_CLICK_ACTIVEOBJECT)
1891 infostream<<"Server: CLICK_ACTIVEOBJECT not supported anymore"<<std::endl;
1894 else if(command == TOSERVER_GROUND_ACTION)
1896 infostream<<"Server: GROUND_ACTION not supported anymore"<<std::endl;
1900 else if(command == TOSERVER_RELEASE)
1902 infostream<<"Server: RELEASE not supported anymore"<<std::endl;
1905 else if(command == TOSERVER_SIGNTEXT)
1907 infostream<<"Server: SIGNTEXT not supported anymore"
1911 else if(command == TOSERVER_SIGNNODETEXT)
1913 infostream<<"Server: SIGNNODETEXT not supported anymore"
1917 else if(command == TOSERVER_INVENTORY_ACTION)
1919 // Strip command and create a stream
1920 std::string datastring((char*)&data[2], datasize-2);
1921 verbosestream<<"TOSERVER_INVENTORY_ACTION: data="<<datastring<<std::endl;
1922 std::istringstream is(datastring, std::ios_base::binary);
1924 InventoryAction *a = InventoryAction::deSerialize(is);
1927 infostream<<"TOSERVER_INVENTORY_ACTION: "
1928 <<"InventoryAction::deSerialize() returned NULL"
1933 // If something goes wrong, this player is to blame
1934 RollbackScopeActor rollback_scope(m_rollback,
1935 std::string("player:")+player->getName());
1938 Note: Always set inventory not sent, to repair cases
1939 where the client made a bad prediction.
1943 Handle restrictions and special cases of the move action
1945 if(a->getType() == IACTION_MOVE)
1947 IMoveAction *ma = (IMoveAction*)a;
1949 ma->from_inv.applyCurrentPlayer(player->getName());
1950 ma->to_inv.applyCurrentPlayer(player->getName());
1952 setInventoryModified(ma->from_inv);
1953 setInventoryModified(ma->to_inv);
1955 bool from_inv_is_current_player =
1956 (ma->from_inv.type == InventoryLocation::PLAYER) &&
1957 (ma->from_inv.name == player->getName());
1959 bool to_inv_is_current_player =
1960 (ma->to_inv.type == InventoryLocation::PLAYER) &&
1961 (ma->to_inv.name == player->getName());
1964 Disable moving items out of craftpreview
1966 if(ma->from_list == "craftpreview")
1968 infostream<<"Ignoring IMoveAction from "
1969 <<(ma->from_inv.dump())<<":"<<ma->from_list
1970 <<" to "<<(ma->to_inv.dump())<<":"<<ma->to_list
1971 <<" because src is "<<ma->from_list<<std::endl;
1977 Disable moving items into craftresult and craftpreview
1979 if(ma->to_list == "craftpreview" || ma->to_list == "craftresult")
1981 infostream<<"Ignoring IMoveAction from "
1982 <<(ma->from_inv.dump())<<":"<<ma->from_list
1983 <<" to "<<(ma->to_inv.dump())<<":"<<ma->to_list
1984 <<" because dst is "<<ma->to_list<<std::endl;
1989 // Disallow moving items in elsewhere than player's inventory
1990 // if not allowed to interact
1991 if(!checkPriv(player->getName(), "interact") &&
1992 (!from_inv_is_current_player ||
1993 !to_inv_is_current_player))
1995 infostream<<"Cannot move outside of player's inventory: "
1996 <<"No interact privilege"<<std::endl;
2002 Handle restrictions and special cases of the drop action
2004 else if(a->getType() == IACTION_DROP)
2006 IDropAction *da = (IDropAction*)a;
2008 da->from_inv.applyCurrentPlayer(player->getName());
2010 setInventoryModified(da->from_inv);
2013 Disable dropping items out of craftpreview
2015 if(da->from_list == "craftpreview")
2017 infostream<<"Ignoring IDropAction from "
2018 <<(da->from_inv.dump())<<":"<<da->from_list
2019 <<" because src is "<<da->from_list<<std::endl;
2024 // Disallow dropping items if not allowed to interact
2025 if(!checkPriv(player->getName(), "interact"))
2032 Handle restrictions and special cases of the craft action
2034 else if(a->getType() == IACTION_CRAFT)
2036 ICraftAction *ca = (ICraftAction*)a;
2038 ca->craft_inv.applyCurrentPlayer(player->getName());
2040 setInventoryModified(ca->craft_inv);
2042 //bool craft_inv_is_current_player =
2043 // (ca->craft_inv.type == InventoryLocation::PLAYER) &&
2044 // (ca->craft_inv.name == player->getName());
2046 // Disallow crafting if not allowed to interact
2047 if(!checkPriv(player->getName(), "interact"))
2049 infostream<<"Cannot craft: "
2050 <<"No interact privilege"<<std::endl;
2057 a->apply(this, playersao, this);
2061 else if(command == TOSERVER_CHAT_MESSAGE)
2069 std::string datastring((char*)&data[2], datasize-2);
2070 std::istringstream is(datastring, std::ios_base::binary);
2073 is.read((char*)buf, 2);
2074 u16 len = readU16(buf);
2076 std::wstring message;
2077 for(u16 i=0; i<len; i++)
2079 is.read((char*)buf, 2);
2080 message += (wchar_t)readU16(buf);
2083 // If something goes wrong, this player is to blame
2084 RollbackScopeActor rollback_scope(m_rollback,
2085 std::string("player:")+player->getName());
2087 // Get player name of this client
2088 std::wstring name = narrow_to_wide(player->getName());
2091 bool ate = m_script->on_chat_message(player->getName(),
2092 wide_to_narrow(message));
2093 // If script ate the message, don't proceed
2097 // Line to send to players
2099 // Whether to send to the player that sent the line
2100 bool send_to_sender_only = false;
2102 // Commands are implemented in Lua, so only catch invalid
2103 // commands that were not "eaten" and send an error back
2104 if(message[0] == L'/')
2106 message = message.substr(1);
2107 send_to_sender_only = true;
2108 if(message.length() == 0)
2109 line += L"-!- Empty command";
2111 line += L"-!- Invalid command: " + str_split(message, L' ')[0];
2115 if(checkPriv(player->getName(), "shout")){
2121 line += L"-!- You don't have permission to shout.";
2122 send_to_sender_only = true;
2129 Send the message to sender
2131 if (send_to_sender_only)
2133 SendChatMessage(peer_id, line);
2136 Send the message to others
2140 actionstream<<"CHAT: "<<wide_to_narrow(line)<<std::endl;
2142 std::list<u16> clients = m_clients.getClientIDs();
2144 for(std::list<u16>::iterator
2145 i = clients.begin();
2146 i != clients.end(); ++i)
2149 SendChatMessage(*i, line);
2154 else if(command == TOSERVER_DAMAGE)
2156 std::string datastring((char*)&data[2], datasize-2);
2157 std::istringstream is(datastring, std::ios_base::binary);
2158 u8 damage = readU8(is);
2160 if(g_settings->getBool("enable_damage"))
2162 actionstream<<player->getName()<<" damaged by "
2163 <<(int)damage<<" hp at "<<PP(player->getPosition()/BS)
2166 playersao->setHP(playersao->getHP() - damage);
2168 if(playersao->getHP() == 0 && playersao->m_hp_not_sent)
2171 if(playersao->m_hp_not_sent)
2172 SendPlayerHP(peer_id);
2175 else if(command == TOSERVER_BREATH)
2177 std::string datastring((char*)&data[2], datasize-2);
2178 std::istringstream is(datastring, std::ios_base::binary);
2179 u16 breath = readU16(is);
2180 playersao->setBreath(breath);
2181 m_script->player_event(playersao,"breath_changed");
2183 else if(command == TOSERVER_PASSWORD)
2186 [0] u16 TOSERVER_PASSWORD
2187 [2] u8[28] old password
2188 [30] u8[28] new password
2191 if(datasize != 2+PASSWORD_SIZE*2)
2193 /*char password[PASSWORD_SIZE];
2194 for(u32 i=0; i<PASSWORD_SIZE-1; i++)
2195 password[i] = data[2+i];
2196 password[PASSWORD_SIZE-1] = 0;*/
2198 for(u32 i=0; i<PASSWORD_SIZE-1; i++)
2206 for(u32 i=0; i<PASSWORD_SIZE-1; i++)
2208 char c = data[2+PASSWORD_SIZE+i];
2214 if(!base64_is_valid(newpwd)){
2215 infostream<<"Server: "<<player->getName()<<" supplied invalid password hash"<<std::endl;
2216 // Wrong old password supplied!!
2217 SendChatMessage(peer_id, L"Invalid new password hash supplied. Password NOT changed.");
2221 infostream<<"Server: Client requests a password change from "
2222 <<"'"<<oldpwd<<"' to '"<<newpwd<<"'"<<std::endl;
2224 std::string playername = player->getName();
2226 std::string checkpwd;
2227 m_script->getAuth(playername, &checkpwd, NULL);
2229 if(oldpwd != checkpwd)
2231 infostream<<"Server: invalid old password"<<std::endl;
2232 // Wrong old password supplied!!
2233 SendChatMessage(peer_id, L"Invalid old password supplied. Password NOT changed.");
2237 bool success = m_script->setPassword(playername, newpwd);
2239 actionstream<<player->getName()<<" changes password"<<std::endl;
2240 SendChatMessage(peer_id, L"Password change successful.");
2242 actionstream<<player->getName()<<" tries to change password but "
2243 <<"it fails"<<std::endl;
2244 SendChatMessage(peer_id, L"Password change failed or inavailable.");
2247 else if(command == TOSERVER_PLAYERITEM)
2252 u16 item = readU16(&data[2]);
2253 playersao->setWieldIndex(item);
2255 else if(command == TOSERVER_RESPAWN)
2257 if(player->hp != 0 || !g_settings->getBool("enable_damage"))
2260 RespawnPlayer(peer_id);
2262 actionstream<<player->getName()<<" respawns at "
2263 <<PP(player->getPosition()/BS)<<std::endl;
2265 // ActiveObject is added to environment in AsyncRunStep after
2266 // the previous addition has been succesfully removed
2268 else if(command == TOSERVER_INTERACT)
2270 std::string datastring((char*)&data[2], datasize-2);
2271 std::istringstream is(datastring, std::ios_base::binary);
2277 [5] u32 length of the next item
2278 [9] serialized PointedThing
2280 0: start digging (from undersurface) or use
2281 1: stop digging (all parameters ignored)
2282 2: digging completed
2283 3: place block or item (to abovesurface)
2286 u8 action = readU8(is);
2287 u16 item_i = readU16(is);
2288 std::istringstream tmp_is(deSerializeLongString(is), std::ios::binary);
2289 PointedThing pointed;
2290 pointed.deSerialize(tmp_is);
2292 verbosestream<<"TOSERVER_INTERACT: action="<<(int)action<<", item="
2293 <<item_i<<", pointed="<<pointed.dump()<<std::endl;
2297 verbosestream<<"TOSERVER_INTERACT: "<<player->getName()
2298 <<" tried to interact, but is dead!"<<std::endl;
2302 v3f player_pos = playersao->getLastGoodPosition();
2304 // Update wielded item
2305 playersao->setWieldIndex(item_i);
2307 // Get pointed to node (undefined if not POINTEDTYPE_NODE)
2308 v3s16 p_under = pointed.node_undersurface;
2309 v3s16 p_above = pointed.node_abovesurface;
2311 // Get pointed to object (NULL if not POINTEDTYPE_OBJECT)
2312 ServerActiveObject *pointed_object = NULL;
2313 if(pointed.type == POINTEDTHING_OBJECT)
2315 pointed_object = m_env->getActiveObject(pointed.object_id);
2316 if(pointed_object == NULL)
2318 verbosestream<<"TOSERVER_INTERACT: "
2319 "pointed object is NULL"<<std::endl;
2325 v3f pointed_pos_under = player_pos;
2326 v3f pointed_pos_above = player_pos;
2327 if(pointed.type == POINTEDTHING_NODE)
2329 pointed_pos_under = intToFloat(p_under, BS);
2330 pointed_pos_above = intToFloat(p_above, BS);
2332 else if(pointed.type == POINTEDTHING_OBJECT)
2334 pointed_pos_under = pointed_object->getBasePosition();
2335 pointed_pos_above = pointed_pos_under;
2339 Check that target is reasonably close
2340 (only when digging or placing things)
2342 if(action == 0 || action == 2 || action == 3)
2344 float d = player_pos.getDistanceFrom(pointed_pos_under);
2345 float max_d = BS * 14; // Just some large enough value
2347 actionstream<<"Player "<<player->getName()
2348 <<" tried to access "<<pointed.dump()
2350 <<"d="<<d<<", max_d="<<max_d
2351 <<". ignoring."<<std::endl;
2352 // Re-send block to revert change on client-side
2353 RemoteClient *client = getClient(peer_id);
2354 v3s16 blockpos = getNodeBlockPos(floatToInt(pointed_pos_under, BS));
2355 client->SetBlockNotSent(blockpos);
2357 m_script->on_cheat(playersao, "interacted_too_far");
2364 Make sure the player is allowed to do it
2366 if(!checkPriv(player->getName(), "interact"))
2368 actionstream<<player->getName()<<" attempted to interact with "
2369 <<pointed.dump()<<" without 'interact' privilege"
2371 // Re-send block to revert change on client-side
2372 RemoteClient *client = getClient(peer_id);
2373 // Digging completed -> under
2375 v3s16 blockpos = getNodeBlockPos(floatToInt(pointed_pos_under, BS));
2376 client->SetBlockNotSent(blockpos);
2378 // Placement -> above
2380 v3s16 blockpos = getNodeBlockPos(floatToInt(pointed_pos_above, BS));
2381 client->SetBlockNotSent(blockpos);
2387 If something goes wrong, this player is to blame
2389 RollbackScopeActor rollback_scope(m_rollback,
2390 std::string("player:")+player->getName());
2393 0: start digging or punch object
2397 if(pointed.type == POINTEDTHING_NODE)
2400 NOTE: This can be used in the future to check if
2401 somebody is cheating, by checking the timing.
2403 MapNode n(CONTENT_IGNORE);
2406 n = m_env->getMap().getNode(p_under);
2408 catch(InvalidPositionException &e)
2410 infostream<<"Server: Not punching: Node not found."
2411 <<" Adding block to emerge queue."
2413 m_emerge->enqueueBlockEmerge(peer_id, getNodeBlockPos(p_above), false);
2415 if(n.getContent() != CONTENT_IGNORE)
2416 m_script->node_on_punch(p_under, n, playersao, pointed);
2418 playersao->noCheatDigStart(p_under);
2420 else if(pointed.type == POINTEDTHING_OBJECT)
2422 // Skip if object has been removed
2423 if(pointed_object->m_removed)
2426 actionstream<<player->getName()<<" punches object "
2427 <<pointed.object_id<<": "
2428 <<pointed_object->getDescription()<<std::endl;
2430 ItemStack punchitem = playersao->getWieldedItem();
2431 ToolCapabilities toolcap =
2432 punchitem.getToolCapabilities(m_itemdef);
2433 v3f dir = (pointed_object->getBasePosition() -
2434 (player->getPosition() + player->getEyeOffset())
2436 float time_from_last_punch =
2437 playersao->resetTimeFromLastPunch();
2438 pointed_object->punch(dir, &toolcap, playersao,
2439 time_from_last_punch);
2447 else if(action == 1)
2452 2: Digging completed
2454 else if(action == 2)
2456 // Only digging of nodes
2457 if(pointed.type == POINTEDTHING_NODE)
2459 MapNode n(CONTENT_IGNORE);
2462 n = m_env->getMap().getNode(p_under);
2464 catch(InvalidPositionException &e)
2466 infostream<<"Server: Not finishing digging: Node not found."
2467 <<" Adding block to emerge queue."
2469 m_emerge->enqueueBlockEmerge(peer_id, getNodeBlockPos(p_above), false);
2472 /* Cheat prevention */
2473 bool is_valid_dig = true;
2474 if(!isSingleplayer() && !g_settings->getBool("disable_anticheat"))
2476 v3s16 nocheat_p = playersao->getNoCheatDigPos();
2477 float nocheat_t = playersao->getNoCheatDigTime();
2478 playersao->noCheatDigEnd();
2479 // If player didn't start digging this, ignore dig
2480 if(nocheat_p != p_under){
2481 infostream<<"Server: NoCheat: "<<player->getName()
2482 <<" started digging "
2483 <<PP(nocheat_p)<<" and completed digging "
2484 <<PP(p_under)<<"; not digging."<<std::endl;
2485 is_valid_dig = false;
2487 m_script->on_cheat(playersao, "finished_unknown_dig");
2489 // Get player's wielded item
2490 ItemStack playeritem;
2491 InventoryList *mlist = playersao->getInventory()->getList("main");
2493 playeritem = mlist->getItem(playersao->getWieldIndex());
2494 ToolCapabilities playeritem_toolcap =
2495 playeritem.getToolCapabilities(m_itemdef);
2496 // Get diggability and expected digging time
2497 DigParams params = getDigParams(m_nodedef->get(n).groups,
2498 &playeritem_toolcap);
2499 // If can't dig, try hand
2500 if(!params.diggable){
2501 const ItemDefinition &hand = m_itemdef->get("");
2502 const ToolCapabilities *tp = hand.tool_capabilities;
2504 params = getDigParams(m_nodedef->get(n).groups, tp);
2506 // If can't dig, ignore dig
2507 if(!params.diggable){
2508 infostream<<"Server: NoCheat: "<<player->getName()
2509 <<" completed digging "<<PP(p_under)
2510 <<", which is not diggable with tool. not digging."
2512 is_valid_dig = false;
2514 m_script->on_cheat(playersao, "dug_unbreakable");
2516 // Check digging time
2517 // If already invalidated, we don't have to
2519 // Well not our problem then
2521 // Clean and long dig
2522 else if(params.time > 2.0 && nocheat_t * 1.2 > params.time){
2523 // All is good, but grab time from pool; don't care if
2524 // it's actually available
2525 playersao->getDigPool().grab(params.time);
2527 // Short or laggy dig
2528 // Try getting the time from pool
2529 else if(playersao->getDigPool().grab(params.time)){
2534 infostream<<"Server: NoCheat: "<<player->getName()
2535 <<" completed digging "<<PP(p_under)
2536 <<"too fast; not digging."<<std::endl;
2537 is_valid_dig = false;
2539 m_script->on_cheat(playersao, "dug_too_fast");
2543 /* Actually dig node */
2545 if(is_valid_dig && n.getContent() != CONTENT_IGNORE)
2546 m_script->node_on_dig(p_under, n, playersao);
2548 // Send unusual result (that is, node not being removed)
2549 if(m_env->getMap().getNodeNoEx(p_under).getContent() != CONTENT_AIR)
2551 // Re-send block to revert change on client-side
2552 RemoteClient *client = getClient(peer_id);
2553 v3s16 blockpos = getNodeBlockPos(floatToInt(pointed_pos_under, BS));
2554 client->SetBlockNotSent(blockpos);
2560 3: place block or right-click object
2562 else if(action == 3)
2564 ItemStack item = playersao->getWieldedItem();
2566 // Reset build time counter
2567 if(pointed.type == POINTEDTHING_NODE &&
2568 item.getDefinition(m_itemdef).type == ITEM_NODE)
2569 getClient(peer_id)->m_time_from_building = 0.0;
2571 if(pointed.type == POINTEDTHING_OBJECT)
2573 // Right click object
2575 // Skip if object has been removed
2576 if(pointed_object->m_removed)
2579 actionstream<<player->getName()<<" right-clicks object "
2580 <<pointed.object_id<<": "
2581 <<pointed_object->getDescription()<<std::endl;
2584 pointed_object->rightClick(playersao);
2586 else if(m_script->item_OnPlace(
2587 item, playersao, pointed))
2589 // Placement was handled in lua
2591 // Apply returned ItemStack
2592 playersao->setWieldedItem(item);
2595 // If item has node placement prediction, always send the
2596 // blocks to make sure the client knows what exactly happened
2597 if(item.getDefinition(m_itemdef).node_placement_prediction != ""){
2598 RemoteClient *client = getClient(peer_id);
2599 v3s16 blockpos = getNodeBlockPos(floatToInt(pointed_pos_above, BS));
2600 client->SetBlockNotSent(blockpos);
2601 v3s16 blockpos2 = getNodeBlockPos(floatToInt(pointed_pos_under, BS));
2602 if(blockpos2 != blockpos){
2603 client->SetBlockNotSent(blockpos2);
2611 else if(action == 4)
2613 ItemStack item = playersao->getWieldedItem();
2615 actionstream<<player->getName()<<" uses "<<item.name
2616 <<", pointing at "<<pointed.dump()<<std::endl;
2618 if(m_script->item_OnUse(
2619 item, playersao, pointed))
2621 // Apply returned ItemStack
2622 playersao->setWieldedItem(item);
2629 Catch invalid actions
2633 infostream<<"WARNING: Server: Invalid action "
2634 <<action<<std::endl;
2637 else if(command == TOSERVER_REMOVED_SOUNDS)
2639 std::string datastring((char*)&data[2], datasize-2);
2640 std::istringstream is(datastring, std::ios_base::binary);
2642 int num = readU16(is);
2643 for(int k=0; k<num; k++){
2644 s32 id = readS32(is);
2645 std::map<s32, ServerPlayingSound>::iterator i =
2646 m_playing_sounds.find(id);
2647 if(i == m_playing_sounds.end())
2649 ServerPlayingSound &psound = i->second;
2650 psound.clients.erase(peer_id);
2651 if(psound.clients.size() == 0)
2652 m_playing_sounds.erase(i++);
2655 else if(command == TOSERVER_NODEMETA_FIELDS)
2657 std::string datastring((char*)&data[2], datasize-2);
2658 std::istringstream is(datastring, std::ios_base::binary);
2660 v3s16 p = readV3S16(is);
2661 std::string formname = deSerializeString(is);
2662 int num = readU16(is);
2663 std::map<std::string, std::string> fields;
2664 for(int k=0; k<num; k++){
2665 std::string fieldname = deSerializeString(is);
2666 std::string fieldvalue = deSerializeLongString(is);
2667 fields[fieldname] = fieldvalue;
2670 // If something goes wrong, this player is to blame
2671 RollbackScopeActor rollback_scope(m_rollback,
2672 std::string("player:")+player->getName());
2674 // Check the target node for rollback data; leave others unnoticed
2675 RollbackNode rn_old(&m_env->getMap(), p, this);
2677 m_script->node_on_receive_fields(p, formname, fields,playersao);
2679 // Report rollback data
2680 RollbackNode rn_new(&m_env->getMap(), p, this);
2681 if(rollback() && rn_new != rn_old){
2682 RollbackAction action;
2683 action.setSetNode(p, rn_old, rn_new);
2684 rollback()->reportAction(action);
2687 else if(command == TOSERVER_INVENTORY_FIELDS)
2689 std::string datastring((char*)&data[2], datasize-2);
2690 std::istringstream is(datastring, std::ios_base::binary);
2692 std::string formname = deSerializeString(is);
2693 int num = readU16(is);
2694 std::map<std::string, std::string> fields;
2695 for(int k=0; k<num; k++){
2696 std::string fieldname = deSerializeString(is);
2697 std::string fieldvalue = deSerializeLongString(is);
2698 fields[fieldname] = fieldvalue;
2701 m_script->on_playerReceiveFields(playersao, formname, fields);
2705 infostream<<"Server::ProcessData(): Ignoring "
2706 "unknown command "<<command<<std::endl;
2710 catch(SendFailedException &e)
2712 errorstream<<"Server::ProcessData(): SendFailedException: "
2718 void Server::setTimeOfDay(u32 time)
2720 m_env->setTimeOfDay(time);
2721 m_time_of_day_send_timer = 0;
2724 void Server::onMapEditEvent(MapEditEvent *event)
2726 //infostream<<"Server::onMapEditEvent()"<<std::endl;
2727 if(m_ignore_map_edit_events)
2729 if(m_ignore_map_edit_events_area.contains(event->getArea()))
2731 MapEditEvent *e = event->clone();
2732 m_unsent_map_edit_queue.push_back(e);
2735 Inventory* Server::getInventory(const InventoryLocation &loc)
2738 case InventoryLocation::UNDEFINED:
2741 case InventoryLocation::CURRENT_PLAYER:
2744 case InventoryLocation::PLAYER:
2746 Player *player = m_env->getPlayer(loc.name.c_str());
2749 PlayerSAO *playersao = player->getPlayerSAO();
2752 return playersao->getInventory();
2755 case InventoryLocation::NODEMETA:
2757 NodeMetadata *meta = m_env->getMap().getNodeMetadata(loc.p);
2760 return meta->getInventory();
2763 case InventoryLocation::DETACHED:
2765 if(m_detached_inventories.count(loc.name) == 0)
2767 return m_detached_inventories[loc.name];
2775 void Server::setInventoryModified(const InventoryLocation &loc)
2778 case InventoryLocation::UNDEFINED:
2781 case InventoryLocation::PLAYER:
2783 Player *player = m_env->getPlayer(loc.name.c_str());
2786 PlayerSAO *playersao = player->getPlayerSAO();
2789 playersao->m_inventory_not_sent = true;
2790 playersao->m_wielded_item_not_sent = true;
2793 case InventoryLocation::NODEMETA:
2795 v3s16 blockpos = getNodeBlockPos(loc.p);
2797 MapBlock *block = m_env->getMap().getBlockNoCreateNoEx(blockpos);
2799 block->raiseModified(MOD_STATE_WRITE_NEEDED);
2801 setBlockNotSent(blockpos);
2804 case InventoryLocation::DETACHED:
2806 sendDetachedInventory(loc.name,PEER_ID_INEXISTENT);
2814 void Server::SetBlocksNotSent(std::map<v3s16, MapBlock *>& block)
2816 std::list<u16> clients = m_clients.getClientIDs();
2818 // Set the modified blocks unsent for all the clients
2819 for (std::list<u16>::iterator
2820 i = clients.begin();
2821 i != clients.end(); ++i) {
2822 RemoteClient *client = m_clients.lockedGetClientNoEx(*i);
2824 client->SetBlocksNotSent(block);
2829 void Server::peerAdded(con::Peer *peer)
2831 DSTACK(__FUNCTION_NAME);
2832 verbosestream<<"Server::peerAdded(): peer->id="
2833 <<peer->id<<std::endl;
2836 c.type = con::PEER_ADDED;
2837 c.peer_id = peer->id;
2839 m_peer_change_queue.push_back(c);
2842 void Server::deletingPeer(con::Peer *peer, bool timeout)
2844 DSTACK(__FUNCTION_NAME);
2845 verbosestream<<"Server::deletingPeer(): peer->id="
2846 <<peer->id<<", timeout="<<timeout<<std::endl;
2848 m_clients.event(peer->id, CSE_Disconnect);
2850 c.type = con::PEER_REMOVED;
2851 c.peer_id = peer->id;
2852 c.timeout = timeout;
2853 m_peer_change_queue.push_back(c);
2856 bool Server::getClientConInfo(u16 peer_id, con::rtt_stat_type type, float* retval)
2858 *retval = m_con.getPeerStat(peer_id,type);
2859 if (*retval == -1) return false;
2863 bool Server::getClientInfo(
2872 std::string* vers_string
2875 *state = m_clients.getClientState(peer_id);
2877 RemoteClient* client = m_clients.lockedGetClientNoEx(peer_id, CS_Invalid);
2879 if (client == NULL) {
2884 *uptime = client->uptime();
2885 *ser_vers = client->serialization_version;
2886 *prot_vers = client->net_proto_version;
2888 *major = client->getMajor();
2889 *minor = client->getMinor();
2890 *patch = client->getPatch();
2891 *vers_string = client->getPatch();
2898 void Server::handlePeerChanges()
2900 while(m_peer_change_queue.size() > 0)
2902 con::PeerChange c = m_peer_change_queue.pop_front();
2904 verbosestream<<"Server: Handling peer change: "
2905 <<"id="<<c.peer_id<<", timeout="<<c.timeout
2910 case con::PEER_ADDED:
2911 m_clients.CreateClient(c.peer_id);
2914 case con::PEER_REMOVED:
2915 DeleteClient(c.peer_id, c.timeout?CDR_TIMEOUT:CDR_LEAVE);
2919 assert("Invalid peer change event received!" == 0);
2925 void Server::SendMovement(u16 peer_id)
2927 DSTACK(__FUNCTION_NAME);
2928 std::ostringstream os(std::ios_base::binary);
2930 writeU16(os, TOCLIENT_MOVEMENT);
2931 writeF1000(os, g_settings->getFloat("movement_acceleration_default"));
2932 writeF1000(os, g_settings->getFloat("movement_acceleration_air"));
2933 writeF1000(os, g_settings->getFloat("movement_acceleration_fast"));
2934 writeF1000(os, g_settings->getFloat("movement_speed_walk"));
2935 writeF1000(os, g_settings->getFloat("movement_speed_crouch"));
2936 writeF1000(os, g_settings->getFloat("movement_speed_fast"));
2937 writeF1000(os, g_settings->getFloat("movement_speed_climb"));
2938 writeF1000(os, g_settings->getFloat("movement_speed_jump"));
2939 writeF1000(os, g_settings->getFloat("movement_liquid_fluidity"));
2940 writeF1000(os, g_settings->getFloat("movement_liquid_fluidity_smooth"));
2941 writeF1000(os, g_settings->getFloat("movement_liquid_sink"));
2942 writeF1000(os, g_settings->getFloat("movement_gravity"));
2945 std::string s = os.str();
2946 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
2948 m_clients.send(peer_id, 0, data, true);
2951 void Server::SendHP(u16 peer_id, u8 hp)
2953 DSTACK(__FUNCTION_NAME);
2954 std::ostringstream os(std::ios_base::binary);
2956 writeU16(os, TOCLIENT_HP);
2960 std::string s = os.str();
2961 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
2963 m_clients.send(peer_id, 0, data, true);
2966 void Server::SendBreath(u16 peer_id, u16 breath)
2968 DSTACK(__FUNCTION_NAME);
2969 std::ostringstream os(std::ios_base::binary);
2971 writeU16(os, TOCLIENT_BREATH);
2972 writeU16(os, breath);
2975 std::string s = os.str();
2976 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
2978 m_clients.send(peer_id, 0, data, true);
2981 void Server::SendAccessDenied(u16 peer_id,const std::wstring &reason)
2983 DSTACK(__FUNCTION_NAME);
2984 std::ostringstream os(std::ios_base::binary);
2986 writeU16(os, TOCLIENT_ACCESS_DENIED);
2987 os<<serializeWideString(reason);
2990 std::string s = os.str();
2991 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
2993 m_clients.send(peer_id, 0, data, true);
2996 void Server::SendDeathscreen(u16 peer_id,bool set_camera_point_target,
2997 v3f camera_point_target)
2999 DSTACK(__FUNCTION_NAME);
3000 std::ostringstream os(std::ios_base::binary);
3002 writeU16(os, TOCLIENT_DEATHSCREEN);
3003 writeU8(os, set_camera_point_target);
3004 writeV3F1000(os, camera_point_target);
3007 std::string s = os.str();
3008 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3010 m_clients.send(peer_id, 0, data, true);
3013 void Server::SendItemDef(u16 peer_id,
3014 IItemDefManager *itemdef, u16 protocol_version)
3016 DSTACK(__FUNCTION_NAME);
3017 std::ostringstream os(std::ios_base::binary);
3021 u32 length of the next item
3022 zlib-compressed serialized ItemDefManager
3024 writeU16(os, TOCLIENT_ITEMDEF);
3025 std::ostringstream tmp_os(std::ios::binary);
3026 itemdef->serialize(tmp_os, protocol_version);
3027 std::ostringstream tmp_os2(std::ios::binary);
3028 compressZlib(tmp_os.str(), tmp_os2);
3029 os<<serializeLongString(tmp_os2.str());
3032 std::string s = os.str();
3033 verbosestream<<"Server: Sending item definitions to id("<<peer_id
3034 <<"): size="<<s.size()<<std::endl;
3035 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3037 m_clients.send(peer_id, 0, data, true);
3040 void Server::SendNodeDef(u16 peer_id,
3041 INodeDefManager *nodedef, u16 protocol_version)
3043 DSTACK(__FUNCTION_NAME);
3044 std::ostringstream os(std::ios_base::binary);
3048 u32 length of the next item
3049 zlib-compressed serialized NodeDefManager
3051 writeU16(os, TOCLIENT_NODEDEF);
3052 std::ostringstream tmp_os(std::ios::binary);
3053 nodedef->serialize(tmp_os, protocol_version);
3054 std::ostringstream tmp_os2(std::ios::binary);
3055 compressZlib(tmp_os.str(), tmp_os2);
3056 os<<serializeLongString(tmp_os2.str());
3059 std::string s = os.str();
3060 verbosestream<<"Server: Sending node definitions to id("<<peer_id
3061 <<"): size="<<s.size()<<std::endl;
3062 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3064 m_clients.send(peer_id, 0, data, true);
3068 Non-static send methods
3071 void Server::SendInventory(u16 peer_id)
3073 DSTACK(__FUNCTION_NAME);
3075 PlayerSAO *playersao = getPlayerSAO(peer_id);
3078 playersao->m_inventory_not_sent = false;
3084 std::ostringstream os;
3085 playersao->getInventory()->serialize(os);
3087 std::string s = os.str();
3089 SharedBuffer<u8> data(s.size()+2);
3090 writeU16(&data[0], TOCLIENT_INVENTORY);
3091 memcpy(&data[2], s.c_str(), s.size());
3094 m_clients.send(peer_id, 0, data, true);
3097 void Server::SendChatMessage(u16 peer_id, const std::wstring &message)
3099 DSTACK(__FUNCTION_NAME);
3101 std::ostringstream os(std::ios_base::binary);
3105 writeU16(buf, TOCLIENT_CHAT_MESSAGE);
3106 os.write((char*)buf, 2);
3109 writeU16(buf, message.size());
3110 os.write((char*)buf, 2);
3113 for(u32 i=0; i<message.size(); i++)
3117 os.write((char*)buf, 2);
3121 std::string s = os.str();
3122 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3124 if (peer_id != PEER_ID_INEXISTENT)
3127 m_clients.send(peer_id, 0, data, true);
3131 m_clients.sendToAll(0,data,true);
3135 void Server::SendShowFormspecMessage(u16 peer_id, const std::string &formspec,
3136 const std::string &formname)
3138 DSTACK(__FUNCTION_NAME);
3140 std::ostringstream os(std::ios_base::binary);
3145 writeU16(buf, TOCLIENT_SHOW_FORMSPEC);
3146 os.write((char*)buf, 2);
3147 os<<serializeLongString(FORMSPEC_VERSION_STRING + formspec);
3148 os<<serializeString(formname);
3151 std::string s = os.str();
3152 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3154 m_clients.send(peer_id, 0, data, true);
3157 // Spawns a particle on peer with peer_id
3158 void Server::SendSpawnParticle(u16 peer_id, v3f pos, v3f velocity, v3f acceleration,
3159 float expirationtime, float size, bool collisiondetection,
3160 bool vertical, std::string texture)
3162 DSTACK(__FUNCTION_NAME);
3164 std::ostringstream os(std::ios_base::binary);
3165 writeU16(os, TOCLIENT_SPAWN_PARTICLE);
3166 writeV3F1000(os, pos);
3167 writeV3F1000(os, velocity);
3168 writeV3F1000(os, acceleration);
3169 writeF1000(os, expirationtime);
3170 writeF1000(os, size);
3171 writeU8(os, collisiondetection);
3172 os<<serializeLongString(texture);
3173 writeU8(os, vertical);
3176 std::string s = os.str();
3177 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3179 if (peer_id != PEER_ID_INEXISTENT)
3182 m_clients.send(peer_id, 0, data, true);
3186 m_clients.sendToAll(0,data,true);
3190 // Adds a ParticleSpawner on peer with peer_id
3191 void Server::SendAddParticleSpawner(u16 peer_id, u16 amount, float spawntime, v3f minpos, v3f maxpos,
3192 v3f minvel, v3f maxvel, v3f minacc, v3f maxacc, float minexptime, float maxexptime,
3193 float minsize, float maxsize, bool collisiondetection, bool vertical, std::string texture, u32 id)
3195 DSTACK(__FUNCTION_NAME);
3197 std::ostringstream os(std::ios_base::binary);
3198 writeU16(os, TOCLIENT_ADD_PARTICLESPAWNER);
3200 writeU16(os, amount);
3201 writeF1000(os, spawntime);
3202 writeV3F1000(os, minpos);
3203 writeV3F1000(os, maxpos);
3204 writeV3F1000(os, minvel);
3205 writeV3F1000(os, maxvel);
3206 writeV3F1000(os, minacc);
3207 writeV3F1000(os, maxacc);
3208 writeF1000(os, minexptime);
3209 writeF1000(os, maxexptime);
3210 writeF1000(os, minsize);
3211 writeF1000(os, maxsize);
3212 writeU8(os, collisiondetection);
3213 os<<serializeLongString(texture);
3215 writeU8(os, vertical);
3218 std::string s = os.str();
3219 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3221 if (peer_id != PEER_ID_INEXISTENT)
3224 m_clients.send(peer_id, 0, data, true);
3227 m_clients.sendToAll(0,data,true);
3231 void Server::SendDeleteParticleSpawner(u16 peer_id, u32 id)
3233 DSTACK(__FUNCTION_NAME);
3235 std::ostringstream os(std::ios_base::binary);
3236 writeU16(os, TOCLIENT_DELETE_PARTICLESPAWNER);
3241 std::string s = os.str();
3242 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3244 if (peer_id != PEER_ID_INEXISTENT) {
3246 m_clients.send(peer_id, 0, data, true);
3249 m_clients.sendToAll(0,data,true);
3254 void Server::SendHUDAdd(u16 peer_id, u32 id, HudElement *form)
3256 std::ostringstream os(std::ios_base::binary);
3259 writeU16(os, TOCLIENT_HUDADD);
3261 writeU8(os, (u8)form->type);
3262 writeV2F1000(os, form->pos);
3263 os << serializeString(form->name);
3264 writeV2F1000(os, form->scale);
3265 os << serializeString(form->text);
3266 writeU32(os, form->number);
3267 writeU32(os, form->item);
3268 writeU32(os, form->dir);
3269 writeV2F1000(os, form->align);
3270 writeV2F1000(os, form->offset);
3271 writeV3F1000(os, form->world_pos);
3272 writeV2S32(os,form->size);
3275 std::string s = os.str();
3276 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3278 m_clients.send(peer_id, 1, data, true);
3281 void Server::SendHUDRemove(u16 peer_id, u32 id)
3283 std::ostringstream os(std::ios_base::binary);
3286 writeU16(os, TOCLIENT_HUDRM);
3290 std::string s = os.str();
3291 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3294 m_clients.send(peer_id, 1, data, true);
3297 void Server::SendHUDChange(u16 peer_id, u32 id, HudElementStat stat, void *value)
3299 std::ostringstream os(std::ios_base::binary);
3302 writeU16(os, TOCLIENT_HUDCHANGE);
3304 writeU8(os, (u8)stat);
3307 case HUD_STAT_SCALE:
3308 case HUD_STAT_ALIGN:
3309 case HUD_STAT_OFFSET:
3310 writeV2F1000(os, *(v2f *)value);
3314 os << serializeString(*(std::string *)value);
3316 case HUD_STAT_WORLD_POS:
3317 writeV3F1000(os, *(v3f *)value);
3320 writeV2S32(os,*(v2s32 *)value);
3322 case HUD_STAT_NUMBER:
3326 writeU32(os, *(u32 *)value);
3331 std::string s = os.str();
3332 SharedBuffer<u8> data((u8 *)s.c_str(), s.size());
3334 m_clients.send(peer_id, 0, data, true);
3337 void Server::SendHUDSetFlags(u16 peer_id, u32 flags, u32 mask)
3339 std::ostringstream os(std::ios_base::binary);
3342 writeU16(os, TOCLIENT_HUD_SET_FLAGS);
3344 //////////////////////////// compatibility code to be removed //////////////
3345 flags &= ~(HUD_FLAG_HEALTHBAR_VISIBLE | HUD_FLAG_BREATHBAR_VISIBLE);
3346 ////////////////////////////////////////////////////////////////////////////
3347 writeU32(os, flags);
3351 std::string s = os.str();
3352 SharedBuffer<u8> data((u8 *)s.c_str(), s.size());
3354 m_clients.send(peer_id, 0, data, true);
3357 void Server::SendHUDSetParam(u16 peer_id, u16 param, const std::string &value)
3359 std::ostringstream os(std::ios_base::binary);
3362 writeU16(os, TOCLIENT_HUD_SET_PARAM);
3363 writeU16(os, param);
3364 os<<serializeString(value);
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::SendSetSky(u16 peer_id, const video::SColor &bgcolor,
3374 const std::string &type, const std::vector<std::string> ¶ms)
3376 std::ostringstream os(std::ios_base::binary);
3379 writeU16(os, TOCLIENT_SET_SKY);
3380 writeARGB8(os, bgcolor);
3381 os<<serializeString(type);
3382 writeU16(os, params.size());
3383 for(size_t i=0; i<params.size(); i++)
3384 os<<serializeString(params[i]);
3387 std::string s = os.str();
3388 SharedBuffer<u8> data((u8 *)s.c_str(), s.size());
3390 m_clients.send(peer_id, 0, data, true);
3393 void Server::SendOverrideDayNightRatio(u16 peer_id, bool do_override,
3396 std::ostringstream os(std::ios_base::binary);
3399 writeU16(os, TOCLIENT_OVERRIDE_DAY_NIGHT_RATIO);
3400 writeU8(os, do_override);
3401 writeU16(os, ratio*65535);
3404 std::string s = os.str();
3405 SharedBuffer<u8> data((u8 *)s.c_str(), s.size());
3407 m_clients.send(peer_id, 0, data, true);
3410 void Server::SendTimeOfDay(u16 peer_id, u16 time, f32 time_speed)
3412 DSTACK(__FUNCTION_NAME);
3415 SharedBuffer<u8> data(2+2+4);
3416 writeU16(&data[0], TOCLIENT_TIME_OF_DAY);
3417 writeU16(&data[2], time);
3418 writeF1000(&data[4], time_speed);
3420 if (peer_id == PEER_ID_INEXISTENT) {
3421 m_clients.sendToAll(0,data,true);
3425 m_clients.send(peer_id, 0, data, true);
3429 void Server::SendPlayerHP(u16 peer_id)
3431 DSTACK(__FUNCTION_NAME);
3432 PlayerSAO *playersao = getPlayerSAO(peer_id);
3434 playersao->m_hp_not_sent = false;
3435 SendHP(peer_id, playersao->getHP());
3436 m_script->player_event(playersao,"health_changed");
3438 // Send to other clients
3439 std::string str = gob_cmd_punched(playersao->readDamage(), playersao->getHP());
3440 ActiveObjectMessage aom(playersao->getId(), true, str);
3441 playersao->m_messages_out.push_back(aom);
3444 void Server::SendPlayerBreath(u16 peer_id)
3446 DSTACK(__FUNCTION_NAME);
3447 PlayerSAO *playersao = getPlayerSAO(peer_id);
3449 playersao->m_breath_not_sent = false;
3450 m_script->player_event(playersao,"breath_changed");
3451 SendBreath(peer_id, playersao->getBreath());
3454 void Server::SendMovePlayer(u16 peer_id)
3456 DSTACK(__FUNCTION_NAME);
3457 Player *player = m_env->getPlayer(peer_id);
3460 std::ostringstream os(std::ios_base::binary);
3461 writeU16(os, TOCLIENT_MOVE_PLAYER);
3462 writeV3F1000(os, player->getPosition());
3463 writeF1000(os, player->getPitch());
3464 writeF1000(os, player->getYaw());
3467 v3f pos = player->getPosition();
3468 f32 pitch = player->getPitch();
3469 f32 yaw = player->getYaw();
3470 verbosestream<<"Server: Sending TOCLIENT_MOVE_PLAYER"
3471 <<" pos=("<<pos.X<<","<<pos.Y<<","<<pos.Z<<")"
3478 std::string s = os.str();
3479 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3481 m_clients.send(peer_id, 0, data, true);
3484 void Server::SendLocalPlayerAnimations(u16 peer_id, v2s32 animation_frames[4], f32 animation_speed)
3486 std::ostringstream os(std::ios_base::binary);
3488 writeU16(os, TOCLIENT_LOCAL_PLAYER_ANIMATIONS);
3489 writeV2S32(os, animation_frames[0]);
3490 writeV2S32(os, animation_frames[1]);
3491 writeV2S32(os, animation_frames[2]);
3492 writeV2S32(os, animation_frames[3]);
3493 writeF1000(os, animation_speed);
3496 std::string s = os.str();
3497 SharedBuffer<u8> data((u8 *)s.c_str(), s.size());
3499 m_clients.send(peer_id, 0, data, true);
3502 void Server::SendEyeOffset(u16 peer_id, v3f first, v3f third)
3504 std::ostringstream os(std::ios_base::binary);
3506 writeU16(os, TOCLIENT_EYE_OFFSET);
3507 writeV3F1000(os, first);
3508 writeV3F1000(os, third);
3511 std::string s = os.str();
3512 SharedBuffer<u8> data((u8 *)s.c_str(), s.size());
3514 m_clients.send(peer_id, 0, data, true);
3516 void Server::SendPlayerPrivileges(u16 peer_id)
3518 Player *player = m_env->getPlayer(peer_id);
3520 if(player->peer_id == PEER_ID_INEXISTENT)
3523 std::set<std::string> privs;
3524 m_script->getAuth(player->getName(), NULL, &privs);
3526 std::ostringstream os(std::ios_base::binary);
3527 writeU16(os, TOCLIENT_PRIVILEGES);
3528 writeU16(os, privs.size());
3529 for(std::set<std::string>::const_iterator i = privs.begin();
3530 i != privs.end(); i++){
3531 os<<serializeString(*i);
3535 std::string s = os.str();
3536 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3538 m_clients.send(peer_id, 0, data, true);
3541 void Server::SendPlayerInventoryFormspec(u16 peer_id)
3543 Player *player = m_env->getPlayer(peer_id);
3545 if(player->peer_id == PEER_ID_INEXISTENT)
3548 std::ostringstream os(std::ios_base::binary);
3549 writeU16(os, TOCLIENT_INVENTORY_FORMSPEC);
3550 os<<serializeLongString(FORMSPEC_VERSION_STRING + player->inventory_formspec);
3553 std::string s = os.str();
3554 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3556 m_clients.send(peer_id, 0, data, true);
3559 s32 Server::playSound(const SimpleSoundSpec &spec,
3560 const ServerSoundParams ¶ms)
3562 // Find out initial position of sound
3563 bool pos_exists = false;
3564 v3f pos = params.getPos(m_env, &pos_exists);
3565 // If position is not found while it should be, cancel sound
3566 if(pos_exists != (params.type != ServerSoundParams::SSP_LOCAL))
3569 // Filter destination clients
3570 std::list<u16> dst_clients;
3571 if(params.to_player != "")
3573 Player *player = m_env->getPlayer(params.to_player.c_str());
3575 infostream<<"Server::playSound: Player \""<<params.to_player
3576 <<"\" not found"<<std::endl;
3579 if(player->peer_id == PEER_ID_INEXISTENT){
3580 infostream<<"Server::playSound: Player \""<<params.to_player
3581 <<"\" not connected"<<std::endl;
3584 dst_clients.push_back(player->peer_id);
3588 std::list<u16> clients = m_clients.getClientIDs();
3590 for(std::list<u16>::iterator
3591 i = clients.begin(); i != clients.end(); ++i)
3593 Player *player = m_env->getPlayer(*i);
3597 if(player->getPosition().getDistanceFrom(pos) >
3598 params.max_hear_distance)
3601 dst_clients.push_back(*i);
3604 if(dst_clients.size() == 0)
3608 s32 id = m_next_sound_id++;
3609 // The sound will exist as a reference in m_playing_sounds
3610 m_playing_sounds[id] = ServerPlayingSound();
3611 ServerPlayingSound &psound = m_playing_sounds[id];
3612 psound.params = params;
3613 for(std::list<u16>::iterator i = dst_clients.begin();
3614 i != dst_clients.end(); i++)
3615 psound.clients.insert(*i);
3617 std::ostringstream os(std::ios_base::binary);
3618 writeU16(os, TOCLIENT_PLAY_SOUND);
3620 os<<serializeString(spec.name);
3621 writeF1000(os, spec.gain * params.gain);
3622 writeU8(os, params.type);
3623 writeV3F1000(os, pos);
3624 writeU16(os, params.object);
3625 writeU8(os, params.loop);
3627 std::string s = os.str();
3628 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3630 for(std::list<u16>::iterator i = dst_clients.begin();
3631 i != dst_clients.end(); i++){
3633 m_clients.send(*i, 0, data, true);
3637 void Server::stopSound(s32 handle)
3639 // Get sound reference
3640 std::map<s32, ServerPlayingSound>::iterator i =
3641 m_playing_sounds.find(handle);
3642 if(i == m_playing_sounds.end())
3644 ServerPlayingSound &psound = i->second;
3646 std::ostringstream os(std::ios_base::binary);
3647 writeU16(os, TOCLIENT_STOP_SOUND);
3648 writeS32(os, handle);
3650 std::string s = os.str();
3651 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3653 for(std::set<u16>::iterator i = psound.clients.begin();
3654 i != psound.clients.end(); i++){
3656 m_clients.send(*i, 0, data, true);
3658 // Remove sound reference
3659 m_playing_sounds.erase(i);
3662 void Server::sendRemoveNode(v3s16 p, u16 ignore_id,
3663 std::list<u16> *far_players, float far_d_nodes)
3665 float maxd = far_d_nodes*BS;
3666 v3f p_f = intToFloat(p, BS);
3670 SharedBuffer<u8> reply(replysize);
3671 writeU16(&reply[0], TOCLIENT_REMOVENODE);
3672 writeS16(&reply[2], p.X);
3673 writeS16(&reply[4], p.Y);
3674 writeS16(&reply[6], p.Z);
3676 std::list<u16> clients = m_clients.getClientIDs();
3677 for(std::list<u16>::iterator
3678 i = clients.begin();
3679 i != clients.end(); ++i)
3684 Player *player = m_env->getPlayer(*i);
3687 // If player is far away, only set modified blocks not sent
3688 v3f player_pos = player->getPosition();
3689 if(player_pos.getDistanceFrom(p_f) > maxd)
3691 far_players->push_back(*i);
3698 m_clients.send(*i, 0, reply, true);
3702 void Server::sendAddNode(v3s16 p, MapNode n, u16 ignore_id,
3703 std::list<u16> *far_players, float far_d_nodes,
3704 bool remove_metadata)
3706 float maxd = far_d_nodes*BS;
3707 v3f p_f = intToFloat(p, BS);
3709 std::list<u16> clients = m_clients.getClientIDs();
3710 for(std::list<u16>::iterator
3711 i = clients.begin();
3712 i != clients.end(); ++i)
3718 Player *player = m_env->getPlayer(*i);
3721 // If player is far away, only set modified blocks not sent
3722 v3f player_pos = player->getPosition();
3723 if(player_pos.getDistanceFrom(p_f) > maxd)
3725 far_players->push_back(*i);
3730 SharedBuffer<u8> reply(0);
3732 RemoteClient* client = m_clients.lockedGetClientNoEx(*i);
3736 u32 replysize = 9 + MapNode::serializedLength(client->serialization_version);
3737 reply = SharedBuffer<u8>(replysize);
3738 writeU16(&reply[0], TOCLIENT_ADDNODE);
3739 writeS16(&reply[2], p.X);
3740 writeS16(&reply[4], p.Y);
3741 writeS16(&reply[6], p.Z);
3742 n.serialize(&reply[8], client->serialization_version);
3743 u32 index = 8 + MapNode::serializedLength(client->serialization_version);
3744 writeU8(&reply[index], remove_metadata ? 0 : 1);
3746 if (!remove_metadata) {
3747 if (client->net_proto_version <= 21) {
3748 // Old clients always clear metadata; fix it
3749 // by sending the full block again.
3750 client->SetBlockNotSent(p);
3757 if (reply.getSize() > 0)
3758 m_clients.send(*i, 0, reply, true);
3762 void Server::setBlockNotSent(v3s16 p)
3764 std::list<u16> clients = m_clients.getClientIDs();
3766 for(std::list<u16>::iterator
3767 i = clients.begin();
3768 i != clients.end(); ++i)
3770 RemoteClient *client = m_clients.lockedGetClientNoEx(*i);
3771 client->SetBlockNotSent(p);
3776 void Server::SendBlockNoLock(u16 peer_id, MapBlock *block, u8 ver, u16 net_proto_version)
3778 DSTACK(__FUNCTION_NAME);
3780 v3s16 p = block->getPos();
3784 bool completely_air = true;
3785 for(s16 z0=0; z0<MAP_BLOCKSIZE; z0++)
3786 for(s16 x0=0; x0<MAP_BLOCKSIZE; x0++)
3787 for(s16 y0=0; y0<MAP_BLOCKSIZE; y0++)
3789 if(block->getNodeNoEx(v3s16(x0,y0,z0)).d != CONTENT_AIR)
3791 completely_air = false;
3792 x0 = y0 = z0 = MAP_BLOCKSIZE; // Break out
3797 infostream<<"Server: Sending block ("<<p.X<<","<<p.Y<<","<<p.Z<<"): ";
3799 infostream<<"[completely air] ";
3800 infostream<<std::endl;
3804 Create a packet with the block in the right format
3807 std::ostringstream os(std::ios_base::binary);
3808 block->serialize(os, ver, false);
3809 block->serializeNetworkSpecific(os, net_proto_version);
3810 std::string s = os.str();
3811 SharedBuffer<u8> blockdata((u8*)s.c_str(), s.size());
3813 u32 replysize = 8 + blockdata.getSize();
3814 SharedBuffer<u8> reply(replysize);
3815 writeU16(&reply[0], TOCLIENT_BLOCKDATA);
3816 writeS16(&reply[2], p.X);
3817 writeS16(&reply[4], p.Y);
3818 writeS16(&reply[6], p.Z);
3819 memcpy(&reply[8], *blockdata, blockdata.getSize());
3821 /*infostream<<"Server: Sending block ("<<p.X<<","<<p.Y<<","<<p.Z<<")"
3822 <<": \tpacket size: "<<replysize<<std::endl;*/
3827 m_clients.send(peer_id, 2, reply, true);
3830 void Server::SendBlocks(float dtime)
3832 DSTACK(__FUNCTION_NAME);
3834 JMutexAutoLock envlock(m_env_mutex);
3835 //TODO check if one big lock could be faster then multiple small ones
3837 ScopeProfiler sp(g_profiler, "Server: sel and send blocks to clients");
3839 std::vector<PrioritySortedBlockTransfer> queue;
3841 s32 total_sending = 0;
3844 ScopeProfiler sp(g_profiler, "Server: selecting blocks for sending");
3846 std::list<u16> clients = m_clients.getClientIDs();
3849 for(std::list<u16>::iterator
3850 i = clients.begin();
3851 i != clients.end(); ++i)
3853 RemoteClient *client = m_clients.lockedGetClientNoEx(*i, CS_Active);
3858 total_sending += client->SendingCount();
3859 client->GetNextBlocks(m_env,m_emerge, dtime, queue);
3865 // Lowest priority number comes first.
3866 // Lowest is most important.
3867 std::sort(queue.begin(), queue.end());
3870 for(u32 i=0; i<queue.size(); i++)
3872 //TODO: Calculate limit dynamically
3873 if(total_sending >= g_settings->getS32
3874 ("max_simultaneous_block_sends_server_total"))
3877 PrioritySortedBlockTransfer q = queue[i];
3879 MapBlock *block = NULL;
3882 block = m_env->getMap().getBlockNoCreate(q.pos);
3884 catch(InvalidPositionException &e)
3889 RemoteClient *client = m_clients.lockedGetClientNoEx(q.peer_id, CS_Active);
3894 SendBlockNoLock(q.peer_id, block, client->serialization_version, client->net_proto_version);
3896 client->SentBlock(q.pos);
3902 void Server::fillMediaCache()
3904 DSTACK(__FUNCTION_NAME);
3906 infostream<<"Server: Calculating media file checksums"<<std::endl;
3908 // Collect all media file paths
3909 std::list<std::string> paths;
3910 for(std::vector<ModSpec>::iterator i = m_mods.begin();
3911 i != m_mods.end(); i++){
3912 const ModSpec &mod = *i;
3913 paths.push_back(mod.path + DIR_DELIM + "textures");
3914 paths.push_back(mod.path + DIR_DELIM + "sounds");
3915 paths.push_back(mod.path + DIR_DELIM + "media");
3916 paths.push_back(mod.path + DIR_DELIM + "models");
3918 paths.push_back(porting::path_user + DIR_DELIM + "textures" + DIR_DELIM + "server");
3920 // Collect media file information from paths into cache
3921 for(std::list<std::string>::iterator i = paths.begin();
3922 i != paths.end(); i++)
3924 std::string mediapath = *i;
3925 std::vector<fs::DirListNode> dirlist = fs::GetDirListing(mediapath);
3926 for(u32 j=0; j<dirlist.size(); j++){
3927 if(dirlist[j].dir) // Ignode dirs
3929 std::string filename = dirlist[j].name;
3930 // If name contains illegal characters, ignore the file
3931 if(!string_allowed(filename, TEXTURENAME_ALLOWED_CHARS)){
3932 infostream<<"Server: ignoring illegal file name: \""
3933 <<filename<<"\""<<std::endl;
3936 // If name is not in a supported format, ignore it
3937 const char *supported_ext[] = {
3938 ".png", ".jpg", ".bmp", ".tga",
3939 ".pcx", ".ppm", ".psd", ".wal", ".rgb",
3941 ".x", ".b3d", ".md2", ".obj",
3944 if(removeStringEnd(filename, supported_ext) == ""){
3945 infostream<<"Server: ignoring unsupported file extension: \""
3946 <<filename<<"\""<<std::endl;
3949 // Ok, attempt to load the file and add to cache
3950 std::string filepath = mediapath + DIR_DELIM + filename;
3952 std::ifstream fis(filepath.c_str(), std::ios_base::binary);
3953 if(fis.good() == false){
3954 errorstream<<"Server::fillMediaCache(): Could not open \""
3955 <<filename<<"\" for reading"<<std::endl;
3958 std::ostringstream tmp_os(std::ios_base::binary);
3962 fis.read(buf, 1024);
3963 std::streamsize len = fis.gcount();
3964 tmp_os.write(buf, len);
3973 errorstream<<"Server::fillMediaCache(): Failed to read \""
3974 <<filename<<"\""<<std::endl;
3977 if(tmp_os.str().length() == 0){
3978 errorstream<<"Server::fillMediaCache(): Empty file \""
3979 <<filepath<<"\""<<std::endl;
3984 sha1.addBytes(tmp_os.str().c_str(), tmp_os.str().length());
3986 unsigned char *digest = sha1.getDigest();
3987 std::string sha1_base64 = base64_encode(digest, 20);
3988 std::string sha1_hex = hex_encode((char*)digest, 20);
3992 this->m_media[filename] = MediaInfo(filepath, sha1_base64);
3993 verbosestream<<"Server: "<<sha1_hex<<" is "<<filename<<std::endl;
3998 struct SendableMediaAnnouncement
4001 std::string sha1_digest;
4003 SendableMediaAnnouncement(const std::string &name_="",
4004 const std::string &sha1_digest_=""):
4006 sha1_digest(sha1_digest_)
4010 void Server::sendMediaAnnouncement(u16 peer_id)
4012 DSTACK(__FUNCTION_NAME);
4014 verbosestream<<"Server: Announcing files to id("<<peer_id<<")"
4017 std::list<SendableMediaAnnouncement> file_announcements;
4019 for(std::map<std::string, MediaInfo>::iterator i = m_media.begin();
4020 i != m_media.end(); i++){
4022 file_announcements.push_back(
4023 SendableMediaAnnouncement(i->first, i->second.sha1_digest));
4027 std::ostringstream os(std::ios_base::binary);
4035 u16 length of sha1_digest
4040 writeU16(os, TOCLIENT_ANNOUNCE_MEDIA);
4041 writeU16(os, file_announcements.size());
4043 for(std::list<SendableMediaAnnouncement>::iterator
4044 j = file_announcements.begin();
4045 j != file_announcements.end(); ++j){
4046 os<<serializeString(j->name);
4047 os<<serializeString(j->sha1_digest);
4049 os<<serializeString(g_settings->get("remote_media"));
4052 std::string s = os.str();
4053 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
4056 m_clients.send(peer_id, 0, data, true);
4059 struct SendableMedia
4065 SendableMedia(const std::string &name_="", const std::string &path_="",
4066 const std::string &data_=""):
4073 void Server::sendRequestedMedia(u16 peer_id,
4074 const std::list<std::string> &tosend)
4076 DSTACK(__FUNCTION_NAME);
4078 verbosestream<<"Server::sendRequestedMedia(): "
4079 <<"Sending files to client"<<std::endl;
4083 // Put 5kB in one bunch (this is not accurate)
4084 u32 bytes_per_bunch = 5000;
4086 std::vector< std::list<SendableMedia> > file_bunches;
4087 file_bunches.push_back(std::list<SendableMedia>());
4089 u32 file_size_bunch_total = 0;
4091 for(std::list<std::string>::const_iterator i = tosend.begin();
4092 i != tosend.end(); ++i)
4094 const std::string &name = *i;
4096 if(m_media.find(name) == m_media.end()){
4097 errorstream<<"Server::sendRequestedMedia(): Client asked for "
4098 <<"unknown file \""<<(name)<<"\""<<std::endl;
4102 //TODO get path + name
4103 std::string tpath = m_media[name].path;
4106 std::ifstream fis(tpath.c_str(), std::ios_base::binary);
4107 if(fis.good() == false){
4108 errorstream<<"Server::sendRequestedMedia(): Could not open \""
4109 <<tpath<<"\" for reading"<<std::endl;
4112 std::ostringstream tmp_os(std::ios_base::binary);
4116 fis.read(buf, 1024);
4117 std::streamsize len = fis.gcount();
4118 tmp_os.write(buf, len);
4119 file_size_bunch_total += len;
4128 errorstream<<"Server::sendRequestedMedia(): Failed to read \""
4129 <<name<<"\""<<std::endl;
4132 /*infostream<<"Server::sendRequestedMedia(): Loaded \""
4133 <<tname<<"\""<<std::endl;*/
4135 file_bunches[file_bunches.size()-1].push_back(
4136 SendableMedia(name, tpath, tmp_os.str()));
4138 // Start next bunch if got enough data
4139 if(file_size_bunch_total >= bytes_per_bunch){
4140 file_bunches.push_back(std::list<SendableMedia>());
4141 file_size_bunch_total = 0;
4146 /* Create and send packets */
4148 u32 num_bunches = file_bunches.size();
4149 for(u32 i=0; i<num_bunches; i++)
4151 std::ostringstream os(std::ios_base::binary);
4155 u16 total number of texture bunches
4156 u16 index of this bunch
4157 u32 number of files in this bunch
4166 writeU16(os, TOCLIENT_MEDIA);
4167 writeU16(os, num_bunches);
4169 writeU32(os, file_bunches[i].size());
4171 for(std::list<SendableMedia>::iterator
4172 j = file_bunches[i].begin();
4173 j != file_bunches[i].end(); ++j){
4174 os<<serializeString(j->name);
4175 os<<serializeLongString(j->data);
4179 std::string s = os.str();
4180 verbosestream<<"Server::sendRequestedMedia(): bunch "
4181 <<i<<"/"<<num_bunches
4182 <<" files="<<file_bunches[i].size()
4183 <<" size=" <<s.size()<<std::endl;
4184 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
4186 m_clients.send(peer_id, 2, data, true);
4190 void Server::sendDetachedInventory(const std::string &name, u16 peer_id)
4192 if(m_detached_inventories.count(name) == 0){
4193 errorstream<<__FUNCTION_NAME<<": \""<<name<<"\" not found"<<std::endl;
4196 Inventory *inv = m_detached_inventories[name];
4198 std::ostringstream os(std::ios_base::binary);
4199 writeU16(os, TOCLIENT_DETACHED_INVENTORY);
4200 os<<serializeString(name);
4204 std::string s = os.str();
4205 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
4207 if (peer_id != PEER_ID_INEXISTENT)
4210 m_clients.send(peer_id, 0, data, true);
4214 m_clients.sendToAll(0,data,true);
4218 void Server::sendDetachedInventories(u16 peer_id)
4220 DSTACK(__FUNCTION_NAME);
4222 for(std::map<std::string, Inventory*>::iterator
4223 i = m_detached_inventories.begin();
4224 i != m_detached_inventories.end(); i++){
4225 const std::string &name = i->first;
4226 //Inventory *inv = i->second;
4227 sendDetachedInventory(name, peer_id);
4235 void Server::DiePlayer(u16 peer_id)
4237 DSTACK(__FUNCTION_NAME);
4239 PlayerSAO *playersao = getPlayerSAO(peer_id);
4242 infostream<<"Server::DiePlayer(): Player "
4243 <<playersao->getPlayer()->getName()
4244 <<" dies"<<std::endl;
4246 playersao->setHP(0);
4248 // Trigger scripted stuff
4249 m_script->on_dieplayer(playersao);
4251 SendPlayerHP(peer_id);
4252 SendDeathscreen(peer_id, false, v3f(0,0,0));
4255 void Server::RespawnPlayer(u16 peer_id)
4257 DSTACK(__FUNCTION_NAME);
4259 PlayerSAO *playersao = getPlayerSAO(peer_id);
4262 infostream<<"Server::RespawnPlayer(): Player "
4263 <<playersao->getPlayer()->getName()
4264 <<" respawns"<<std::endl;
4266 playersao->setHP(PLAYER_MAX_HP);
4268 bool repositioned = m_script->on_respawnplayer(playersao);
4270 v3f pos = findSpawnPos(m_env->getServerMap());
4271 playersao->setPos(pos);
4275 void Server::DenyAccess(u16 peer_id, const std::wstring &reason)
4277 DSTACK(__FUNCTION_NAME);
4279 SendAccessDenied(peer_id, reason);
4280 m_clients.event(peer_id, CSE_SetDenied);
4281 m_con.DisconnectPeer(peer_id);
4284 void Server::DeleteClient(u16 peer_id, ClientDeletionReason reason)
4286 DSTACK(__FUNCTION_NAME);
4287 std::wstring message;
4290 Clear references to playing sounds
4292 for(std::map<s32, ServerPlayingSound>::iterator
4293 i = m_playing_sounds.begin();
4294 i != m_playing_sounds.end();)
4296 ServerPlayingSound &psound = i->second;
4297 psound.clients.erase(peer_id);
4298 if(psound.clients.size() == 0)
4299 m_playing_sounds.erase(i++);
4304 Player *player = m_env->getPlayer(peer_id);
4306 // Collect information about leaving in chat
4308 if(player != NULL && reason != CDR_DENY)
4310 std::wstring name = narrow_to_wide(player->getName());
4313 message += L" left the game.";
4314 if(reason == CDR_TIMEOUT)
4315 message += L" (timed out)";
4319 /* Run scripts and remove from environment */
4323 PlayerSAO *playersao = player->getPlayerSAO();
4326 m_script->on_leaveplayer(playersao);
4328 playersao->disconnected();
4336 if(player != NULL && reason != CDR_DENY)
4338 std::ostringstream os(std::ios_base::binary);
4339 std::list<u16> clients = m_clients.getClientIDs();
4341 for(std::list<u16>::iterator
4342 i = clients.begin();
4343 i != clients.end(); ++i)
4346 Player *player = m_env->getPlayer(*i);
4349 // Get name of player
4350 os<<player->getName()<<" ";
4353 actionstream<<player->getName()<<" "
4354 <<(reason==CDR_TIMEOUT?"times out.":"leaves game.")
4355 <<" List of players: "<<os.str()<<std::endl;
4359 JMutexAutoLock env_lock(m_env_mutex);
4360 m_clients.DeleteClient(peer_id);
4364 // Send leave chat message to all remaining clients
4365 if(message.length() != 0)
4366 SendChatMessage(PEER_ID_INEXISTENT,message);
4369 void Server::UpdateCrafting(u16 peer_id)
4371 DSTACK(__FUNCTION_NAME);
4373 Player* player = m_env->getPlayer(peer_id);
4376 // Get a preview for crafting
4378 InventoryLocation loc;
4379 loc.setPlayer(player->getName());
4380 getCraftingResult(&player->inventory, preview, false, this);
4381 m_env->getScriptIface()->item_CraftPredict(preview, player->getPlayerSAO(), (&player->inventory)->getList("craft"), loc);
4383 // Put the new preview in
4384 InventoryList *plist = player->inventory.getList("craftpreview");
4386 assert(plist->getSize() >= 1);
4387 plist->changeItem(0, preview);
4390 RemoteClient* Server::getClient(u16 peer_id, ClientState state_min)
4392 RemoteClient *client = getClientNoEx(peer_id,state_min);
4394 throw ClientNotFoundException("Client not found");
4398 RemoteClient* Server::getClientNoEx(u16 peer_id, ClientState state_min)
4400 return m_clients.getClientNoEx(peer_id, state_min);
4403 std::string Server::getPlayerName(u16 peer_id)
4405 Player *player = m_env->getPlayer(peer_id);
4407 return "[id="+itos(peer_id)+"]";
4408 return player->getName();
4411 PlayerSAO* Server::getPlayerSAO(u16 peer_id)
4413 Player *player = m_env->getPlayer(peer_id);
4416 return player->getPlayerSAO();
4419 std::wstring Server::getStatusString()
4421 std::wostringstream os(std::ios_base::binary);
4424 os<<L"version="<<narrow_to_wide(minetest_version_simple);
4426 os<<L", uptime="<<m_uptime.get();
4428 os<<L", max_lag="<<m_env->getMaxLagEstimate();
4429 // Information about clients
4432 std::list<u16> clients = m_clients.getClientIDs();
4433 for(std::list<u16>::iterator i = clients.begin();
4434 i != clients.end(); ++i)
4437 Player *player = m_env->getPlayer(*i);
4438 // Get name of player
4439 std::wstring name = L"unknown";
4441 name = narrow_to_wide(player->getName());
4442 // Add name to information string
4450 if(((ServerMap*)(&m_env->getMap()))->isSavingEnabled() == false)
4451 os<<std::endl<<L"# Server: "<<" WARNING: Map saving is disabled.";
4452 if(g_settings->get("motd") != "")
4453 os<<std::endl<<L"# Server: "<<narrow_to_wide(g_settings->get("motd"));
4457 std::set<std::string> Server::getPlayerEffectivePrivs(const std::string &name)
4459 std::set<std::string> privs;
4460 m_script->getAuth(name, NULL, &privs);
4464 bool Server::checkPriv(const std::string &name, const std::string &priv)
4466 std::set<std::string> privs = getPlayerEffectivePrivs(name);
4467 return (privs.count(priv) != 0);
4470 void Server::reportPrivsModified(const std::string &name)
4473 std::list<u16> clients = m_clients.getClientIDs();
4474 for(std::list<u16>::iterator
4475 i = clients.begin();
4476 i != clients.end(); ++i){
4477 Player *player = m_env->getPlayer(*i);
4478 reportPrivsModified(player->getName());
4481 Player *player = m_env->getPlayer(name.c_str());
4484 SendPlayerPrivileges(player->peer_id);
4485 PlayerSAO *sao = player->getPlayerSAO();
4488 sao->updatePrivileges(
4489 getPlayerEffectivePrivs(name),
4494 void Server::reportInventoryFormspecModified(const std::string &name)
4496 Player *player = m_env->getPlayer(name.c_str());
4499 SendPlayerInventoryFormspec(player->peer_id);
4502 void Server::setIpBanned(const std::string &ip, const std::string &name)
4504 m_banmanager->add(ip, name);
4507 void Server::unsetIpBanned(const std::string &ip_or_name)
4509 m_banmanager->remove(ip_or_name);
4512 std::string Server::getBanDescription(const std::string &ip_or_name)
4514 return m_banmanager->getBanDescription(ip_or_name);
4517 void Server::notifyPlayer(const char *name, const std::wstring &msg)
4519 Player *player = m_env->getPlayer(name);
4523 if (player->peer_id == PEER_ID_INEXISTENT)
4526 SendChatMessage(player->peer_id, msg);
4529 bool Server::showFormspec(const char *playername, const std::string &formspec, const std::string &formname)
4531 Player *player = m_env->getPlayer(playername);
4535 infostream<<"showFormspec: couldn't find player:"<<playername<<std::endl;
4539 SendShowFormspecMessage(player->peer_id, formspec, formname);
4543 u32 Server::hudAdd(Player *player, HudElement *form) {
4547 u32 id = player->addHud(form);
4549 SendHUDAdd(player->peer_id, id, form);
4554 bool Server::hudRemove(Player *player, u32 id) {
4558 HudElement* todel = player->removeHud(id);
4565 SendHUDRemove(player->peer_id, id);
4569 bool Server::hudChange(Player *player, u32 id, HudElementStat stat, void *data) {
4573 SendHUDChange(player->peer_id, id, stat, data);
4577 bool Server::hudSetFlags(Player *player, u32 flags, u32 mask) {
4581 SendHUDSetFlags(player->peer_id, flags, mask);
4582 player->hud_flags = flags;
4584 PlayerSAO* playersao = player->getPlayerSAO();
4586 if (playersao == NULL)
4589 m_script->player_event(playersao, "hud_changed");
4593 bool Server::hudSetHotbarItemcount(Player *player, s32 hotbar_itemcount) {
4596 if (hotbar_itemcount <= 0 || hotbar_itemcount > HUD_HOTBAR_ITEMCOUNT_MAX)
4599 std::ostringstream os(std::ios::binary);
4600 writeS32(os, hotbar_itemcount);
4601 SendHUDSetParam(player->peer_id, HUD_PARAM_HOTBAR_ITEMCOUNT, os.str());
4605 void Server::hudSetHotbarImage(Player *player, std::string name) {
4609 SendHUDSetParam(player->peer_id, HUD_PARAM_HOTBAR_IMAGE, name);
4612 void Server::hudSetHotbarSelectedImage(Player *player, std::string name) {
4616 SendHUDSetParam(player->peer_id, HUD_PARAM_HOTBAR_SELECTED_IMAGE, name);
4619 bool Server::setLocalPlayerAnimations(Player *player, v2s32 animation_frames[4], f32 frame_speed)
4624 SendLocalPlayerAnimations(player->peer_id, animation_frames, frame_speed);
4628 bool Server::setPlayerEyeOffset(Player *player, v3f first, v3f third)
4633 SendEyeOffset(player->peer_id, first, third);
4637 bool Server::setSky(Player *player, const video::SColor &bgcolor,
4638 const std::string &type, const std::vector<std::string> ¶ms)
4643 SendSetSky(player->peer_id, bgcolor, type, params);
4647 bool Server::overrideDayNightRatio(Player *player, bool do_override,
4653 SendOverrideDayNightRatio(player->peer_id, do_override, ratio);
4657 void Server::notifyPlayers(const std::wstring &msg)
4659 SendChatMessage(PEER_ID_INEXISTENT,msg);
4662 void Server::spawnParticle(const char *playername, v3f pos,
4663 v3f velocity, v3f acceleration,
4664 float expirationtime, float size, bool
4665 collisiondetection, bool vertical, std::string texture)
4667 Player *player = m_env->getPlayer(playername);
4670 SendSpawnParticle(player->peer_id, pos, velocity, acceleration,
4671 expirationtime, size, collisiondetection, vertical, texture);
4674 void Server::spawnParticleAll(v3f pos, v3f velocity, v3f acceleration,
4675 float expirationtime, float size,
4676 bool collisiondetection, bool vertical, std::string texture)
4678 SendSpawnParticle(PEER_ID_INEXISTENT,pos, velocity, acceleration,
4679 expirationtime, size, collisiondetection, vertical, texture);
4682 u32 Server::addParticleSpawner(const char *playername,
4683 u16 amount, float spawntime,
4684 v3f minpos, v3f maxpos,
4685 v3f minvel, v3f maxvel,
4686 v3f minacc, v3f maxacc,
4687 float minexptime, float maxexptime,
4688 float minsize, float maxsize,
4689 bool collisiondetection, bool vertical, std::string texture)
4691 Player *player = m_env->getPlayer(playername);
4696 for(;;) // look for unused particlespawner id
4699 if (std::find(m_particlespawner_ids.begin(),
4700 m_particlespawner_ids.end(), id)
4701 == m_particlespawner_ids.end())
4703 m_particlespawner_ids.push_back(id);
4708 SendAddParticleSpawner(player->peer_id, amount, spawntime,
4709 minpos, maxpos, minvel, maxvel, minacc, maxacc,
4710 minexptime, maxexptime, minsize, maxsize,
4711 collisiondetection, vertical, texture, id);
4716 u32 Server::addParticleSpawnerAll(u16 amount, float spawntime,
4717 v3f minpos, v3f maxpos,
4718 v3f minvel, v3f maxvel,
4719 v3f minacc, v3f maxacc,
4720 float minexptime, float maxexptime,
4721 float minsize, float maxsize,
4722 bool collisiondetection, bool vertical, std::string texture)
4725 for(;;) // look for unused particlespawner id
4728 if (std::find(m_particlespawner_ids.begin(),
4729 m_particlespawner_ids.end(), id)
4730 == m_particlespawner_ids.end())
4732 m_particlespawner_ids.push_back(id);
4737 SendAddParticleSpawner(PEER_ID_INEXISTENT, amount, spawntime,
4738 minpos, maxpos, minvel, maxvel, minacc, maxacc,
4739 minexptime, maxexptime, minsize, maxsize,
4740 collisiondetection, vertical, texture, id);
4745 void Server::deleteParticleSpawner(const char *playername, u32 id)
4747 Player *player = m_env->getPlayer(playername);
4751 m_particlespawner_ids.erase(
4752 std::remove(m_particlespawner_ids.begin(),
4753 m_particlespawner_ids.end(), id),
4754 m_particlespawner_ids.end());
4755 SendDeleteParticleSpawner(player->peer_id, id);
4758 void Server::deleteParticleSpawnerAll(u32 id)
4760 m_particlespawner_ids.erase(
4761 std::remove(m_particlespawner_ids.begin(),
4762 m_particlespawner_ids.end(), id),
4763 m_particlespawner_ids.end());
4764 SendDeleteParticleSpawner(PEER_ID_INEXISTENT, id);
4767 Inventory* Server::createDetachedInventory(const std::string &name)
4769 if(m_detached_inventories.count(name) > 0){
4770 infostream<<"Server clearing detached inventory \""<<name<<"\""<<std::endl;
4771 delete m_detached_inventories[name];
4773 infostream<<"Server creating detached inventory \""<<name<<"\""<<std::endl;
4775 Inventory *inv = new Inventory(m_itemdef);
4777 m_detached_inventories[name] = inv;
4778 //TODO find a better way to do this
4779 sendDetachedInventory(name,PEER_ID_INEXISTENT);
4786 BoolScopeSet(bool *dst, bool val):
4789 m_orig_state = *m_dst;
4794 *m_dst = m_orig_state;
4801 // actions: time-reversed list
4802 // Return value: success/failure
4803 bool Server::rollbackRevertActions(const std::list<RollbackAction> &actions,
4804 std::list<std::string> *log)
4806 infostream<<"Server::rollbackRevertActions(len="<<actions.size()<<")"<<std::endl;
4807 ServerMap *map = (ServerMap*)(&m_env->getMap());
4808 // Disable rollback report sink while reverting
4809 BoolScopeSet rollback_scope_disable(&m_rollback_sink_enabled, false);
4811 // Fail if no actions to handle
4812 if(actions.empty()){
4813 log->push_back("Nothing to do.");
4820 for(std::list<RollbackAction>::const_iterator
4821 i = actions.begin();
4822 i != actions.end(); i++)
4824 const RollbackAction &action = *i;
4826 bool success = action.applyRevert(map, this, this);
4829 std::ostringstream os;
4830 os<<"Revert of step ("<<num_tried<<") "<<action.toString()<<" failed";
4831 infostream<<"Map::rollbackRevertActions(): "<<os.str()<<std::endl;
4833 log->push_back(os.str());
4835 std::ostringstream os;
4836 os<<"Successfully reverted step ("<<num_tried<<") "<<action.toString();
4837 infostream<<"Map::rollbackRevertActions(): "<<os.str()<<std::endl;
4839 log->push_back(os.str());
4843 infostream<<"Map::rollbackRevertActions(): "<<num_failed<<"/"<<num_tried
4844 <<" failed"<<std::endl;
4846 // Call it done if less than half failed
4847 return num_failed <= num_tried/2;
4850 // IGameDef interface
4852 IItemDefManager* Server::getItemDefManager()
4856 INodeDefManager* Server::getNodeDefManager()
4860 ICraftDefManager* Server::getCraftDefManager()
4864 ITextureSource* Server::getTextureSource()
4868 IShaderSource* Server::getShaderSource()
4872 u16 Server::allocateUnknownNodeId(const std::string &name)
4874 return m_nodedef->allocateDummy(name);
4876 ISoundManager* Server::getSoundManager()
4878 return &dummySoundManager;
4880 MtEventManager* Server::getEventManager()
4884 IRollbackReportSink* Server::getRollbackReportSink()
4886 if(!m_enable_rollback_recording)
4888 if(!m_rollback_sink_enabled)
4893 IWritableItemDefManager* Server::getWritableItemDefManager()
4897 IWritableNodeDefManager* Server::getWritableNodeDefManager()
4901 IWritableCraftDefManager* Server::getWritableCraftDefManager()
4906 const ModSpec* Server::getModSpec(const std::string &modname)
4908 for(std::vector<ModSpec>::iterator i = m_mods.begin();
4909 i != m_mods.end(); i++){
4910 const ModSpec &mod = *i;
4911 if(mod.name == modname)
4916 void Server::getModNames(std::list<std::string> &modlist)
4918 for(std::vector<ModSpec>::iterator i = m_mods.begin(); i != m_mods.end(); i++)
4920 modlist.push_back(i->name);
4923 std::string Server::getBuiltinLuaPath()
4925 return porting::path_share + DIR_DELIM + "builtin";
4928 v3f findSpawnPos(ServerMap &map)
4930 //return v3f(50,50,50)*BS;
4935 nodepos = v2s16(0,0);
4940 s16 water_level = map.getWaterLevel();
4942 // Try to find a good place a few times
4943 for(s32 i=0; i<1000; i++)
4946 // We're going to try to throw the player to this position
4947 v2s16 nodepos2d = v2s16(
4948 -range + (myrand() % (range * 2)),
4949 -range + (myrand() % (range * 2)));
4951 // Get ground height at point
4952 s16 groundheight = map.findGroundLevel(nodepos2d);
4953 if (groundheight <= water_level) // Don't go underwater
4955 if (groundheight > water_level + 6) // Don't go to high places
4958 nodepos = v3s16(nodepos2d.X, groundheight, nodepos2d.Y);
4959 bool is_good = false;
4961 for (s32 i = 0; i < 10; i++) {
4962 v3s16 blockpos = getNodeBlockPos(nodepos);
4963 map.emergeBlock(blockpos, true);
4964 content_t c = map.getNodeNoEx(nodepos).getContent();
4965 if (c == CONTENT_AIR || c == CONTENT_IGNORE) {
4967 if (air_count >= 2){
4975 // Found a good place
4976 //infostream<<"Searched through "<<i<<" places."<<std::endl;
4982 return intToFloat(nodepos, BS);
4985 PlayerSAO* Server::emergePlayer(const char *name, u16 peer_id)
4987 RemotePlayer *player = NULL;
4988 bool newplayer = false;
4991 Try to get an existing player
4993 player = static_cast<RemotePlayer*>(m_env->getPlayer(name));
4995 // If player is already connected, cancel
4996 if(player != NULL && player->peer_id != 0)
4998 infostream<<"emergePlayer(): Player already connected"<<std::endl;
5003 If player with the wanted peer_id already exists, cancel.
5005 if(m_env->getPlayer(peer_id) != NULL)
5007 infostream<<"emergePlayer(): Player with wrong name but same"
5008 " peer_id already exists"<<std::endl;
5012 // Load player if it isn't already loaded
5014 player = static_cast<RemotePlayer*>(m_env->loadPlayer(name));
5017 // Create player if it doesn't exist
5020 player = new RemotePlayer(this);
5021 player->updateName(name);
5022 /* Set player position */
5023 infostream<<"Server: Finding spawn place for player \""
5024 <<name<<"\""<<std::endl;
5025 v3f pos = findSpawnPos(m_env->getServerMap());
5026 player->setPosition(pos);
5028 /* Add player to environment */
5029 m_env->addPlayer(player);
5032 // Create a new player active object
5033 PlayerSAO *playersao = new PlayerSAO(m_env, player, peer_id,
5034 getPlayerEffectivePrivs(player->getName()),
5037 /* Clean up old HUD elements from previous sessions */
5040 /* Add object to environment */
5041 m_env->addActiveObject(playersao);
5045 m_script->on_newplayer(playersao);
5051 void dedicated_server_loop(Server &server, bool &kill)
5053 DSTACK(__FUNCTION_NAME);
5055 verbosestream<<"dedicated_server_loop()"<<std::endl;
5057 IntervalLimiter m_profiler_interval;
5061 float steplen = g_settings->getFloat("dedicated_server_step");
5062 // This is kind of a hack but can be done like this
5063 // because server.step() is very light
5065 ScopeProfiler sp(g_profiler, "dedicated server sleep");
5066 sleep_ms((int)(steplen*1000.0));
5068 server.step(steplen);
5070 if(server.getShutdownRequested() || kill)
5072 infostream<<"Dedicated server quitting"<<std::endl;
5074 if(g_settings->getBool("server_announce") == true)
5075 ServerList::sendAnnounce("delete");
5083 float profiler_print_interval =
5084 g_settings->getFloat("profiler_print_interval");
5085 if(profiler_print_interval != 0)
5087 if(m_profiler_interval.step(steplen, profiler_print_interval))
5089 infostream<<"Profiler:"<<std::endl;
5090 g_profiler->print(infostream);
5091 g_profiler->clear();