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);
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;
367 m_env->loadMeta(m_path_world);
371 infostream<<"Server: Loading players"<<std::endl;
372 m_env->deSerializePlayers(m_path_world);
375 Add some test ActiveBlockModifiers to environment
377 add_legacy_abms(m_env, m_nodedef);
379 m_liquid_transform_every = g_settings->getFloat("liquid_update");
384 infostream<<"Server destructing"<<std::endl;
387 Send shutdown message
390 std::wstring line = L"*** Server shutting down";
391 SendChatMessage(PEER_ID_INEXISTENT, line);
395 JMutexAutoLock envlock(m_env_mutex);
398 Execute script shutdown hooks
400 m_script->on_shutdown();
404 JMutexAutoLock envlock(m_env_mutex);
409 infostream<<"Server: Saving players"<<std::endl;
410 m_env->serializePlayers(m_path_world);
413 Save environment metadata
415 infostream<<"Server: Saving environment metadata"<<std::endl;
416 m_env->saveMeta(m_path_world);
425 // stop all emerge threads before deleting players that may have
426 // requested blocks to be emerged
427 m_emerge->stopThreads();
429 // Delete things in the reverse order of creation
432 // N.B. the EmergeManager should be deleted after the Environment since Map
433 // depends on EmergeManager to write its current params to the map meta
442 // Deinitialize scripting
443 infostream<<"Server: Deinitializing scripting"<<std::endl;
446 // Delete detached inventories
448 for(std::map<std::string, Inventory*>::iterator
449 i = m_detached_inventories.begin();
450 i != m_detached_inventories.end(); i++){
456 void Server::start(Address bind_addr)
458 DSTACK(__FUNCTION_NAME);
459 infostream<<"Starting server on "
460 << bind_addr.serializeString() <<"..."<<std::endl;
462 // Stop thread if already running
465 // Initialize connection
466 m_con.SetTimeoutMs(30);
467 m_con.Serve(bind_addr);
472 // ASCII art for the win!
474 <<" .__ __ __ "<<std::endl
475 <<" _____ |__| ____ _____/ |_ ____ _______/ |_ "<<std::endl
476 <<" / \\| |/ \\_/ __ \\ __\\/ __ \\ / ___/\\ __\\"<<std::endl
477 <<"| Y Y \\ | | \\ ___/| | \\ ___/ \\___ \\ | | "<<std::endl
478 <<"|__|_| /__|___| /\\___ >__| \\___ >____ > |__| "<<std::endl
479 <<" \\/ \\/ \\/ \\/ \\/ "<<std::endl;
480 actionstream<<"World at ["<<m_path_world<<"]"<<std::endl;
481 actionstream<<"Server for gameid=\""<<m_gamespec.id
482 <<"\" listening on "<<bind_addr.serializeString()<<":"
483 <<bind_addr.getPort() << "."<<std::endl;
488 DSTACK(__FUNCTION_NAME);
490 infostream<<"Server: Stopping and waiting threads"<<std::endl;
492 // Stop threads (set run=false first so both start stopping)
494 //m_emergethread.setRun(false);
496 //m_emergethread.stop();
498 infostream<<"Server: Threads stopped"<<std::endl;
501 void Server::step(float dtime)
503 DSTACK(__FUNCTION_NAME);
508 JMutexAutoLock lock(m_step_dtime_mutex);
509 m_step_dtime += dtime;
511 // Throw if fatal error occurred in thread
512 std::string async_err = m_async_fatal_error.get();
514 throw ServerError(async_err);
518 void Server::AsyncRunStep(bool initial_step)
520 DSTACK(__FUNCTION_NAME);
522 g_profiler->add("Server::AsyncRunStep (num)", 1);
526 JMutexAutoLock lock1(m_step_dtime_mutex);
527 dtime = m_step_dtime;
531 // Send blocks to clients
535 if((dtime < 0.001) && (initial_step == false))
538 g_profiler->add("Server::AsyncRunStep with dtime (num)", 1);
540 //infostream<<"Server steps "<<dtime<<std::endl;
541 //infostream<<"Server::AsyncRunStep(): dtime="<<dtime<<std::endl;
544 JMutexAutoLock lock1(m_step_dtime_mutex);
545 m_step_dtime -= dtime;
552 m_uptime.set(m_uptime.get() + dtime);
558 Update time of day and overall game time
561 JMutexAutoLock envlock(m_env_mutex);
563 m_env->setTimeOfDaySpeed(g_settings->getFloat("time_speed"));
566 Send to clients at constant intervals
569 m_time_of_day_send_timer -= dtime;
570 if(m_time_of_day_send_timer < 0.0)
572 m_time_of_day_send_timer = g_settings->getFloat("time_send_interval");
573 u16 time = m_env->getTimeOfDay();
574 float time_speed = g_settings->getFloat("time_speed");
575 SendTimeOfDay(PEER_ID_INEXISTENT, time, time_speed);
580 JMutexAutoLock lock(m_env_mutex);
581 // Figure out and report maximum lag to environment
582 float max_lag = m_env->getMaxLagEstimate();
583 max_lag *= 0.9998; // Decrease slowly (about half per 5 minutes)
585 if(dtime > 0.1 && dtime > max_lag * 2.0)
586 infostream<<"Server: Maximum lag peaked to "<<dtime
590 m_env->reportMaxLagEstimate(max_lag);
592 ScopeProfiler sp(g_profiler, "SEnv step");
593 ScopeProfiler sp2(g_profiler, "SEnv step avg", SPT_AVG);
597 const float map_timer_and_unload_dtime = 2.92;
598 if(m_map_timer_and_unload_interval.step(dtime, map_timer_and_unload_dtime))
600 JMutexAutoLock lock(m_env_mutex);
601 // Run Map's timers and unload unused data
602 ScopeProfiler sp(g_profiler, "Server: map timer and unload");
603 m_env->getMap().timerUpdate(map_timer_and_unload_dtime,
604 g_settings->getFloat("server_unload_unused_data_timeout"));
615 JMutexAutoLock lock(m_env_mutex);
617 std::list<u16> clientids = m_clients.getClientIDs();
619 ScopeProfiler sp(g_profiler, "Server: handle players");
621 for(std::list<u16>::iterator
622 i = clientids.begin();
623 i != clientids.end(); ++i)
625 PlayerSAO *playersao = getPlayerSAO(*i);
626 if(playersao == NULL)
630 Handle player HPs (die if hp=0)
632 if(playersao->m_hp_not_sent && g_settings->getBool("enable_damage"))
634 if(playersao->getHP() == 0)
641 Send player breath if changed
643 if(playersao->m_breath_not_sent) {
644 SendPlayerBreath(*i);
648 Send player inventories if necessary
650 if(playersao->m_moved){
652 playersao->m_moved = false;
654 if(playersao->m_inventory_not_sent){
661 /* Transform liquids */
662 m_liquid_transform_timer += dtime;
663 if(m_liquid_transform_timer >= m_liquid_transform_every)
665 m_liquid_transform_timer -= m_liquid_transform_every;
667 JMutexAutoLock lock(m_env_mutex);
669 ScopeProfiler sp(g_profiler, "Server: liquid transform");
671 std::map<v3s16, MapBlock*> modified_blocks;
672 m_env->getMap().transformLiquids(modified_blocks);
677 core::map<v3s16, MapBlock*> lighting_modified_blocks;
678 ServerMap &map = ((ServerMap&)m_env->getMap());
679 map.updateLighting(modified_blocks, lighting_modified_blocks);
681 // Add blocks modified by lighting to modified_blocks
682 for(core::map<v3s16, MapBlock*>::Iterator
683 i = lighting_modified_blocks.getIterator();
684 i.atEnd() == false; i++)
686 MapBlock *block = i.getNode()->getValue();
687 modified_blocks.insert(block->getPos(), block);
691 Set the modified blocks unsent for all the clients
693 if(modified_blocks.size() > 0)
695 SetBlocksNotSent(modified_blocks);
698 m_clients.step(dtime);
700 m_lag += (m_lag > dtime ? -1 : 1) * dtime/100;
702 // send masterserver announce
704 float &counter = m_masterserver_timer;
705 if(!isSingleplayer() && (!counter || counter >= 300.0) &&
706 g_settings->getBool("server_announce") == true)
708 ServerList::sendAnnounce(!counter ? "start" : "update",
709 m_clients.getPlayerNames(),
711 m_env->getGameTime(),
722 Check added and deleted active objects
725 //infostream<<"Server: Checking added and deleted active objects"<<std::endl;
726 JMutexAutoLock envlock(m_env_mutex);
729 std::map<u16, RemoteClient*> clients = m_clients.getClientList();
730 ScopeProfiler sp(g_profiler, "Server: checking added and deleted objs");
732 // Radius inside which objects are active
733 s16 radius = g_settings->getS16("active_object_send_range_blocks");
734 radius *= MAP_BLOCKSIZE;
736 for(std::map<u16, RemoteClient*>::iterator
738 i != clients.end(); ++i)
740 RemoteClient *client = i->second;
742 // If definitions and textures have not been sent, don't
743 // send objects either
744 if (client->getState() < DefinitionsSent)
747 Player *player = m_env->getPlayer(client->peer_id);
750 // This can happen if the client timeouts somehow
751 /*infostream<<"WARNING: "<<__FUNCTION_NAME<<": Client "
753 <<" has no associated player"<<std::endl;*/
756 v3s16 pos = floatToInt(player->getPosition(), BS);
758 std::set<u16> removed_objects;
759 std::set<u16> added_objects;
760 m_env->getRemovedActiveObjects(pos, radius,
761 client->m_known_objects, removed_objects);
762 m_env->getAddedActiveObjects(pos, radius,
763 client->m_known_objects, added_objects);
765 // Ignore if nothing happened
766 if(removed_objects.size() == 0 && added_objects.size() == 0)
768 //infostream<<"active objects: none changed"<<std::endl;
772 std::string data_buffer;
776 // Handle removed objects
777 writeU16((u8*)buf, removed_objects.size());
778 data_buffer.append(buf, 2);
779 for(std::set<u16>::iterator
780 i = removed_objects.begin();
781 i != removed_objects.end(); ++i)
785 ServerActiveObject* obj = m_env->getActiveObject(id);
787 // Add to data buffer for sending
788 writeU16((u8*)buf, id);
789 data_buffer.append(buf, 2);
791 // Remove from known objects
792 client->m_known_objects.erase(id);
794 if(obj && obj->m_known_by_count > 0)
795 obj->m_known_by_count--;
798 // Handle added objects
799 writeU16((u8*)buf, added_objects.size());
800 data_buffer.append(buf, 2);
801 for(std::set<u16>::iterator
802 i = added_objects.begin();
803 i != added_objects.end(); ++i)
807 ServerActiveObject* obj = m_env->getActiveObject(id);
810 u8 type = ACTIVEOBJECT_TYPE_INVALID;
812 infostream<<"WARNING: "<<__FUNCTION_NAME
813 <<": NULL object"<<std::endl;
815 type = obj->getSendType();
817 // Add to data buffer for sending
818 writeU16((u8*)buf, id);
819 data_buffer.append(buf, 2);
820 writeU8((u8*)buf, type);
821 data_buffer.append(buf, 1);
824 data_buffer.append(serializeLongString(
825 obj->getClientInitializationData(client->net_proto_version)));
827 data_buffer.append(serializeLongString(""));
829 // Add to known objects
830 client->m_known_objects.insert(id);
833 obj->m_known_by_count++;
837 SharedBuffer<u8> reply(2 + data_buffer.size());
838 writeU16(&reply[0], TOCLIENT_ACTIVE_OBJECT_REMOVE_ADD);
839 memcpy((char*)&reply[2], data_buffer.c_str(),
842 m_clients.send(client->peer_id, 0, reply, true);
844 verbosestream<<"Server: Sent object remove/add: "
845 <<removed_objects.size()<<" removed, "
846 <<added_objects.size()<<" added, "
847 <<"packet size is "<<reply.getSize()<<std::endl;
852 Collect a list of all the objects known by the clients
853 and report it back to the environment.
856 core::map<u16, bool> all_known_objects;
858 for(core::map<u16, RemoteClient*>::Iterator
859 i = m_clients.getIterator();
860 i.atEnd() == false; i++)
862 RemoteClient *client = i.getNode()->getValue();
863 // Go through all known objects of client
864 for(core::map<u16, bool>::Iterator
865 i = client->m_known_objects.getIterator();
866 i.atEnd()==false; i++)
868 u16 id = i.getNode()->getKey();
869 all_known_objects[id] = true;
873 m_env->setKnownActiveObjects(whatever);
882 JMutexAutoLock envlock(m_env_mutex);
883 ScopeProfiler sp(g_profiler, "Server: sending object messages");
886 // Value = data sent by object
887 std::map<u16, std::list<ActiveObjectMessage>* > buffered_messages;
889 // Get active object messages from environment
892 ActiveObjectMessage aom = m_env->getActiveObjectMessage();
896 std::list<ActiveObjectMessage>* message_list = NULL;
897 std::map<u16, std::list<ActiveObjectMessage>* >::iterator n;
898 n = buffered_messages.find(aom.id);
899 if(n == buffered_messages.end())
901 message_list = new std::list<ActiveObjectMessage>;
902 buffered_messages[aom.id] = message_list;
906 message_list = n->second;
908 message_list->push_back(aom);
912 std::map<u16, RemoteClient*> clients = m_clients.getClientList();
913 // Route data to every client
914 for(std::map<u16, RemoteClient*>::iterator
916 i != clients.end(); ++i)
918 RemoteClient *client = i->second;
919 std::string reliable_data;
920 std::string unreliable_data;
921 // Go through all objects in message buffer
922 for(std::map<u16, std::list<ActiveObjectMessage>* >::iterator
923 j = buffered_messages.begin();
924 j != buffered_messages.end(); ++j)
926 // If object is not known by client, skip it
928 if(client->m_known_objects.find(id) == client->m_known_objects.end())
930 // Get message list of object
931 std::list<ActiveObjectMessage>* list = j->second;
932 // Go through every message
933 for(std::list<ActiveObjectMessage>::iterator
934 k = list->begin(); k != list->end(); ++k)
936 // Compose the full new data with header
937 ActiveObjectMessage aom = *k;
938 std::string new_data;
941 writeU16((u8*)&buf[0], aom.id);
942 new_data.append(buf, 2);
944 new_data += serializeString(aom.datastring);
945 // Add data to buffer
947 reliable_data += new_data;
949 unreliable_data += new_data;
953 reliable_data and unreliable_data are now ready.
956 if(reliable_data.size() > 0)
958 SharedBuffer<u8> reply(2 + reliable_data.size());
959 writeU16(&reply[0], TOCLIENT_ACTIVE_OBJECT_MESSAGES);
960 memcpy((char*)&reply[2], reliable_data.c_str(),
961 reliable_data.size());
963 m_clients.send(client->peer_id, 0, reply, true);
965 if(unreliable_data.size() > 0)
967 SharedBuffer<u8> reply(2 + unreliable_data.size());
968 writeU16(&reply[0], TOCLIENT_ACTIVE_OBJECT_MESSAGES);
969 memcpy((char*)&reply[2], unreliable_data.c_str(),
970 unreliable_data.size());
971 // Send as unreliable
972 m_clients.send(client->peer_id, 1, reply, false);
975 /*if(reliable_data.size() > 0 || unreliable_data.size() > 0)
977 infostream<<"Server: Size of object message data: "
978 <<"reliable: "<<reliable_data.size()
979 <<", unreliable: "<<unreliable_data.size()
985 // Clear buffered_messages
986 for(std::map<u16, std::list<ActiveObjectMessage>* >::iterator
987 i = buffered_messages.begin();
988 i != buffered_messages.end(); ++i)
995 Send queued-for-sending map edit events.
998 // We will be accessing the environment
999 JMutexAutoLock lock(m_env_mutex);
1001 // Don't send too many at a time
1004 // Single change sending is disabled if queue size is not small
1005 bool disable_single_change_sending = false;
1006 if(m_unsent_map_edit_queue.size() >= 4)
1007 disable_single_change_sending = true;
1009 int event_count = m_unsent_map_edit_queue.size();
1011 // We'll log the amount of each
1014 while(m_unsent_map_edit_queue.size() != 0)
1016 MapEditEvent* event = m_unsent_map_edit_queue.pop_front();
1018 // Players far away from the change are stored here.
1019 // Instead of sending the changes, MapBlocks are set not sent
1021 std::list<u16> far_players;
1023 if(event->type == MEET_ADDNODE || event->type == MEET_SWAPNODE)
1025 //infostream<<"Server: MEET_ADDNODE"<<std::endl;
1026 prof.add("MEET_ADDNODE", 1);
1027 if(disable_single_change_sending)
1028 sendAddNode(event->p, event->n, event->already_known_by_peer,
1029 &far_players, 5, event->type == MEET_ADDNODE);
1031 sendAddNode(event->p, event->n, event->already_known_by_peer,
1032 &far_players, 30, event->type == MEET_ADDNODE);
1034 else if(event->type == MEET_REMOVENODE)
1036 //infostream<<"Server: MEET_REMOVENODE"<<std::endl;
1037 prof.add("MEET_REMOVENODE", 1);
1038 if(disable_single_change_sending)
1039 sendRemoveNode(event->p, event->already_known_by_peer,
1042 sendRemoveNode(event->p, event->already_known_by_peer,
1045 else if(event->type == MEET_BLOCK_NODE_METADATA_CHANGED)
1047 infostream<<"Server: MEET_BLOCK_NODE_METADATA_CHANGED"<<std::endl;
1048 prof.add("MEET_BLOCK_NODE_METADATA_CHANGED", 1);
1049 setBlockNotSent(event->p);
1051 else if(event->type == MEET_OTHER)
1053 infostream<<"Server: MEET_OTHER"<<std::endl;
1054 prof.add("MEET_OTHER", 1);
1055 for(std::set<v3s16>::iterator
1056 i = event->modified_blocks.begin();
1057 i != event->modified_blocks.end(); ++i)
1059 setBlockNotSent(*i);
1064 prof.add("unknown", 1);
1065 infostream<<"WARNING: Server: Unknown MapEditEvent "
1066 <<((u32)event->type)<<std::endl;
1070 Set blocks not sent to far players
1072 if(far_players.size() > 0)
1074 // Convert list format to that wanted by SetBlocksNotSent
1075 std::map<v3s16, MapBlock*> modified_blocks2;
1076 for(std::set<v3s16>::iterator
1077 i = event->modified_blocks.begin();
1078 i != event->modified_blocks.end(); ++i)
1080 modified_blocks2[*i] =
1081 m_env->getMap().getBlockNoCreateNoEx(*i);
1083 // Set blocks not sent
1084 for(std::list<u16>::iterator
1085 i = far_players.begin();
1086 i != far_players.end(); ++i)
1089 RemoteClient *client = getClient(peer_id);
1092 client->SetBlocksNotSent(modified_blocks2);
1098 /*// Don't send too many at a time
1100 if(count >= 1 && m_unsent_map_edit_queue.size() < 100)
1104 if(event_count >= 5){
1105 infostream<<"Server: MapEditEvents:"<<std::endl;
1106 prof.print(infostream);
1107 } else if(event_count != 0){
1108 verbosestream<<"Server: MapEditEvents:"<<std::endl;
1109 prof.print(verbosestream);
1115 Trigger emergethread (it somehow gets to a non-triggered but
1116 bysy state sometimes)
1119 float &counter = m_emergethread_trigger_timer;
1125 m_emerge->startThreads();
1127 // Update m_enable_rollback_recording here too
1128 m_enable_rollback_recording =
1129 g_settings->getBool("enable_rollback_recording");
1133 // Save map, players and auth stuff
1135 float &counter = m_savemap_timer;
1137 if(counter >= g_settings->getFloat("server_map_save_interval"))
1140 JMutexAutoLock lock(m_env_mutex);
1142 ScopeProfiler sp(g_profiler, "Server: saving stuff");
1145 if(m_banmanager->isModified())
1146 m_banmanager->save();
1148 // Save changed parts of map
1149 m_env->getMap().save(MOD_STATE_WRITE_NEEDED);
1152 m_env->serializePlayers(m_path_world);
1154 // Save environment metadata
1155 m_env->saveMeta(m_path_world);
1160 void Server::Receive()
1162 DSTACK(__FUNCTION_NAME);
1163 SharedBuffer<u8> data;
1167 datasize = m_con.Receive(peer_id,data);
1168 ProcessData(*data, datasize, peer_id);
1170 catch(con::InvalidIncomingDataException &e)
1172 infostream<<"Server::Receive(): "
1173 "InvalidIncomingDataException: what()="
1174 <<e.what()<<std::endl;
1176 catch(SerializationError &e) {
1177 infostream<<"Server::Receive(): "
1178 "SerializationError: what()="
1179 <<e.what()<<std::endl;
1181 catch(con::PeerNotFoundException &e)
1183 //NOTE: This is not needed anymore
1185 // The peer has been disconnected.
1186 // Find the associated player and remove it.
1188 /*JMutexAutoLock envlock(m_env_mutex);
1190 infostream<<"ServerThread: peer_id="<<peer_id
1191 <<" has apparently closed connection. "
1192 <<"Removing player."<<std::endl;
1194 m_env->removePlayer(peer_id);*/
1196 catch(ClientStateError &e)
1198 errorstream << "ProcessData: peer=" << peer_id << e.what() << std::endl;
1199 DenyAccess(peer_id, L"Your client sent something server didn't expect."
1200 L"Try reconnecting or updating your client");
1204 PlayerSAO* Server::StageTwoClientInit(u16 peer_id)
1206 std::string playername = "";
1207 PlayerSAO *playersao = NULL;
1209 RemoteClient* client = m_clients.lockedGetClientNoEx(peer_id,InitDone);
1210 if (client != NULL) {
1211 playername = client->getName();
1212 playersao = emergePlayer(playername.c_str(), peer_id);
1216 RemotePlayer *player =
1217 static_cast<RemotePlayer*>(m_env->getPlayer(playername.c_str()));
1219 // If failed, cancel
1220 if((playersao == NULL) || (player == NULL))
1222 if(player && player->peer_id != 0){
1223 errorstream<<"Server: "<<playername<<": Failed to emerge player"
1224 <<" (player allocated to an another client)"<<std::endl;
1225 DenyAccess(peer_id, L"Another client is connected with this "
1226 L"name. If your client closed unexpectedly, try again in "
1229 errorstream<<"Server: "<<playername<<": Failed to emerge player"
1231 DenyAccess(peer_id, L"Could not allocate player.");
1237 Send complete position information
1239 SendMovePlayer(peer_id);
1242 SendPlayerPrivileges(peer_id);
1244 // Send inventory formspec
1245 SendPlayerInventoryFormspec(peer_id);
1248 UpdateCrafting(peer_id);
1249 SendInventory(peer_id);
1252 if(g_settings->getBool("enable_damage"))
1253 SendPlayerHP(peer_id);
1256 SendPlayerBreath(peer_id);
1258 // Show death screen if necessary
1260 SendDeathscreen(peer_id, false, v3f(0,0,0));
1262 // Note things in chat if not in simple singleplayer mode
1263 if(!m_simple_singleplayer_mode)
1265 // Send information about server to player in chat
1266 SendChatMessage(peer_id, getStatusString());
1268 // Send information about joining in chat
1270 std::wstring name = L"unknown";
1271 Player *player = m_env->getPlayer(peer_id);
1273 name = narrow_to_wide(player->getName());
1275 std::wstring message;
1278 message += L" joined the game.";
1279 SendChatMessage(PEER_ID_INEXISTENT,message);
1282 Address addr = getPeerAddress(player->peer_id);
1283 std::string ip_str = addr.serializeString();
1284 actionstream<<player->getName() <<" [" << ip_str << "] joins game. " << std::endl;
1289 std::vector<std::string> names = m_clients.getPlayerNames();
1291 actionstream<<player->getName() <<" joins game. List of players: ";
1293 for (std::vector<std::string>::iterator i = names.begin();
1294 i != names.end(); i++)
1296 actionstream << *i << " ";
1299 actionstream << player->getName() <<std::endl;
1304 void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
1306 DSTACK(__FUNCTION_NAME);
1307 // Environment is locked first.
1308 JMutexAutoLock envlock(m_env_mutex);
1310 ScopeProfiler sp(g_profiler, "Server::ProcessData");
1314 Address address = getPeerAddress(peer_id);
1315 addr_s = address.serializeString();
1317 // drop player if is ip is banned
1318 if(m_banmanager->isIpBanned(addr_s)){
1319 std::string ban_name = m_banmanager->getBanName(addr_s);
1320 infostream<<"Server: A banned client tried to connect from "
1321 <<addr_s<<"; banned name was "
1322 <<ban_name<<std::endl;
1323 // This actually doesn't seem to transfer to the client
1324 DenyAccess(peer_id, L"Your ip is banned. Banned name was "
1325 +narrow_to_wide(ban_name));
1329 catch(con::PeerNotFoundException &e)
1332 * no peer for this packet found
1333 * most common reason is peer timeout, e.g. peer didn't
1334 * respond for some time, your server was overloaded or
1337 infostream<<"Server::ProcessData(): Cancelling: peer "
1338 <<peer_id<<" not found"<<std::endl;
1348 ToServerCommand command = (ToServerCommand)readU16(&data[0]);
1350 if(command == TOSERVER_INIT)
1352 // [0] u16 TOSERVER_INIT
1353 // [2] u8 SER_FMT_VER_HIGHEST_READ
1354 // [3] u8[20] player_name
1355 // [23] u8[28] password <--- can be sent without this, from old versions
1357 if(datasize < 2+1+PLAYERNAME_SIZE)
1360 RemoteClient* client = getClient(peer_id,Created);
1362 // If net_proto_version is set, this client has already been handled
1363 if(client->getState() > Created)
1365 verbosestream<<"Server: Ignoring multiple TOSERVER_INITs from "
1366 <<addr_s<<" (peer_id="<<peer_id<<")"<<std::endl;
1370 verbosestream<<"Server: Got TOSERVER_INIT from "<<addr_s<<" (peer_id="
1371 <<peer_id<<")"<<std::endl;
1373 // Do not allow multiple players in simple singleplayer mode.
1374 // This isn't a perfect way to do it, but will suffice for now
1375 if(m_simple_singleplayer_mode && m_clients.getClientIDs().size() > 1){
1376 infostream<<"Server: Not allowing another client ("<<addr_s
1377 <<") to connect in simple singleplayer mode"<<std::endl;
1378 DenyAccess(peer_id, L"Running in simple singleplayer mode.");
1382 // First byte after command is maximum supported
1383 // serialization version
1384 u8 client_max = data[2];
1385 u8 our_max = SER_FMT_VER_HIGHEST_READ;
1386 // Use the highest version supported by both
1387 u8 deployed = std::min(client_max, our_max);
1388 // If it's lower than the lowest supported, give up.
1389 if(deployed < SER_FMT_VER_LOWEST)
1390 deployed = SER_FMT_VER_INVALID;
1392 if(deployed == SER_FMT_VER_INVALID)
1394 actionstream<<"Server: A mismatched client tried to connect from "
1395 <<addr_s<<std::endl;
1396 infostream<<"Server: Cannot negotiate serialization version with "
1397 <<addr_s<<std::endl;
1398 DenyAccess(peer_id, std::wstring(
1399 L"Your client's version is not supported.\n"
1400 L"Server version is ")
1401 + narrow_to_wide(minetest_version_simple) + L"."
1406 client->setPendingSerializationVersion(deployed);
1409 Read and check network protocol version
1412 u16 min_net_proto_version = 0;
1413 if(datasize >= 2+1+PLAYERNAME_SIZE+PASSWORD_SIZE+2)
1414 min_net_proto_version = readU16(&data[2+1+PLAYERNAME_SIZE+PASSWORD_SIZE]);
1416 // Use same version as minimum and maximum if maximum version field
1417 // doesn't exist (backwards compatibility)
1418 u16 max_net_proto_version = min_net_proto_version;
1419 if(datasize >= 2+1+PLAYERNAME_SIZE+PASSWORD_SIZE+2+2)
1420 max_net_proto_version = readU16(&data[2+1+PLAYERNAME_SIZE+PASSWORD_SIZE+2]);
1422 // Start with client's maximum version
1423 u16 net_proto_version = max_net_proto_version;
1425 // Figure out a working version if it is possible at all
1426 if(max_net_proto_version >= SERVER_PROTOCOL_VERSION_MIN ||
1427 min_net_proto_version <= SERVER_PROTOCOL_VERSION_MAX)
1429 // If maximum is larger than our maximum, go with our maximum
1430 if(max_net_proto_version > SERVER_PROTOCOL_VERSION_MAX)
1431 net_proto_version = SERVER_PROTOCOL_VERSION_MAX;
1432 // Else go with client's maximum
1434 net_proto_version = max_net_proto_version;
1437 verbosestream<<"Server: "<<addr_s<<": Protocol version: min: "
1438 <<min_net_proto_version<<", max: "<<max_net_proto_version
1439 <<", chosen: "<<net_proto_version<<std::endl;
1441 client->net_proto_version = net_proto_version;
1443 if(net_proto_version < SERVER_PROTOCOL_VERSION_MIN ||
1444 net_proto_version > SERVER_PROTOCOL_VERSION_MAX)
1446 actionstream<<"Server: A mismatched client tried to connect from "
1447 <<addr_s<<std::endl;
1448 DenyAccess(peer_id, std::wstring(
1449 L"Your client's version is not supported.\n"
1450 L"Server version is ")
1451 + narrow_to_wide(minetest_version_simple) + L",\n"
1452 + L"server's PROTOCOL_VERSION is "
1453 + narrow_to_wide(itos(SERVER_PROTOCOL_VERSION_MIN))
1455 + narrow_to_wide(itos(SERVER_PROTOCOL_VERSION_MAX))
1456 + L", client's PROTOCOL_VERSION is "
1457 + narrow_to_wide(itos(min_net_proto_version))
1459 + narrow_to_wide(itos(max_net_proto_version))
1464 if(g_settings->getBool("strict_protocol_version_checking"))
1466 if(net_proto_version != LATEST_PROTOCOL_VERSION)
1468 actionstream<<"Server: A mismatched (strict) client tried to "
1469 <<"connect from "<<addr_s<<std::endl;
1470 DenyAccess(peer_id, std::wstring(
1471 L"Your client's version is not supported.\n"
1472 L"Server version is ")
1473 + narrow_to_wide(minetest_version_simple) + L",\n"
1474 + L"server's PROTOCOL_VERSION (strict) is "
1475 + narrow_to_wide(itos(LATEST_PROTOCOL_VERSION))
1476 + L", client's PROTOCOL_VERSION is "
1477 + narrow_to_wide(itos(min_net_proto_version))
1479 + narrow_to_wide(itos(max_net_proto_version))
1490 char playername[PLAYERNAME_SIZE];
1491 for(u32 i=0; i<PLAYERNAME_SIZE-1; i++)
1493 playername[i] = data[3+i];
1495 playername[PLAYERNAME_SIZE-1] = 0;
1497 if(playername[0]=='\0')
1499 actionstream<<"Server: Player with an empty name "
1500 <<"tried to connect from "<<addr_s<<std::endl;
1501 DenyAccess(peer_id, L"Empty name");
1505 if(string_allowed(playername, PLAYERNAME_ALLOWED_CHARS)==false)
1507 actionstream<<"Server: Player with an invalid name "
1508 <<"tried to connect from "<<addr_s<<std::endl;
1509 DenyAccess(peer_id, L"Name contains unallowed characters");
1513 if(!isSingleplayer() && strcasecmp(playername, "singleplayer") == 0)
1515 actionstream<<"Server: Player with the name \"singleplayer\" "
1516 <<"tried to connect from "<<addr_s<<std::endl;
1517 DenyAccess(peer_id, L"Name is not allowed");
1523 if(m_script->on_prejoinplayer(playername, addr_s, reason))
1525 actionstream<<"Server: Player with the name \""<<playername<<"\" "
1526 <<"tried to connect from "<<addr_s<<" "
1527 <<"but it was disallowed for the following reason: "
1528 <<reason<<std::endl;
1529 DenyAccess(peer_id, narrow_to_wide(reason.c_str()));
1534 infostream<<"Server: New connection: \""<<playername<<"\" from "
1535 <<addr_s<<" (peer_id="<<peer_id<<")"<<std::endl;
1538 char given_password[PASSWORD_SIZE];
1539 if(datasize < 2+1+PLAYERNAME_SIZE+PASSWORD_SIZE)
1541 // old version - assume blank password
1542 given_password[0] = 0;
1546 for(u32 i=0; i<PASSWORD_SIZE-1; i++)
1548 given_password[i] = data[23+i];
1550 given_password[PASSWORD_SIZE-1] = 0;
1553 if(!base64_is_valid(given_password)){
1554 actionstream<<"Server: "<<playername
1555 <<" supplied invalid password hash"<<std::endl;
1556 DenyAccess(peer_id, L"Invalid password hash");
1560 // Enforce user limit.
1561 // Don't enforce for users that have some admin right
1562 if(m_clients.getClientIDs(Created).size() >= g_settings->getU16("max_users") &&
1563 !checkPriv(playername, "server") &&
1564 !checkPriv(playername, "ban") &&
1565 !checkPriv(playername, "privs") &&
1566 !checkPriv(playername, "password") &&
1567 playername != g_settings->get("name"))
1569 actionstream<<"Server: "<<playername<<" tried to join, but there"
1570 <<" are already max_users="
1571 <<g_settings->getU16("max_users")<<" players."<<std::endl;
1572 DenyAccess(peer_id, L"Too many users.");
1576 std::string checkpwd; // Password hash to check against
1577 bool has_auth = m_script->getAuth(playername, &checkpwd, NULL);
1579 // If no authentication info exists for user, create it
1581 if(!isSingleplayer() &&
1582 g_settings->getBool("disallow_empty_password") &&
1583 std::string(given_password) == ""){
1584 actionstream<<"Server: "<<playername
1585 <<" supplied empty password"<<std::endl;
1586 DenyAccess(peer_id, L"Empty passwords are "
1587 L"disallowed. Set a password and try again.");
1590 std::wstring raw_default_password =
1591 narrow_to_wide(g_settings->get("default_password"));
1592 std::string initial_password =
1593 translatePassword(playername, raw_default_password);
1595 // If default_password is empty, allow any initial password
1596 if (raw_default_password.length() == 0)
1597 initial_password = given_password;
1599 m_script->createAuth(playername, initial_password);
1602 has_auth = m_script->getAuth(playername, &checkpwd, NULL);
1605 actionstream<<"Server: "<<playername<<" cannot be authenticated"
1606 <<" (auth handler does not work?)"<<std::endl;
1607 DenyAccess(peer_id, L"Not allowed to login");
1611 if(given_password != checkpwd){
1612 actionstream<<"Server: "<<playername<<" supplied wrong password"
1614 DenyAccess(peer_id, L"Wrong password");
1618 RemotePlayer *player =
1619 static_cast<RemotePlayer*>(m_env->getPlayer(playername));
1621 if(player && player->peer_id != 0){
1622 errorstream<<"Server: "<<playername<<": Failed to emerge player"
1623 <<" (player allocated to an another client)"<<std::endl;
1624 DenyAccess(peer_id, L"Another client is connected with this "
1625 L"name. If your client closed unexpectedly, try again in "
1629 m_clients.setPlayerName(peer_id,playername);
1632 Answer with a TOCLIENT_INIT
1635 SharedBuffer<u8> reply(2+1+6+8+4);
1636 writeU16(&reply[0], TOCLIENT_INIT);
1637 writeU8(&reply[2], deployed);
1638 //send dummy pos for legacy reasons only
1639 writeV3S16(&reply[2+1], floatToInt(v3f(0,0,0), BS));
1640 writeU64(&reply[2+1+6], m_env->getServerMap().getSeed());
1641 writeF1000(&reply[2+1+6+8], g_settings->getFloat("dedicated_server_step"));
1644 m_clients.send(peer_id, 0, reply, true);
1645 m_clients.event(peer_id, Init);
1651 if(command == TOSERVER_INIT2)
1654 verbosestream<<"Server: Got TOSERVER_INIT2 from "
1655 <<peer_id<<std::endl;
1657 m_clients.event(peer_id, GotInit2);
1658 u16 protocol_version = m_clients.getProtocolVersion(peer_id);
1661 ///// begin compatibility code
1662 PlayerSAO* playersao = NULL;
1663 if (protocol_version <= 22) {
1664 playersao = StageTwoClientInit(peer_id);
1666 if (playersao == NULL) {
1668 << "TOSERVER_INIT2 stage 2 client init failed for peer "
1669 << peer_id << std::endl;
1673 ///// end compatibility code
1676 Send some initialization data
1679 infostream<<"Server: Sending content to "
1680 <<getPlayerName(peer_id)<<std::endl;
1682 // Send player movement settings
1683 SendMovement(peer_id);
1685 // Send item definitions
1686 SendItemDef(peer_id, m_itemdef, protocol_version);
1688 // Send node definitions
1689 SendNodeDef(peer_id, m_nodedef, protocol_version);
1691 m_clients.event(peer_id, SetDefinitionsSent);
1693 // Send media announcement
1694 sendMediaAnnouncement(peer_id);
1696 // Send detached inventories
1697 sendDetachedInventories(peer_id);
1700 u16 time = m_env->getTimeOfDay();
1701 float time_speed = g_settings->getFloat("time_speed");
1702 SendTimeOfDay(peer_id, time, time_speed);
1704 ///// begin compatibility code
1705 if (protocol_version <= 22) {
1706 m_clients.event(peer_id, SetClientReady);
1707 m_script->on_joinplayer(playersao);
1709 ///// end compatibility code
1711 // Warnings about protocol version can be issued here
1712 if(getClient(peer_id)->net_proto_version < LATEST_PROTOCOL_VERSION)
1714 SendChatMessage(peer_id, L"# Server: WARNING: YOUR CLIENT'S "
1715 L"VERSION MAY NOT BE FULLY COMPATIBLE WITH THIS SERVER!");
1721 u8 peer_ser_ver = getClient(peer_id,InitDone)->serialization_version;
1722 u16 peer_proto_ver = getClient(peer_id,InitDone)->net_proto_version;
1724 if(peer_ser_ver == SER_FMT_VER_INVALID)
1726 errorstream<<"Server::ProcessData(): Cancelling: Peer"
1727 " serialization format invalid or not initialized."
1728 " Skipping incoming command="<<command<<std::endl;
1732 /* Handle commands relate to client startup */
1733 if(command == TOSERVER_REQUEST_MEDIA) {
1734 std::string datastring((char*)&data[2], datasize-2);
1735 std::istringstream is(datastring, std::ios_base::binary);
1737 std::list<std::string> tosend;
1738 u16 numfiles = readU16(is);
1740 infostream<<"Sending "<<numfiles<<" files to "
1741 <<getPlayerName(peer_id)<<std::endl;
1742 verbosestream<<"TOSERVER_REQUEST_MEDIA: "<<std::endl;
1744 for(int i = 0; i < numfiles; i++) {
1745 std::string name = deSerializeString(is);
1746 tosend.push_back(name);
1747 verbosestream<<"TOSERVER_REQUEST_MEDIA: requested file "
1751 sendRequestedMedia(peer_id, tosend);
1754 else if(command == TOSERVER_RECEIVED_MEDIA) {
1757 else if(command == TOSERVER_CLIENT_READY) {
1758 // clients <= protocol version 22 did not send ready message,
1759 // they're already initialized
1760 if (peer_proto_ver <= 22) {
1761 infostream << "Client sent message not expected by a "
1762 << "client using protocol version <= 22,"
1763 << "disconnecing peer_id: " << peer_id << std::endl;
1764 m_con.DisconnectPeer(peer_id);
1768 PlayerSAO* playersao = StageTwoClientInit(peer_id);
1770 if (playersao == NULL) {
1772 << "TOSERVER_CLIENT_READY stage 2 client init failed for peer "
1773 << peer_id << std::endl;
1781 m_clients.setClientVersion(
1783 data[2], data[3], data[4],
1784 std::string((char*) &data[8],(u16) data[6]));
1786 m_clients.event(peer_id, SetClientReady);
1787 m_script->on_joinplayer(playersao);
1790 else if(command == TOSERVER_GOTBLOCKS)
1803 u16 count = data[2];
1804 for(u16 i=0; i<count; i++)
1806 if((s16)datasize < 2+1+(i+1)*6)
1807 throw con::InvalidIncomingDataException
1808 ("GOTBLOCKS length is too short");
1809 v3s16 p = readV3S16(&data[2+1+i*6]);
1810 /*infostream<<"Server: GOTBLOCKS ("
1811 <<p.X<<","<<p.Y<<","<<p.Z<<")"<<std::endl;*/
1812 RemoteClient *client = getClient(peer_id);
1813 client->GotBlock(p);
1818 if (m_clients.getClientState(peer_id) < Active)
1820 if (command == TOSERVER_PLAYERPOS) return;
1822 errorstream<<"Got packet command: " << command << " for peer id "
1823 << peer_id << " but client isn't active yet. Dropping packet "
1828 Player *player = m_env->getPlayer(peer_id);
1830 errorstream<<"Server::ProcessData(): Cancelling: "
1831 "No player for peer_id="<<peer_id
1836 PlayerSAO *playersao = player->getPlayerSAO();
1837 if(playersao == NULL){
1838 errorstream<<"Server::ProcessData(): Cancelling: "
1839 "No player object for peer_id="<<peer_id
1844 if(command == TOSERVER_PLAYERPOS)
1846 if(datasize < 2+12+12+4+4)
1850 v3s32 ps = readV3S32(&data[start+2]);
1851 v3s32 ss = readV3S32(&data[start+2+12]);
1852 f32 pitch = (f32)readS32(&data[2+12+12]) / 100.0;
1853 f32 yaw = (f32)readS32(&data[2+12+12+4]) / 100.0;
1855 if(datasize >= 2+12+12+4+4+4)
1856 keyPressed = (u32)readU32(&data[2+12+12+4+4]);
1857 v3f position((f32)ps.X/100., (f32)ps.Y/100., (f32)ps.Z/100.);
1858 v3f speed((f32)ss.X/100., (f32)ss.Y/100., (f32)ss.Z/100.);
1859 pitch = wrapDegrees(pitch);
1860 yaw = wrapDegrees(yaw);
1862 player->setPosition(position);
1863 player->setSpeed(speed);
1864 player->setPitch(pitch);
1865 player->setYaw(yaw);
1866 player->keyPressed=keyPressed;
1867 player->control.up = (bool)(keyPressed&1);
1868 player->control.down = (bool)(keyPressed&2);
1869 player->control.left = (bool)(keyPressed&4);
1870 player->control.right = (bool)(keyPressed&8);
1871 player->control.jump = (bool)(keyPressed&16);
1872 player->control.aux1 = (bool)(keyPressed&32);
1873 player->control.sneak = (bool)(keyPressed&64);
1874 player->control.LMB = (bool)(keyPressed&128);
1875 player->control.RMB = (bool)(keyPressed&256);
1877 bool cheated = playersao->checkMovementCheat();
1880 m_script->on_cheat(playersao, "moved_too_fast");
1883 /*infostream<<"Server::ProcessData(): Moved player "<<peer_id<<" to "
1884 <<"("<<position.X<<","<<position.Y<<","<<position.Z<<")"
1885 <<" pitch="<<pitch<<" yaw="<<yaw<<std::endl;*/
1887 else if(command == TOSERVER_DELETEDBLOCKS)
1900 u16 count = data[2];
1901 for(u16 i=0; i<count; i++)
1903 if((s16)datasize < 2+1+(i+1)*6)
1904 throw con::InvalidIncomingDataException
1905 ("DELETEDBLOCKS length is too short");
1906 v3s16 p = readV3S16(&data[2+1+i*6]);
1907 /*infostream<<"Server: DELETEDBLOCKS ("
1908 <<p.X<<","<<p.Y<<","<<p.Z<<")"<<std::endl;*/
1909 RemoteClient *client = getClient(peer_id);
1910 client->SetBlockNotSent(p);
1913 else if(command == TOSERVER_CLICK_OBJECT)
1915 infostream<<"Server: CLICK_OBJECT not supported anymore"<<std::endl;
1918 else if(command == TOSERVER_CLICK_ACTIVEOBJECT)
1920 infostream<<"Server: CLICK_ACTIVEOBJECT not supported anymore"<<std::endl;
1923 else if(command == TOSERVER_GROUND_ACTION)
1925 infostream<<"Server: GROUND_ACTION not supported anymore"<<std::endl;
1929 else if(command == TOSERVER_RELEASE)
1931 infostream<<"Server: RELEASE not supported anymore"<<std::endl;
1934 else if(command == TOSERVER_SIGNTEXT)
1936 infostream<<"Server: SIGNTEXT not supported anymore"
1940 else if(command == TOSERVER_SIGNNODETEXT)
1942 infostream<<"Server: SIGNNODETEXT not supported anymore"
1946 else if(command == TOSERVER_INVENTORY_ACTION)
1948 // Strip command and create a stream
1949 std::string datastring((char*)&data[2], datasize-2);
1950 verbosestream<<"TOSERVER_INVENTORY_ACTION: data="<<datastring<<std::endl;
1951 std::istringstream is(datastring, std::ios_base::binary);
1953 InventoryAction *a = InventoryAction::deSerialize(is);
1956 infostream<<"TOSERVER_INVENTORY_ACTION: "
1957 <<"InventoryAction::deSerialize() returned NULL"
1962 // If something goes wrong, this player is to blame
1963 RollbackScopeActor rollback_scope(m_rollback,
1964 std::string("player:")+player->getName());
1967 Note: Always set inventory not sent, to repair cases
1968 where the client made a bad prediction.
1972 Handle restrictions and special cases of the move action
1974 if(a->getType() == IACTION_MOVE)
1976 IMoveAction *ma = (IMoveAction*)a;
1978 ma->from_inv.applyCurrentPlayer(player->getName());
1979 ma->to_inv.applyCurrentPlayer(player->getName());
1981 setInventoryModified(ma->from_inv);
1982 setInventoryModified(ma->to_inv);
1984 bool from_inv_is_current_player =
1985 (ma->from_inv.type == InventoryLocation::PLAYER) &&
1986 (ma->from_inv.name == player->getName());
1988 bool to_inv_is_current_player =
1989 (ma->to_inv.type == InventoryLocation::PLAYER) &&
1990 (ma->to_inv.name == player->getName());
1993 Disable moving items out of craftpreview
1995 if(ma->from_list == "craftpreview")
1997 infostream<<"Ignoring IMoveAction from "
1998 <<(ma->from_inv.dump())<<":"<<ma->from_list
1999 <<" to "<<(ma->to_inv.dump())<<":"<<ma->to_list
2000 <<" because src is "<<ma->from_list<<std::endl;
2006 Disable moving items into craftresult and craftpreview
2008 if(ma->to_list == "craftpreview" || ma->to_list == "craftresult")
2010 infostream<<"Ignoring IMoveAction from "
2011 <<(ma->from_inv.dump())<<":"<<ma->from_list
2012 <<" to "<<(ma->to_inv.dump())<<":"<<ma->to_list
2013 <<" because dst is "<<ma->to_list<<std::endl;
2018 // Disallow moving items in elsewhere than player's inventory
2019 // if not allowed to interact
2020 if(!checkPriv(player->getName(), "interact") &&
2021 (!from_inv_is_current_player ||
2022 !to_inv_is_current_player))
2024 infostream<<"Cannot move outside of player's inventory: "
2025 <<"No interact privilege"<<std::endl;
2031 Handle restrictions and special cases of the drop action
2033 else if(a->getType() == IACTION_DROP)
2035 IDropAction *da = (IDropAction*)a;
2037 da->from_inv.applyCurrentPlayer(player->getName());
2039 setInventoryModified(da->from_inv);
2042 Disable dropping items out of craftpreview
2044 if(da->from_list == "craftpreview")
2046 infostream<<"Ignoring IDropAction from "
2047 <<(da->from_inv.dump())<<":"<<da->from_list
2048 <<" because src is "<<da->from_list<<std::endl;
2053 // Disallow dropping items if not allowed to interact
2054 if(!checkPriv(player->getName(), "interact"))
2061 Handle restrictions and special cases of the craft action
2063 else if(a->getType() == IACTION_CRAFT)
2065 ICraftAction *ca = (ICraftAction*)a;
2067 ca->craft_inv.applyCurrentPlayer(player->getName());
2069 setInventoryModified(ca->craft_inv);
2071 //bool craft_inv_is_current_player =
2072 // (ca->craft_inv.type == InventoryLocation::PLAYER) &&
2073 // (ca->craft_inv.name == player->getName());
2075 // Disallow crafting if not allowed to interact
2076 if(!checkPriv(player->getName(), "interact"))
2078 infostream<<"Cannot craft: "
2079 <<"No interact privilege"<<std::endl;
2086 a->apply(this, playersao, this);
2090 else if(command == TOSERVER_CHAT_MESSAGE)
2098 std::string datastring((char*)&data[2], datasize-2);
2099 std::istringstream is(datastring, std::ios_base::binary);
2102 is.read((char*)buf, 2);
2103 u16 len = readU16(buf);
2105 std::wstring message;
2106 for(u16 i=0; i<len; i++)
2108 is.read((char*)buf, 2);
2109 message += (wchar_t)readU16(buf);
2112 // If something goes wrong, this player is to blame
2113 RollbackScopeActor rollback_scope(m_rollback,
2114 std::string("player:")+player->getName());
2116 // Get player name of this client
2117 std::wstring name = narrow_to_wide(player->getName());
2120 bool ate = m_script->on_chat_message(player->getName(),
2121 wide_to_narrow(message));
2122 // If script ate the message, don't proceed
2126 // Line to send to players
2128 // Whether to send to the player that sent the line
2129 bool send_to_sender_only = false;
2131 // Commands are implemented in Lua, so only catch invalid
2132 // commands that were not "eaten" and send an error back
2133 if(message[0] == L'/')
2135 message = message.substr(1);
2136 send_to_sender_only = true;
2137 if(message.length() == 0)
2138 line += L"-!- Empty command";
2140 line += L"-!- Invalid command: " + str_split(message, L' ')[0];
2144 if(checkPriv(player->getName(), "shout")){
2150 line += L"-!- You don't have permission to shout.";
2151 send_to_sender_only = true;
2158 Send the message to sender
2160 if (send_to_sender_only)
2162 SendChatMessage(peer_id, line);
2165 Send the message to others
2169 actionstream<<"CHAT: "<<wide_to_narrow(line)<<std::endl;
2171 std::list<u16> clients = m_clients.getClientIDs();
2173 for(std::list<u16>::iterator
2174 i = clients.begin();
2175 i != clients.end(); ++i)
2178 SendChatMessage(*i, line);
2183 else if(command == TOSERVER_DAMAGE)
2185 std::string datastring((char*)&data[2], datasize-2);
2186 std::istringstream is(datastring, std::ios_base::binary);
2187 u8 damage = readU8(is);
2189 if(g_settings->getBool("enable_damage"))
2191 actionstream<<player->getName()<<" damaged by "
2192 <<(int)damage<<" hp at "<<PP(player->getPosition()/BS)
2195 playersao->setHP(playersao->getHP() - damage);
2197 if(playersao->getHP() == 0 && playersao->m_hp_not_sent)
2200 if(playersao->m_hp_not_sent)
2201 SendPlayerHP(peer_id);
2204 else if(command == TOSERVER_BREATH)
2206 std::string datastring((char*)&data[2], datasize-2);
2207 std::istringstream is(datastring, std::ios_base::binary);
2208 u16 breath = readU16(is);
2209 playersao->setBreath(breath);
2210 m_script->player_event(playersao,"breath_changed");
2212 else if(command == TOSERVER_PASSWORD)
2215 [0] u16 TOSERVER_PASSWORD
2216 [2] u8[28] old password
2217 [30] u8[28] new password
2220 if(datasize != 2+PASSWORD_SIZE*2)
2222 /*char password[PASSWORD_SIZE];
2223 for(u32 i=0; i<PASSWORD_SIZE-1; i++)
2224 password[i] = data[2+i];
2225 password[PASSWORD_SIZE-1] = 0;*/
2227 for(u32 i=0; i<PASSWORD_SIZE-1; i++)
2235 for(u32 i=0; i<PASSWORD_SIZE-1; i++)
2237 char c = data[2+PASSWORD_SIZE+i];
2243 if(!base64_is_valid(newpwd)){
2244 infostream<<"Server: "<<player->getName()<<" supplied invalid password hash"<<std::endl;
2245 // Wrong old password supplied!!
2246 SendChatMessage(peer_id, L"Invalid new password hash supplied. Password NOT changed.");
2250 infostream<<"Server: Client requests a password change from "
2251 <<"'"<<oldpwd<<"' to '"<<newpwd<<"'"<<std::endl;
2253 std::string playername = player->getName();
2255 std::string checkpwd;
2256 m_script->getAuth(playername, &checkpwd, NULL);
2258 if(oldpwd != checkpwd)
2260 infostream<<"Server: invalid old password"<<std::endl;
2261 // Wrong old password supplied!!
2262 SendChatMessage(peer_id, L"Invalid old password supplied. Password NOT changed.");
2266 bool success = m_script->setPassword(playername, newpwd);
2268 actionstream<<player->getName()<<" changes password"<<std::endl;
2269 SendChatMessage(peer_id, L"Password change successful.");
2271 actionstream<<player->getName()<<" tries to change password but "
2272 <<"it fails"<<std::endl;
2273 SendChatMessage(peer_id, L"Password change failed or inavailable.");
2276 else if(command == TOSERVER_PLAYERITEM)
2281 u16 item = readU16(&data[2]);
2282 playersao->setWieldIndex(item);
2284 else if(command == TOSERVER_RESPAWN)
2286 if(player->hp != 0 || !g_settings->getBool("enable_damage"))
2289 RespawnPlayer(peer_id);
2291 actionstream<<player->getName()<<" respawns at "
2292 <<PP(player->getPosition()/BS)<<std::endl;
2294 // ActiveObject is added to environment in AsyncRunStep after
2295 // the previous addition has been succesfully removed
2297 else if(command == TOSERVER_INTERACT)
2299 std::string datastring((char*)&data[2], datasize-2);
2300 std::istringstream is(datastring, std::ios_base::binary);
2306 [5] u32 length of the next item
2307 [9] serialized PointedThing
2309 0: start digging (from undersurface) or use
2310 1: stop digging (all parameters ignored)
2311 2: digging completed
2312 3: place block or item (to abovesurface)
2315 u8 action = readU8(is);
2316 u16 item_i = readU16(is);
2317 std::istringstream tmp_is(deSerializeLongString(is), std::ios::binary);
2318 PointedThing pointed;
2319 pointed.deSerialize(tmp_is);
2321 verbosestream<<"TOSERVER_INTERACT: action="<<(int)action<<", item="
2322 <<item_i<<", pointed="<<pointed.dump()<<std::endl;
2326 verbosestream<<"TOSERVER_INTERACT: "<<player->getName()
2327 <<" tried to interact, but is dead!"<<std::endl;
2331 v3f player_pos = playersao->getLastGoodPosition();
2333 // Update wielded item
2334 playersao->setWieldIndex(item_i);
2336 // Get pointed to node (undefined if not POINTEDTYPE_NODE)
2337 v3s16 p_under = pointed.node_undersurface;
2338 v3s16 p_above = pointed.node_abovesurface;
2340 // Get pointed to object (NULL if not POINTEDTYPE_OBJECT)
2341 ServerActiveObject *pointed_object = NULL;
2342 if(pointed.type == POINTEDTHING_OBJECT)
2344 pointed_object = m_env->getActiveObject(pointed.object_id);
2345 if(pointed_object == NULL)
2347 verbosestream<<"TOSERVER_INTERACT: "
2348 "pointed object is NULL"<<std::endl;
2354 v3f pointed_pos_under = player_pos;
2355 v3f pointed_pos_above = player_pos;
2356 if(pointed.type == POINTEDTHING_NODE)
2358 pointed_pos_under = intToFloat(p_under, BS);
2359 pointed_pos_above = intToFloat(p_above, BS);
2361 else if(pointed.type == POINTEDTHING_OBJECT)
2363 pointed_pos_under = pointed_object->getBasePosition();
2364 pointed_pos_above = pointed_pos_under;
2368 Check that target is reasonably close
2369 (only when digging or placing things)
2371 if(action == 0 || action == 2 || action == 3)
2373 float d = player_pos.getDistanceFrom(pointed_pos_under);
2374 float max_d = BS * 14; // Just some large enough value
2376 actionstream<<"Player "<<player->getName()
2377 <<" tried to access "<<pointed.dump()
2379 <<"d="<<d<<", max_d="<<max_d
2380 <<". ignoring."<<std::endl;
2381 // Re-send block to revert change on client-side
2382 RemoteClient *client = getClient(peer_id);
2383 v3s16 blockpos = getNodeBlockPos(floatToInt(pointed_pos_under, BS));
2384 client->SetBlockNotSent(blockpos);
2386 m_script->on_cheat(playersao, "interacted_too_far");
2393 Make sure the player is allowed to do it
2395 if(!checkPriv(player->getName(), "interact"))
2397 actionstream<<player->getName()<<" attempted to interact with "
2398 <<pointed.dump()<<" without 'interact' privilege"
2400 // Re-send block to revert change on client-side
2401 RemoteClient *client = getClient(peer_id);
2402 // Digging completed -> under
2404 v3s16 blockpos = getNodeBlockPos(floatToInt(pointed_pos_under, BS));
2405 client->SetBlockNotSent(blockpos);
2407 // Placement -> above
2409 v3s16 blockpos = getNodeBlockPos(floatToInt(pointed_pos_above, BS));
2410 client->SetBlockNotSent(blockpos);
2416 If something goes wrong, this player is to blame
2418 RollbackScopeActor rollback_scope(m_rollback,
2419 std::string("player:")+player->getName());
2422 0: start digging or punch object
2426 if(pointed.type == POINTEDTHING_NODE)
2429 NOTE: This can be used in the future to check if
2430 somebody is cheating, by checking the timing.
2432 MapNode n(CONTENT_IGNORE);
2435 n = m_env->getMap().getNode(p_under);
2437 catch(InvalidPositionException &e)
2439 infostream<<"Server: Not punching: Node not found."
2440 <<" Adding block to emerge queue."
2442 m_emerge->enqueueBlockEmerge(peer_id, getNodeBlockPos(p_above), false);
2444 if(n.getContent() != CONTENT_IGNORE)
2445 m_script->node_on_punch(p_under, n, playersao, pointed);
2447 playersao->noCheatDigStart(p_under);
2449 else if(pointed.type == POINTEDTHING_OBJECT)
2451 // Skip if object has been removed
2452 if(pointed_object->m_removed)
2455 actionstream<<player->getName()<<" punches object "
2456 <<pointed.object_id<<": "
2457 <<pointed_object->getDescription()<<std::endl;
2459 ItemStack punchitem = playersao->getWieldedItem();
2460 ToolCapabilities toolcap =
2461 punchitem.getToolCapabilities(m_itemdef);
2462 v3f dir = (pointed_object->getBasePosition() -
2463 (player->getPosition() + player->getEyeOffset())
2465 float time_from_last_punch =
2466 playersao->resetTimeFromLastPunch();
2467 pointed_object->punch(dir, &toolcap, playersao,
2468 time_from_last_punch);
2476 else if(action == 1)
2481 2: Digging completed
2483 else if(action == 2)
2485 // Only digging of nodes
2486 if(pointed.type == POINTEDTHING_NODE)
2488 MapNode n(CONTENT_IGNORE);
2491 n = m_env->getMap().getNode(p_under);
2493 catch(InvalidPositionException &e)
2495 infostream<<"Server: Not finishing digging: Node not found."
2496 <<" Adding block to emerge queue."
2498 m_emerge->enqueueBlockEmerge(peer_id, getNodeBlockPos(p_above), false);
2501 /* Cheat prevention */
2502 bool is_valid_dig = true;
2503 if(!isSingleplayer() && !g_settings->getBool("disable_anticheat"))
2505 v3s16 nocheat_p = playersao->getNoCheatDigPos();
2506 float nocheat_t = playersao->getNoCheatDigTime();
2507 playersao->noCheatDigEnd();
2508 // If player didn't start digging this, ignore dig
2509 if(nocheat_p != p_under){
2510 infostream<<"Server: NoCheat: "<<player->getName()
2511 <<" started digging "
2512 <<PP(nocheat_p)<<" and completed digging "
2513 <<PP(p_under)<<"; not digging."<<std::endl;
2514 is_valid_dig = false;
2516 m_script->on_cheat(playersao, "finished_unknown_dig");
2518 // Get player's wielded item
2519 ItemStack playeritem;
2520 InventoryList *mlist = playersao->getInventory()->getList("main");
2522 playeritem = mlist->getItem(playersao->getWieldIndex());
2523 ToolCapabilities playeritem_toolcap =
2524 playeritem.getToolCapabilities(m_itemdef);
2525 // Get diggability and expected digging time
2526 DigParams params = getDigParams(m_nodedef->get(n).groups,
2527 &playeritem_toolcap);
2528 // If can't dig, try hand
2529 if(!params.diggable){
2530 const ItemDefinition &hand = m_itemdef->get("");
2531 const ToolCapabilities *tp = hand.tool_capabilities;
2533 params = getDigParams(m_nodedef->get(n).groups, tp);
2535 // If can't dig, ignore dig
2536 if(!params.diggable){
2537 infostream<<"Server: NoCheat: "<<player->getName()
2538 <<" completed digging "<<PP(p_under)
2539 <<", which is not diggable with tool. not digging."
2541 is_valid_dig = false;
2543 m_script->on_cheat(playersao, "dug_unbreakable");
2545 // Check digging time
2546 // If already invalidated, we don't have to
2548 // Well not our problem then
2550 // Clean and long dig
2551 else if(params.time > 2.0 && nocheat_t * 1.2 > params.time){
2552 // All is good, but grab time from pool; don't care if
2553 // it's actually available
2554 playersao->getDigPool().grab(params.time);
2556 // Short or laggy dig
2557 // Try getting the time from pool
2558 else if(playersao->getDigPool().grab(params.time)){
2563 infostream<<"Server: NoCheat: "<<player->getName()
2564 <<" completed digging "<<PP(p_under)
2565 <<"too fast; not digging."<<std::endl;
2566 is_valid_dig = false;
2568 m_script->on_cheat(playersao, "dug_too_fast");
2572 /* Actually dig node */
2574 if(is_valid_dig && n.getContent() != CONTENT_IGNORE)
2575 m_script->node_on_dig(p_under, n, playersao);
2577 // Send unusual result (that is, node not being removed)
2578 if(m_env->getMap().getNodeNoEx(p_under).getContent() != CONTENT_AIR)
2580 // Re-send block to revert change on client-side
2581 RemoteClient *client = getClient(peer_id);
2582 v3s16 blockpos = getNodeBlockPos(floatToInt(pointed_pos_under, BS));
2583 client->SetBlockNotSent(blockpos);
2589 3: place block or right-click object
2591 else if(action == 3)
2593 ItemStack item = playersao->getWieldedItem();
2595 // Reset build time counter
2596 if(pointed.type == POINTEDTHING_NODE &&
2597 item.getDefinition(m_itemdef).type == ITEM_NODE)
2598 getClient(peer_id)->m_time_from_building = 0.0;
2600 if(pointed.type == POINTEDTHING_OBJECT)
2602 // Right click object
2604 // Skip if object has been removed
2605 if(pointed_object->m_removed)
2608 actionstream<<player->getName()<<" right-clicks object "
2609 <<pointed.object_id<<": "
2610 <<pointed_object->getDescription()<<std::endl;
2613 pointed_object->rightClick(playersao);
2615 else if(m_script->item_OnPlace(
2616 item, playersao, pointed))
2618 // Placement was handled in lua
2620 // Apply returned ItemStack
2621 playersao->setWieldedItem(item);
2624 // If item has node placement prediction, always send the
2625 // blocks to make sure the client knows what exactly happened
2626 if(item.getDefinition(m_itemdef).node_placement_prediction != ""){
2627 RemoteClient *client = getClient(peer_id);
2628 v3s16 blockpos = getNodeBlockPos(floatToInt(pointed_pos_above, BS));
2629 client->SetBlockNotSent(blockpos);
2630 v3s16 blockpos2 = getNodeBlockPos(floatToInt(pointed_pos_under, BS));
2631 if(blockpos2 != blockpos){
2632 client->SetBlockNotSent(blockpos2);
2640 else if(action == 4)
2642 ItemStack item = playersao->getWieldedItem();
2644 actionstream<<player->getName()<<" uses "<<item.name
2645 <<", pointing at "<<pointed.dump()<<std::endl;
2647 if(m_script->item_OnUse(
2648 item, playersao, pointed))
2650 // Apply returned ItemStack
2651 playersao->setWieldedItem(item);
2658 Catch invalid actions
2662 infostream<<"WARNING: Server: Invalid action "
2663 <<action<<std::endl;
2666 else if(command == TOSERVER_REMOVED_SOUNDS)
2668 std::string datastring((char*)&data[2], datasize-2);
2669 std::istringstream is(datastring, std::ios_base::binary);
2671 int num = readU16(is);
2672 for(int k=0; k<num; k++){
2673 s32 id = readS32(is);
2674 std::map<s32, ServerPlayingSound>::iterator i =
2675 m_playing_sounds.find(id);
2676 if(i == m_playing_sounds.end())
2678 ServerPlayingSound &psound = i->second;
2679 psound.clients.erase(peer_id);
2680 if(psound.clients.size() == 0)
2681 m_playing_sounds.erase(i++);
2684 else if(command == TOSERVER_NODEMETA_FIELDS)
2686 std::string datastring((char*)&data[2], datasize-2);
2687 std::istringstream is(datastring, std::ios_base::binary);
2689 v3s16 p = readV3S16(is);
2690 std::string formname = deSerializeString(is);
2691 int num = readU16(is);
2692 std::map<std::string, std::string> fields;
2693 for(int k=0; k<num; k++){
2694 std::string fieldname = deSerializeString(is);
2695 std::string fieldvalue = deSerializeLongString(is);
2696 fields[fieldname] = fieldvalue;
2699 // If something goes wrong, this player is to blame
2700 RollbackScopeActor rollback_scope(m_rollback,
2701 std::string("player:")+player->getName());
2703 // Check the target node for rollback data; leave others unnoticed
2704 RollbackNode rn_old(&m_env->getMap(), p, this);
2706 m_script->node_on_receive_fields(p, formname, fields,playersao);
2708 // Report rollback data
2709 RollbackNode rn_new(&m_env->getMap(), p, this);
2710 if(rollback() && rn_new != rn_old){
2711 RollbackAction action;
2712 action.setSetNode(p, rn_old, rn_new);
2713 rollback()->reportAction(action);
2716 else if(command == TOSERVER_INVENTORY_FIELDS)
2718 std::string datastring((char*)&data[2], datasize-2);
2719 std::istringstream is(datastring, std::ios_base::binary);
2721 std::string formname = deSerializeString(is);
2722 int num = readU16(is);
2723 std::map<std::string, std::string> fields;
2724 for(int k=0; k<num; k++){
2725 std::string fieldname = deSerializeString(is);
2726 std::string fieldvalue = deSerializeLongString(is);
2727 fields[fieldname] = fieldvalue;
2730 m_script->on_playerReceiveFields(playersao, formname, fields);
2734 infostream<<"Server::ProcessData(): Ignoring "
2735 "unknown command "<<command<<std::endl;
2739 catch(SendFailedException &e)
2741 errorstream<<"Server::ProcessData(): SendFailedException: "
2747 void Server::setTimeOfDay(u32 time)
2749 m_env->setTimeOfDay(time);
2750 m_time_of_day_send_timer = 0;
2753 void Server::onMapEditEvent(MapEditEvent *event)
2755 //infostream<<"Server::onMapEditEvent()"<<std::endl;
2756 if(m_ignore_map_edit_events)
2758 if(m_ignore_map_edit_events_area.contains(event->getArea()))
2760 MapEditEvent *e = event->clone();
2761 m_unsent_map_edit_queue.push_back(e);
2764 Inventory* Server::getInventory(const InventoryLocation &loc)
2767 case InventoryLocation::UNDEFINED:
2770 case InventoryLocation::CURRENT_PLAYER:
2773 case InventoryLocation::PLAYER:
2775 Player *player = m_env->getPlayer(loc.name.c_str());
2778 PlayerSAO *playersao = player->getPlayerSAO();
2781 return playersao->getInventory();
2784 case InventoryLocation::NODEMETA:
2786 NodeMetadata *meta = m_env->getMap().getNodeMetadata(loc.p);
2789 return meta->getInventory();
2792 case InventoryLocation::DETACHED:
2794 if(m_detached_inventories.count(loc.name) == 0)
2796 return m_detached_inventories[loc.name];
2804 void Server::setInventoryModified(const InventoryLocation &loc)
2807 case InventoryLocation::UNDEFINED:
2810 case InventoryLocation::PLAYER:
2812 Player *player = m_env->getPlayer(loc.name.c_str());
2815 PlayerSAO *playersao = player->getPlayerSAO();
2818 playersao->m_inventory_not_sent = true;
2819 playersao->m_wielded_item_not_sent = true;
2822 case InventoryLocation::NODEMETA:
2824 v3s16 blockpos = getNodeBlockPos(loc.p);
2826 MapBlock *block = m_env->getMap().getBlockNoCreateNoEx(blockpos);
2828 block->raiseModified(MOD_STATE_WRITE_NEEDED);
2830 setBlockNotSent(blockpos);
2833 case InventoryLocation::DETACHED:
2835 sendDetachedInventory(loc.name,PEER_ID_INEXISTENT);
2843 void Server::SetBlocksNotSent(std::map<v3s16, MapBlock *>& block)
2845 std::list<u16> clients = m_clients.getClientIDs();
2847 // Set the modified blocks unsent for all the clients
2848 for (std::list<u16>::iterator
2849 i = clients.begin();
2850 i != clients.end(); ++i) {
2851 RemoteClient *client = m_clients.lockedGetClientNoEx(*i);
2853 client->SetBlocksNotSent(block);
2858 void Server::peerAdded(con::Peer *peer)
2860 DSTACK(__FUNCTION_NAME);
2861 verbosestream<<"Server::peerAdded(): peer->id="
2862 <<peer->id<<std::endl;
2865 c.type = con::PEER_ADDED;
2866 c.peer_id = peer->id;
2868 m_peer_change_queue.push_back(c);
2871 void Server::deletingPeer(con::Peer *peer, bool timeout)
2873 DSTACK(__FUNCTION_NAME);
2874 verbosestream<<"Server::deletingPeer(): peer->id="
2875 <<peer->id<<", timeout="<<timeout<<std::endl;
2877 m_clients.event(peer->id,Disconnect);
2879 c.type = con::PEER_REMOVED;
2880 c.peer_id = peer->id;
2881 c.timeout = timeout;
2882 m_peer_change_queue.push_back(c);
2885 bool Server::getClientConInfo(u16 peer_id, con::rtt_stat_type type, float* retval)
2887 *retval = m_con.getPeerStat(peer_id,type);
2888 if (*retval == -1) return false;
2892 bool Server::getClientInfo(
2901 std::string* vers_string
2904 *state = m_clients.getClientState(peer_id);
2906 RemoteClient* client = m_clients.lockedGetClientNoEx(peer_id,Invalid);
2908 if (client == NULL) {
2913 *uptime = client->uptime();
2914 *ser_vers = client->serialization_version;
2915 *prot_vers = client->net_proto_version;
2917 *major = client->getMajor();
2918 *minor = client->getMinor();
2919 *patch = client->getPatch();
2920 *vers_string = client->getPatch();
2927 void Server::handlePeerChanges()
2929 while(m_peer_change_queue.size() > 0)
2931 con::PeerChange c = m_peer_change_queue.pop_front();
2933 verbosestream<<"Server: Handling peer change: "
2934 <<"id="<<c.peer_id<<", timeout="<<c.timeout
2939 case con::PEER_ADDED:
2940 m_clients.CreateClient(c.peer_id);
2943 case con::PEER_REMOVED:
2944 DeleteClient(c.peer_id, c.timeout?CDR_TIMEOUT:CDR_LEAVE);
2948 assert("Invalid peer change event received!" == 0);
2954 void Server::SendMovement(u16 peer_id)
2956 DSTACK(__FUNCTION_NAME);
2957 std::ostringstream os(std::ios_base::binary);
2959 writeU16(os, TOCLIENT_MOVEMENT);
2960 writeF1000(os, g_settings->getFloat("movement_acceleration_default"));
2961 writeF1000(os, g_settings->getFloat("movement_acceleration_air"));
2962 writeF1000(os, g_settings->getFloat("movement_acceleration_fast"));
2963 writeF1000(os, g_settings->getFloat("movement_speed_walk"));
2964 writeF1000(os, g_settings->getFloat("movement_speed_crouch"));
2965 writeF1000(os, g_settings->getFloat("movement_speed_fast"));
2966 writeF1000(os, g_settings->getFloat("movement_speed_climb"));
2967 writeF1000(os, g_settings->getFloat("movement_speed_jump"));
2968 writeF1000(os, g_settings->getFloat("movement_liquid_fluidity"));
2969 writeF1000(os, g_settings->getFloat("movement_liquid_fluidity_smooth"));
2970 writeF1000(os, g_settings->getFloat("movement_liquid_sink"));
2971 writeF1000(os, g_settings->getFloat("movement_gravity"));
2974 std::string s = os.str();
2975 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
2977 m_clients.send(peer_id, 0, data, true);
2980 void Server::SendHP(u16 peer_id, u8 hp)
2982 DSTACK(__FUNCTION_NAME);
2983 std::ostringstream os(std::ios_base::binary);
2985 writeU16(os, TOCLIENT_HP);
2989 std::string s = os.str();
2990 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
2992 m_clients.send(peer_id, 0, data, true);
2995 void Server::SendBreath(u16 peer_id, u16 breath)
2997 DSTACK(__FUNCTION_NAME);
2998 std::ostringstream os(std::ios_base::binary);
3000 writeU16(os, TOCLIENT_BREATH);
3001 writeU16(os, breath);
3004 std::string s = os.str();
3005 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3007 m_clients.send(peer_id, 0, data, true);
3010 void Server::SendAccessDenied(u16 peer_id,const std::wstring &reason)
3012 DSTACK(__FUNCTION_NAME);
3013 std::ostringstream os(std::ios_base::binary);
3015 writeU16(os, TOCLIENT_ACCESS_DENIED);
3016 os<<serializeWideString(reason);
3019 std::string s = os.str();
3020 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3022 m_clients.send(peer_id, 0, data, true);
3025 void Server::SendDeathscreen(u16 peer_id,bool set_camera_point_target,
3026 v3f camera_point_target)
3028 DSTACK(__FUNCTION_NAME);
3029 std::ostringstream os(std::ios_base::binary);
3031 writeU16(os, TOCLIENT_DEATHSCREEN);
3032 writeU8(os, set_camera_point_target);
3033 writeV3F1000(os, camera_point_target);
3036 std::string s = os.str();
3037 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3039 m_clients.send(peer_id, 0, data, true);
3042 void Server::SendItemDef(u16 peer_id,
3043 IItemDefManager *itemdef, u16 protocol_version)
3045 DSTACK(__FUNCTION_NAME);
3046 std::ostringstream os(std::ios_base::binary);
3050 u32 length of the next item
3051 zlib-compressed serialized ItemDefManager
3053 writeU16(os, TOCLIENT_ITEMDEF);
3054 std::ostringstream tmp_os(std::ios::binary);
3055 itemdef->serialize(tmp_os, protocol_version);
3056 std::ostringstream tmp_os2(std::ios::binary);
3057 compressZlib(tmp_os.str(), tmp_os2);
3058 os<<serializeLongString(tmp_os2.str());
3061 std::string s = os.str();
3062 verbosestream<<"Server: Sending item definitions to id("<<peer_id
3063 <<"): size="<<s.size()<<std::endl;
3064 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3066 m_clients.send(peer_id, 0, data, true);
3069 void Server::SendNodeDef(u16 peer_id,
3070 INodeDefManager *nodedef, u16 protocol_version)
3072 DSTACK(__FUNCTION_NAME);
3073 std::ostringstream os(std::ios_base::binary);
3077 u32 length of the next item
3078 zlib-compressed serialized NodeDefManager
3080 writeU16(os, TOCLIENT_NODEDEF);
3081 std::ostringstream tmp_os(std::ios::binary);
3082 nodedef->serialize(tmp_os, protocol_version);
3083 std::ostringstream tmp_os2(std::ios::binary);
3084 compressZlib(tmp_os.str(), tmp_os2);
3085 os<<serializeLongString(tmp_os2.str());
3088 std::string s = os.str();
3089 verbosestream<<"Server: Sending node definitions to id("<<peer_id
3090 <<"): size="<<s.size()<<std::endl;
3091 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3093 m_clients.send(peer_id, 0, data, true);
3097 Non-static send methods
3100 void Server::SendInventory(u16 peer_id)
3102 DSTACK(__FUNCTION_NAME);
3104 PlayerSAO *playersao = getPlayerSAO(peer_id);
3107 playersao->m_inventory_not_sent = false;
3113 std::ostringstream os;
3114 playersao->getInventory()->serialize(os);
3116 std::string s = os.str();
3118 SharedBuffer<u8> data(s.size()+2);
3119 writeU16(&data[0], TOCLIENT_INVENTORY);
3120 memcpy(&data[2], s.c_str(), s.size());
3123 m_clients.send(peer_id, 0, data, true);
3126 void Server::SendChatMessage(u16 peer_id, const std::wstring &message)
3128 DSTACK(__FUNCTION_NAME);
3130 std::ostringstream os(std::ios_base::binary);
3134 writeU16(buf, TOCLIENT_CHAT_MESSAGE);
3135 os.write((char*)buf, 2);
3138 writeU16(buf, message.size());
3139 os.write((char*)buf, 2);
3142 for(u32 i=0; i<message.size(); i++)
3146 os.write((char*)buf, 2);
3150 std::string s = os.str();
3151 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3153 if (peer_id != PEER_ID_INEXISTENT)
3156 m_clients.send(peer_id, 0, data, true);
3160 m_clients.sendToAll(0,data,true);
3164 void Server::SendShowFormspecMessage(u16 peer_id, const std::string &formspec,
3165 const std::string &formname)
3167 DSTACK(__FUNCTION_NAME);
3169 std::ostringstream os(std::ios_base::binary);
3173 writeU16(buf, TOCLIENT_SHOW_FORMSPEC);
3174 os.write((char*)buf, 2);
3175 os<<serializeLongString(formspec);
3176 os<<serializeString(formname);
3179 std::string s = os.str();
3180 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3182 m_clients.send(peer_id, 0, data, true);
3185 // Spawns a particle on peer with peer_id
3186 void Server::SendSpawnParticle(u16 peer_id, v3f pos, v3f velocity, v3f acceleration,
3187 float expirationtime, float size, bool collisiondetection,
3188 bool vertical, std::string texture)
3190 DSTACK(__FUNCTION_NAME);
3192 std::ostringstream os(std::ios_base::binary);
3193 writeU16(os, TOCLIENT_SPAWN_PARTICLE);
3194 writeV3F1000(os, pos);
3195 writeV3F1000(os, velocity);
3196 writeV3F1000(os, acceleration);
3197 writeF1000(os, expirationtime);
3198 writeF1000(os, size);
3199 writeU8(os, collisiondetection);
3200 os<<serializeLongString(texture);
3201 writeU8(os, vertical);
3204 std::string s = os.str();
3205 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3207 if (peer_id != PEER_ID_INEXISTENT)
3210 m_clients.send(peer_id, 0, data, true);
3214 m_clients.sendToAll(0,data,true);
3218 // Adds a ParticleSpawner on peer with peer_id
3219 void Server::SendAddParticleSpawner(u16 peer_id, u16 amount, float spawntime, v3f minpos, v3f maxpos,
3220 v3f minvel, v3f maxvel, v3f minacc, v3f maxacc, float minexptime, float maxexptime,
3221 float minsize, float maxsize, bool collisiondetection, bool vertical, std::string texture, u32 id)
3223 DSTACK(__FUNCTION_NAME);
3225 std::ostringstream os(std::ios_base::binary);
3226 writeU16(os, TOCLIENT_ADD_PARTICLESPAWNER);
3228 writeU16(os, amount);
3229 writeF1000(os, spawntime);
3230 writeV3F1000(os, minpos);
3231 writeV3F1000(os, maxpos);
3232 writeV3F1000(os, minvel);
3233 writeV3F1000(os, maxvel);
3234 writeV3F1000(os, minacc);
3235 writeV3F1000(os, maxacc);
3236 writeF1000(os, minexptime);
3237 writeF1000(os, maxexptime);
3238 writeF1000(os, minsize);
3239 writeF1000(os, maxsize);
3240 writeU8(os, collisiondetection);
3241 os<<serializeLongString(texture);
3243 writeU8(os, vertical);
3246 std::string s = os.str();
3247 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3249 if (peer_id != PEER_ID_INEXISTENT)
3252 m_clients.send(peer_id, 0, data, true);
3255 m_clients.sendToAll(0,data,true);
3259 void Server::SendDeleteParticleSpawner(u16 peer_id, u32 id)
3261 DSTACK(__FUNCTION_NAME);
3263 std::ostringstream os(std::ios_base::binary);
3264 writeU16(os, TOCLIENT_DELETE_PARTICLESPAWNER);
3269 std::string s = os.str();
3270 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3272 if (peer_id != PEER_ID_INEXISTENT) {
3274 m_clients.send(peer_id, 0, data, true);
3277 m_clients.sendToAll(0,data,true);
3282 void Server::SendHUDAdd(u16 peer_id, u32 id, HudElement *form)
3284 std::ostringstream os(std::ios_base::binary);
3287 writeU16(os, TOCLIENT_HUDADD);
3289 writeU8(os, (u8)form->type);
3290 writeV2F1000(os, form->pos);
3291 os << serializeString(form->name);
3292 writeV2F1000(os, form->scale);
3293 os << serializeString(form->text);
3294 writeU32(os, form->number);
3295 writeU32(os, form->item);
3296 writeU32(os, form->dir);
3297 writeV2F1000(os, form->align);
3298 writeV2F1000(os, form->offset);
3299 writeV3F1000(os, form->world_pos);
3300 writeV2S32(os,form->size);
3303 std::string s = os.str();
3304 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3306 m_clients.send(peer_id, 1, data, true);
3309 void Server::SendHUDRemove(u16 peer_id, u32 id)
3311 std::ostringstream os(std::ios_base::binary);
3314 writeU16(os, TOCLIENT_HUDRM);
3318 std::string s = os.str();
3319 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3322 m_clients.send(peer_id, 1, data, true);
3325 void Server::SendHUDChange(u16 peer_id, u32 id, HudElementStat stat, void *value)
3327 std::ostringstream os(std::ios_base::binary);
3330 writeU16(os, TOCLIENT_HUDCHANGE);
3332 writeU8(os, (u8)stat);
3335 case HUD_STAT_SCALE:
3336 case HUD_STAT_ALIGN:
3337 case HUD_STAT_OFFSET:
3338 writeV2F1000(os, *(v2f *)value);
3342 os << serializeString(*(std::string *)value);
3344 case HUD_STAT_WORLD_POS:
3345 writeV3F1000(os, *(v3f *)value);
3348 writeV2S32(os,*(v2s32 *)value);
3350 case HUD_STAT_NUMBER:
3354 writeU32(os, *(u32 *)value);
3359 std::string s = os.str();
3360 SharedBuffer<u8> data((u8 *)s.c_str(), s.size());
3362 m_clients.send(peer_id, 0, data, true);
3365 void Server::SendHUDSetFlags(u16 peer_id, u32 flags, u32 mask)
3367 std::ostringstream os(std::ios_base::binary);
3370 writeU16(os, TOCLIENT_HUD_SET_FLAGS);
3372 //////////////////////////// compatibility code to be removed //////////////
3373 flags &= ~(HUD_FLAG_HEALTHBAR_VISIBLE | HUD_FLAG_BREATHBAR_VISIBLE);
3374 ////////////////////////////////////////////////////////////////////////////
3375 writeU32(os, flags);
3379 std::string s = os.str();
3380 SharedBuffer<u8> data((u8 *)s.c_str(), s.size());
3382 m_clients.send(peer_id, 0, data, true);
3385 void Server::SendHUDSetParam(u16 peer_id, u16 param, const std::string &value)
3387 std::ostringstream os(std::ios_base::binary);
3390 writeU16(os, TOCLIENT_HUD_SET_PARAM);
3391 writeU16(os, param);
3392 os<<serializeString(value);
3395 std::string s = os.str();
3396 SharedBuffer<u8> data((u8 *)s.c_str(), s.size());
3398 m_clients.send(peer_id, 0, data, true);
3401 void Server::SendSetSky(u16 peer_id, const video::SColor &bgcolor,
3402 const std::string &type, const std::vector<std::string> ¶ms)
3404 std::ostringstream os(std::ios_base::binary);
3407 writeU16(os, TOCLIENT_SET_SKY);
3408 writeARGB8(os, bgcolor);
3409 os<<serializeString(type);
3410 writeU16(os, params.size());
3411 for(size_t i=0; i<params.size(); i++)
3412 os<<serializeString(params[i]);
3415 std::string s = os.str();
3416 SharedBuffer<u8> data((u8 *)s.c_str(), s.size());
3418 m_clients.send(peer_id, 0, data, true);
3421 void Server::SendOverrideDayNightRatio(u16 peer_id, bool do_override,
3424 std::ostringstream os(std::ios_base::binary);
3427 writeU16(os, TOCLIENT_OVERRIDE_DAY_NIGHT_RATIO);
3428 writeU8(os, do_override);
3429 writeU16(os, ratio*65535);
3432 std::string s = os.str();
3433 SharedBuffer<u8> data((u8 *)s.c_str(), s.size());
3435 m_clients.send(peer_id, 0, data, true);
3438 void Server::SendTimeOfDay(u16 peer_id, u16 time, f32 time_speed)
3440 DSTACK(__FUNCTION_NAME);
3443 SharedBuffer<u8> data(2+2+4);
3444 writeU16(&data[0], TOCLIENT_TIME_OF_DAY);
3445 writeU16(&data[2], time);
3446 writeF1000(&data[4], time_speed);
3448 if (peer_id == PEER_ID_INEXISTENT) {
3449 m_clients.sendToAll(0,data,true);
3453 m_clients.send(peer_id, 0, data, true);
3457 void Server::SendPlayerHP(u16 peer_id)
3459 DSTACK(__FUNCTION_NAME);
3460 PlayerSAO *playersao = getPlayerSAO(peer_id);
3462 playersao->m_hp_not_sent = false;
3463 SendHP(peer_id, playersao->getHP());
3464 m_script->player_event(playersao,"health_changed");
3466 // Send to other clients
3467 std::string str = gob_cmd_punched(playersao->readDamage(), playersao->getHP());
3468 ActiveObjectMessage aom(playersao->getId(), true, str);
3469 playersao->m_messages_out.push_back(aom);
3472 void Server::SendPlayerBreath(u16 peer_id)
3474 DSTACK(__FUNCTION_NAME);
3475 PlayerSAO *playersao = getPlayerSAO(peer_id);
3477 playersao->m_breath_not_sent = false;
3478 m_script->player_event(playersao,"breath_changed");
3479 SendBreath(peer_id, playersao->getBreath());
3482 void Server::SendMovePlayer(u16 peer_id)
3484 DSTACK(__FUNCTION_NAME);
3485 Player *player = m_env->getPlayer(peer_id);
3488 std::ostringstream os(std::ios_base::binary);
3489 writeU16(os, TOCLIENT_MOVE_PLAYER);
3490 writeV3F1000(os, player->getPosition());
3491 writeF1000(os, player->getPitch());
3492 writeF1000(os, player->getYaw());
3495 v3f pos = player->getPosition();
3496 f32 pitch = player->getPitch();
3497 f32 yaw = player->getYaw();
3498 verbosestream<<"Server: Sending TOCLIENT_MOVE_PLAYER"
3499 <<" pos=("<<pos.X<<","<<pos.Y<<","<<pos.Z<<")"
3506 std::string s = os.str();
3507 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3509 m_clients.send(peer_id, 0, data, true);
3512 void Server::SendLocalPlayerAnimations(u16 peer_id, v2s32 animation_frames[4], f32 animation_speed)
3514 std::ostringstream os(std::ios_base::binary);
3516 writeU16(os, TOCLIENT_LOCAL_PLAYER_ANIMATIONS);
3517 writeV2S32(os, animation_frames[0]);
3518 writeV2S32(os, animation_frames[1]);
3519 writeV2S32(os, animation_frames[2]);
3520 writeV2S32(os, animation_frames[3]);
3521 writeF1000(os, animation_speed);
3524 std::string s = os.str();
3525 SharedBuffer<u8> data((u8 *)s.c_str(), s.size());
3527 m_clients.send(peer_id, 0, data, true);
3530 void Server::SendEyeOffset(u16 peer_id, v3f first, v3f third)
3532 std::ostringstream os(std::ios_base::binary);
3534 writeU16(os, TOCLIENT_EYE_OFFSET);
3535 writeV3F1000(os, first);
3536 writeV3F1000(os, third);
3539 std::string s = os.str();
3540 SharedBuffer<u8> data((u8 *)s.c_str(), s.size());
3542 m_clients.send(peer_id, 0, data, true);
3544 void Server::SendPlayerPrivileges(u16 peer_id)
3546 Player *player = m_env->getPlayer(peer_id);
3548 if(player->peer_id == PEER_ID_INEXISTENT)
3551 std::set<std::string> privs;
3552 m_script->getAuth(player->getName(), NULL, &privs);
3554 std::ostringstream os(std::ios_base::binary);
3555 writeU16(os, TOCLIENT_PRIVILEGES);
3556 writeU16(os, privs.size());
3557 for(std::set<std::string>::const_iterator i = privs.begin();
3558 i != privs.end(); i++){
3559 os<<serializeString(*i);
3563 std::string s = os.str();
3564 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3566 m_clients.send(peer_id, 0, data, true);
3569 void Server::SendPlayerInventoryFormspec(u16 peer_id)
3571 Player *player = m_env->getPlayer(peer_id);
3573 if(player->peer_id == PEER_ID_INEXISTENT)
3576 std::ostringstream os(std::ios_base::binary);
3577 writeU16(os, TOCLIENT_INVENTORY_FORMSPEC);
3578 os<<serializeLongString(player->inventory_formspec);
3581 std::string s = os.str();
3582 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3584 m_clients.send(peer_id, 0, data, true);
3587 s32 Server::playSound(const SimpleSoundSpec &spec,
3588 const ServerSoundParams ¶ms)
3590 // Find out initial position of sound
3591 bool pos_exists = false;
3592 v3f pos = params.getPos(m_env, &pos_exists);
3593 // If position is not found while it should be, cancel sound
3594 if(pos_exists != (params.type != ServerSoundParams::SSP_LOCAL))
3597 // Filter destination clients
3598 std::list<u16> dst_clients;
3599 if(params.to_player != "")
3601 Player *player = m_env->getPlayer(params.to_player.c_str());
3603 infostream<<"Server::playSound: Player \""<<params.to_player
3604 <<"\" not found"<<std::endl;
3607 if(player->peer_id == PEER_ID_INEXISTENT){
3608 infostream<<"Server::playSound: Player \""<<params.to_player
3609 <<"\" not connected"<<std::endl;
3612 dst_clients.push_back(player->peer_id);
3616 std::list<u16> clients = m_clients.getClientIDs();
3618 for(std::list<u16>::iterator
3619 i = clients.begin(); i != clients.end(); ++i)
3621 Player *player = m_env->getPlayer(*i);
3625 if(player->getPosition().getDistanceFrom(pos) >
3626 params.max_hear_distance)
3629 dst_clients.push_back(*i);
3632 if(dst_clients.size() == 0)
3636 s32 id = m_next_sound_id++;
3637 // The sound will exist as a reference in m_playing_sounds
3638 m_playing_sounds[id] = ServerPlayingSound();
3639 ServerPlayingSound &psound = m_playing_sounds[id];
3640 psound.params = params;
3641 for(std::list<u16>::iterator i = dst_clients.begin();
3642 i != dst_clients.end(); i++)
3643 psound.clients.insert(*i);
3645 std::ostringstream os(std::ios_base::binary);
3646 writeU16(os, TOCLIENT_PLAY_SOUND);
3648 os<<serializeString(spec.name);
3649 writeF1000(os, spec.gain * params.gain);
3650 writeU8(os, params.type);
3651 writeV3F1000(os, pos);
3652 writeU16(os, params.object);
3653 writeU8(os, params.loop);
3655 std::string s = os.str();
3656 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3658 for(std::list<u16>::iterator i = dst_clients.begin();
3659 i != dst_clients.end(); i++){
3661 m_clients.send(*i, 0, data, true);
3665 void Server::stopSound(s32 handle)
3667 // Get sound reference
3668 std::map<s32, ServerPlayingSound>::iterator i =
3669 m_playing_sounds.find(handle);
3670 if(i == m_playing_sounds.end())
3672 ServerPlayingSound &psound = i->second;
3674 std::ostringstream os(std::ios_base::binary);
3675 writeU16(os, TOCLIENT_STOP_SOUND);
3676 writeS32(os, handle);
3678 std::string s = os.str();
3679 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3681 for(std::set<u16>::iterator i = psound.clients.begin();
3682 i != psound.clients.end(); i++){
3684 m_clients.send(*i, 0, data, true);
3686 // Remove sound reference
3687 m_playing_sounds.erase(i);
3690 void Server::sendRemoveNode(v3s16 p, u16 ignore_id,
3691 std::list<u16> *far_players, float far_d_nodes)
3693 float maxd = far_d_nodes*BS;
3694 v3f p_f = intToFloat(p, BS);
3698 SharedBuffer<u8> reply(replysize);
3699 writeU16(&reply[0], TOCLIENT_REMOVENODE);
3700 writeS16(&reply[2], p.X);
3701 writeS16(&reply[4], p.Y);
3702 writeS16(&reply[6], p.Z);
3704 std::list<u16> clients = m_clients.getClientIDs();
3705 for(std::list<u16>::iterator
3706 i = clients.begin();
3707 i != clients.end(); ++i)
3712 Player *player = m_env->getPlayer(*i);
3715 // If player is far away, only set modified blocks not sent
3716 v3f player_pos = player->getPosition();
3717 if(player_pos.getDistanceFrom(p_f) > maxd)
3719 far_players->push_back(*i);
3726 m_clients.send(*i, 0, reply, true);
3730 void Server::sendAddNode(v3s16 p, MapNode n, u16 ignore_id,
3731 std::list<u16> *far_players, float far_d_nodes,
3732 bool remove_metadata)
3734 float maxd = far_d_nodes*BS;
3735 v3f p_f = intToFloat(p, BS);
3737 std::list<u16> clients = m_clients.getClientIDs();
3738 for(std::list<u16>::iterator
3739 i = clients.begin();
3740 i != clients.end(); ++i)
3746 Player *player = m_env->getPlayer(*i);
3749 // If player is far away, only set modified blocks not sent
3750 v3f player_pos = player->getPosition();
3751 if(player_pos.getDistanceFrom(p_f) > maxd)
3753 far_players->push_back(*i);
3758 SharedBuffer<u8> reply(0);
3760 RemoteClient* client = m_clients.lockedGetClientNoEx(*i);
3764 u32 replysize = 9 + MapNode::serializedLength(client->serialization_version);
3765 reply = SharedBuffer<u8>(replysize);
3766 writeU16(&reply[0], TOCLIENT_ADDNODE);
3767 writeS16(&reply[2], p.X);
3768 writeS16(&reply[4], p.Y);
3769 writeS16(&reply[6], p.Z);
3770 n.serialize(&reply[8], client->serialization_version);
3771 u32 index = 8 + MapNode::serializedLength(client->serialization_version);
3772 writeU8(&reply[index], remove_metadata ? 0 : 1);
3774 if (!remove_metadata) {
3775 if (client->net_proto_version <= 21) {
3776 // Old clients always clear metadata; fix it
3777 // by sending the full block again.
3778 client->SetBlockNotSent(p);
3785 if (reply.getSize() > 0)
3786 m_clients.send(*i, 0, reply, true);
3790 void Server::setBlockNotSent(v3s16 p)
3792 std::list<u16> clients = m_clients.getClientIDs();
3794 for(std::list<u16>::iterator
3795 i = clients.begin();
3796 i != clients.end(); ++i)
3798 RemoteClient *client = m_clients.lockedGetClientNoEx(*i);
3799 client->SetBlockNotSent(p);
3804 void Server::SendBlockNoLock(u16 peer_id, MapBlock *block, u8 ver, u16 net_proto_version)
3806 DSTACK(__FUNCTION_NAME);
3808 v3s16 p = block->getPos();
3812 bool completely_air = true;
3813 for(s16 z0=0; z0<MAP_BLOCKSIZE; z0++)
3814 for(s16 x0=0; x0<MAP_BLOCKSIZE; x0++)
3815 for(s16 y0=0; y0<MAP_BLOCKSIZE; y0++)
3817 if(block->getNodeNoEx(v3s16(x0,y0,z0)).d != CONTENT_AIR)
3819 completely_air = false;
3820 x0 = y0 = z0 = MAP_BLOCKSIZE; // Break out
3825 infostream<<"Server: Sending block ("<<p.X<<","<<p.Y<<","<<p.Z<<"): ";
3827 infostream<<"[completely air] ";
3828 infostream<<std::endl;
3832 Create a packet with the block in the right format
3835 std::ostringstream os(std::ios_base::binary);
3836 block->serialize(os, ver, false);
3837 block->serializeNetworkSpecific(os, net_proto_version);
3838 std::string s = os.str();
3839 SharedBuffer<u8> blockdata((u8*)s.c_str(), s.size());
3841 u32 replysize = 8 + blockdata.getSize();
3842 SharedBuffer<u8> reply(replysize);
3843 writeU16(&reply[0], TOCLIENT_BLOCKDATA);
3844 writeS16(&reply[2], p.X);
3845 writeS16(&reply[4], p.Y);
3846 writeS16(&reply[6], p.Z);
3847 memcpy(&reply[8], *blockdata, blockdata.getSize());
3849 /*infostream<<"Server: Sending block ("<<p.X<<","<<p.Y<<","<<p.Z<<")"
3850 <<": \tpacket size: "<<replysize<<std::endl;*/
3855 m_clients.send(peer_id, 2, reply, true);
3858 void Server::SendBlocks(float dtime)
3860 DSTACK(__FUNCTION_NAME);
3862 JMutexAutoLock envlock(m_env_mutex);
3863 //TODO check if one big lock could be faster then multiple small ones
3865 ScopeProfiler sp(g_profiler, "Server: sel and send blocks to clients");
3867 std::vector<PrioritySortedBlockTransfer> queue;
3869 s32 total_sending = 0;
3872 ScopeProfiler sp(g_profiler, "Server: selecting blocks for sending");
3874 std::list<u16> clients = m_clients.getClientIDs();
3877 for(std::list<u16>::iterator
3878 i = clients.begin();
3879 i != clients.end(); ++i)
3881 RemoteClient *client = m_clients.lockedGetClientNoEx(*i,Active);
3886 total_sending += client->SendingCount();
3887 client->GetNextBlocks(m_env,m_emerge, dtime, queue);
3893 // Lowest priority number comes first.
3894 // Lowest is most important.
3895 std::sort(queue.begin(), queue.end());
3898 for(u32 i=0; i<queue.size(); i++)
3900 //TODO: Calculate limit dynamically
3901 if(total_sending >= g_settings->getS32
3902 ("max_simultaneous_block_sends_server_total"))
3905 PrioritySortedBlockTransfer q = queue[i];
3907 MapBlock *block = NULL;
3910 block = m_env->getMap().getBlockNoCreate(q.pos);
3912 catch(InvalidPositionException &e)
3917 RemoteClient *client = m_clients.lockedGetClientNoEx(q.peer_id,Active);
3922 SendBlockNoLock(q.peer_id, block, client->serialization_version, client->net_proto_version);
3924 client->SentBlock(q.pos);
3930 void Server::fillMediaCache()
3932 DSTACK(__FUNCTION_NAME);
3934 infostream<<"Server: Calculating media file checksums"<<std::endl;
3936 // Collect all media file paths
3937 std::list<std::string> paths;
3938 for(std::vector<ModSpec>::iterator i = m_mods.begin();
3939 i != m_mods.end(); i++){
3940 const ModSpec &mod = *i;
3941 paths.push_back(mod.path + DIR_DELIM + "textures");
3942 paths.push_back(mod.path + DIR_DELIM + "sounds");
3943 paths.push_back(mod.path + DIR_DELIM + "media");
3944 paths.push_back(mod.path + DIR_DELIM + "models");
3946 paths.push_back(porting::path_user + DIR_DELIM + "textures" + DIR_DELIM + "server");
3948 // Collect media file information from paths into cache
3949 for(std::list<std::string>::iterator i = paths.begin();
3950 i != paths.end(); i++)
3952 std::string mediapath = *i;
3953 std::vector<fs::DirListNode> dirlist = fs::GetDirListing(mediapath);
3954 for(u32 j=0; j<dirlist.size(); j++){
3955 if(dirlist[j].dir) // Ignode dirs
3957 std::string filename = dirlist[j].name;
3958 // If name contains illegal characters, ignore the file
3959 if(!string_allowed(filename, TEXTURENAME_ALLOWED_CHARS)){
3960 infostream<<"Server: ignoring illegal file name: \""
3961 <<filename<<"\""<<std::endl;
3964 // If name is not in a supported format, ignore it
3965 const char *supported_ext[] = {
3966 ".png", ".jpg", ".bmp", ".tga",
3967 ".pcx", ".ppm", ".psd", ".wal", ".rgb",
3969 ".x", ".b3d", ".md2", ".obj",
3972 if(removeStringEnd(filename, supported_ext) == ""){
3973 infostream<<"Server: ignoring unsupported file extension: \""
3974 <<filename<<"\""<<std::endl;
3977 // Ok, attempt to load the file and add to cache
3978 std::string filepath = mediapath + DIR_DELIM + filename;
3980 std::ifstream fis(filepath.c_str(), std::ios_base::binary);
3981 if(fis.good() == false){
3982 errorstream<<"Server::fillMediaCache(): Could not open \""
3983 <<filename<<"\" for reading"<<std::endl;
3986 std::ostringstream tmp_os(std::ios_base::binary);
3990 fis.read(buf, 1024);
3991 std::streamsize len = fis.gcount();
3992 tmp_os.write(buf, len);
4001 errorstream<<"Server::fillMediaCache(): Failed to read \""
4002 <<filename<<"\""<<std::endl;
4005 if(tmp_os.str().length() == 0){
4006 errorstream<<"Server::fillMediaCache(): Empty file \""
4007 <<filepath<<"\""<<std::endl;
4012 sha1.addBytes(tmp_os.str().c_str(), tmp_os.str().length());
4014 unsigned char *digest = sha1.getDigest();
4015 std::string sha1_base64 = base64_encode(digest, 20);
4016 std::string sha1_hex = hex_encode((char*)digest, 20);
4020 this->m_media[filename] = MediaInfo(filepath, sha1_base64);
4021 verbosestream<<"Server: "<<sha1_hex<<" is "<<filename<<std::endl;
4026 struct SendableMediaAnnouncement
4029 std::string sha1_digest;
4031 SendableMediaAnnouncement(const std::string &name_="",
4032 const std::string &sha1_digest_=""):
4034 sha1_digest(sha1_digest_)
4038 void Server::sendMediaAnnouncement(u16 peer_id)
4040 DSTACK(__FUNCTION_NAME);
4042 verbosestream<<"Server: Announcing files to id("<<peer_id<<")"
4045 std::list<SendableMediaAnnouncement> file_announcements;
4047 for(std::map<std::string, MediaInfo>::iterator i = m_media.begin();
4048 i != m_media.end(); i++){
4050 file_announcements.push_back(
4051 SendableMediaAnnouncement(i->first, i->second.sha1_digest));
4055 std::ostringstream os(std::ios_base::binary);
4063 u16 length of sha1_digest
4068 writeU16(os, TOCLIENT_ANNOUNCE_MEDIA);
4069 writeU16(os, file_announcements.size());
4071 for(std::list<SendableMediaAnnouncement>::iterator
4072 j = file_announcements.begin();
4073 j != file_announcements.end(); ++j){
4074 os<<serializeString(j->name);
4075 os<<serializeString(j->sha1_digest);
4077 os<<serializeString(g_settings->get("remote_media"));
4080 std::string s = os.str();
4081 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
4084 m_clients.send(peer_id, 0, data, true);
4087 struct SendableMedia
4093 SendableMedia(const std::string &name_="", const std::string &path_="",
4094 const std::string &data_=""):
4101 void Server::sendRequestedMedia(u16 peer_id,
4102 const std::list<std::string> &tosend)
4104 DSTACK(__FUNCTION_NAME);
4106 verbosestream<<"Server::sendRequestedMedia(): "
4107 <<"Sending files to client"<<std::endl;
4111 // Put 5kB in one bunch (this is not accurate)
4112 u32 bytes_per_bunch = 5000;
4114 std::vector< std::list<SendableMedia> > file_bunches;
4115 file_bunches.push_back(std::list<SendableMedia>());
4117 u32 file_size_bunch_total = 0;
4119 for(std::list<std::string>::const_iterator i = tosend.begin();
4120 i != tosend.end(); ++i)
4122 const std::string &name = *i;
4124 if(m_media.find(name) == m_media.end()){
4125 errorstream<<"Server::sendRequestedMedia(): Client asked for "
4126 <<"unknown file \""<<(name)<<"\""<<std::endl;
4130 //TODO get path + name
4131 std::string tpath = m_media[name].path;
4134 std::ifstream fis(tpath.c_str(), std::ios_base::binary);
4135 if(fis.good() == false){
4136 errorstream<<"Server::sendRequestedMedia(): Could not open \""
4137 <<tpath<<"\" for reading"<<std::endl;
4140 std::ostringstream tmp_os(std::ios_base::binary);
4144 fis.read(buf, 1024);
4145 std::streamsize len = fis.gcount();
4146 tmp_os.write(buf, len);
4147 file_size_bunch_total += len;
4156 errorstream<<"Server::sendRequestedMedia(): Failed to read \""
4157 <<name<<"\""<<std::endl;
4160 /*infostream<<"Server::sendRequestedMedia(): Loaded \""
4161 <<tname<<"\""<<std::endl;*/
4163 file_bunches[file_bunches.size()-1].push_back(
4164 SendableMedia(name, tpath, tmp_os.str()));
4166 // Start next bunch if got enough data
4167 if(file_size_bunch_total >= bytes_per_bunch){
4168 file_bunches.push_back(std::list<SendableMedia>());
4169 file_size_bunch_total = 0;
4174 /* Create and send packets */
4176 u32 num_bunches = file_bunches.size();
4177 for(u32 i=0; i<num_bunches; i++)
4179 std::ostringstream os(std::ios_base::binary);
4183 u16 total number of texture bunches
4184 u16 index of this bunch
4185 u32 number of files in this bunch
4194 writeU16(os, TOCLIENT_MEDIA);
4195 writeU16(os, num_bunches);
4197 writeU32(os, file_bunches[i].size());
4199 for(std::list<SendableMedia>::iterator
4200 j = file_bunches[i].begin();
4201 j != file_bunches[i].end(); ++j){
4202 os<<serializeString(j->name);
4203 os<<serializeLongString(j->data);
4207 std::string s = os.str();
4208 verbosestream<<"Server::sendRequestedMedia(): bunch "
4209 <<i<<"/"<<num_bunches
4210 <<" files="<<file_bunches[i].size()
4211 <<" size=" <<s.size()<<std::endl;
4212 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
4214 m_clients.send(peer_id, 2, data, true);
4218 void Server::sendDetachedInventory(const std::string &name, u16 peer_id)
4220 if(m_detached_inventories.count(name) == 0){
4221 errorstream<<__FUNCTION_NAME<<": \""<<name<<"\" not found"<<std::endl;
4224 Inventory *inv = m_detached_inventories[name];
4226 std::ostringstream os(std::ios_base::binary);
4227 writeU16(os, TOCLIENT_DETACHED_INVENTORY);
4228 os<<serializeString(name);
4232 std::string s = os.str();
4233 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
4235 if (peer_id != PEER_ID_INEXISTENT)
4238 m_clients.send(peer_id, 0, data, true);
4242 m_clients.sendToAll(0,data,true);
4246 void Server::sendDetachedInventories(u16 peer_id)
4248 DSTACK(__FUNCTION_NAME);
4250 for(std::map<std::string, Inventory*>::iterator
4251 i = m_detached_inventories.begin();
4252 i != m_detached_inventories.end(); i++){
4253 const std::string &name = i->first;
4254 //Inventory *inv = i->second;
4255 sendDetachedInventory(name, peer_id);
4263 void Server::DiePlayer(u16 peer_id)
4265 DSTACK(__FUNCTION_NAME);
4267 PlayerSAO *playersao = getPlayerSAO(peer_id);
4270 infostream<<"Server::DiePlayer(): Player "
4271 <<playersao->getPlayer()->getName()
4272 <<" dies"<<std::endl;
4274 playersao->setHP(0);
4276 // Trigger scripted stuff
4277 m_script->on_dieplayer(playersao);
4279 SendPlayerHP(peer_id);
4280 SendDeathscreen(peer_id, false, v3f(0,0,0));
4283 void Server::RespawnPlayer(u16 peer_id)
4285 DSTACK(__FUNCTION_NAME);
4287 PlayerSAO *playersao = getPlayerSAO(peer_id);
4290 infostream<<"Server::RespawnPlayer(): Player "
4291 <<playersao->getPlayer()->getName()
4292 <<" respawns"<<std::endl;
4294 playersao->setHP(PLAYER_MAX_HP);
4296 bool repositioned = m_script->on_respawnplayer(playersao);
4298 v3f pos = findSpawnPos(m_env->getServerMap());
4299 playersao->setPos(pos);
4303 void Server::DenyAccess(u16 peer_id, const std::wstring &reason)
4305 DSTACK(__FUNCTION_NAME);
4307 SendAccessDenied(peer_id, reason);
4308 m_clients.event(peer_id,SetDenied);
4309 m_con.DisconnectPeer(peer_id);
4312 void Server::DeleteClient(u16 peer_id, ClientDeletionReason reason)
4314 DSTACK(__FUNCTION_NAME);
4315 std::wstring message;
4318 Clear references to playing sounds
4320 for(std::map<s32, ServerPlayingSound>::iterator
4321 i = m_playing_sounds.begin();
4322 i != m_playing_sounds.end();)
4324 ServerPlayingSound &psound = i->second;
4325 psound.clients.erase(peer_id);
4326 if(psound.clients.size() == 0)
4327 m_playing_sounds.erase(i++);
4332 Player *player = m_env->getPlayer(peer_id);
4334 // Collect information about leaving in chat
4336 if(player != NULL && reason != CDR_DENY)
4338 std::wstring name = narrow_to_wide(player->getName());
4341 message += L" left the game.";
4342 if(reason == CDR_TIMEOUT)
4343 message += L" (timed out)";
4347 /* Run scripts and remove from environment */
4351 PlayerSAO *playersao = player->getPlayerSAO();
4354 m_script->on_leaveplayer(playersao);
4356 playersao->disconnected();
4364 if(player != NULL && reason != CDR_DENY)
4366 std::ostringstream os(std::ios_base::binary);
4367 std::list<u16> clients = m_clients.getClientIDs();
4369 for(std::list<u16>::iterator
4370 i = clients.begin();
4371 i != clients.end(); ++i)
4374 Player *player = m_env->getPlayer(*i);
4377 // Get name of player
4378 os<<player->getName()<<" ";
4381 actionstream<<player->getName()<<" "
4382 <<(reason==CDR_TIMEOUT?"times out.":"leaves game.")
4383 <<" List of players: "<<os.str()<<std::endl;
4387 JMutexAutoLock env_lock(m_env_mutex);
4388 m_clients.DeleteClient(peer_id);
4392 // Send leave chat message to all remaining clients
4393 if(message.length() != 0)
4394 SendChatMessage(PEER_ID_INEXISTENT,message);
4397 void Server::UpdateCrafting(u16 peer_id)
4399 DSTACK(__FUNCTION_NAME);
4401 Player* player = m_env->getPlayer(peer_id);
4404 // Get a preview for crafting
4406 InventoryLocation loc;
4407 loc.setPlayer(player->getName());
4408 getCraftingResult(&player->inventory, preview, false, this);
4409 m_env->getScriptIface()->item_CraftPredict(preview, player->getPlayerSAO(), (&player->inventory)->getList("craft"), loc);
4411 // Put the new preview in
4412 InventoryList *plist = player->inventory.getList("craftpreview");
4414 assert(plist->getSize() >= 1);
4415 plist->changeItem(0, preview);
4418 RemoteClient* Server::getClient(u16 peer_id, ClientState state_min)
4420 RemoteClient *client = getClientNoEx(peer_id,state_min);
4422 throw ClientNotFoundException("Client not found");
4426 RemoteClient* Server::getClientNoEx(u16 peer_id, ClientState state_min)
4428 return m_clients.getClientNoEx(peer_id, state_min);
4431 std::string Server::getPlayerName(u16 peer_id)
4433 Player *player = m_env->getPlayer(peer_id);
4435 return "[id="+itos(peer_id)+"]";
4436 return player->getName();
4439 PlayerSAO* Server::getPlayerSAO(u16 peer_id)
4441 Player *player = m_env->getPlayer(peer_id);
4444 return player->getPlayerSAO();
4447 std::wstring Server::getStatusString()
4449 std::wostringstream os(std::ios_base::binary);
4452 os<<L"version="<<narrow_to_wide(minetest_version_simple);
4454 os<<L", uptime="<<m_uptime.get();
4456 os<<L", max_lag="<<m_env->getMaxLagEstimate();
4457 // Information about clients
4460 std::list<u16> clients = m_clients.getClientIDs();
4461 for(std::list<u16>::iterator i = clients.begin();
4462 i != clients.end(); ++i)
4465 Player *player = m_env->getPlayer(*i);
4466 // Get name of player
4467 std::wstring name = L"unknown";
4469 name = narrow_to_wide(player->getName());
4470 // Add name to information string
4478 if(((ServerMap*)(&m_env->getMap()))->isSavingEnabled() == false)
4479 os<<std::endl<<L"# Server: "<<" WARNING: Map saving is disabled.";
4480 if(g_settings->get("motd") != "")
4481 os<<std::endl<<L"# Server: "<<narrow_to_wide(g_settings->get("motd"));
4485 std::set<std::string> Server::getPlayerEffectivePrivs(const std::string &name)
4487 std::set<std::string> privs;
4488 m_script->getAuth(name, NULL, &privs);
4492 bool Server::checkPriv(const std::string &name, const std::string &priv)
4494 std::set<std::string> privs = getPlayerEffectivePrivs(name);
4495 return (privs.count(priv) != 0);
4498 void Server::reportPrivsModified(const std::string &name)
4501 std::list<u16> clients = m_clients.getClientIDs();
4502 for(std::list<u16>::iterator
4503 i = clients.begin();
4504 i != clients.end(); ++i){
4505 Player *player = m_env->getPlayer(*i);
4506 reportPrivsModified(player->getName());
4509 Player *player = m_env->getPlayer(name.c_str());
4512 SendPlayerPrivileges(player->peer_id);
4513 PlayerSAO *sao = player->getPlayerSAO();
4516 sao->updatePrivileges(
4517 getPlayerEffectivePrivs(name),
4522 void Server::reportInventoryFormspecModified(const std::string &name)
4524 Player *player = m_env->getPlayer(name.c_str());
4527 SendPlayerInventoryFormspec(player->peer_id);
4530 void Server::setIpBanned(const std::string &ip, const std::string &name)
4532 m_banmanager->add(ip, name);
4535 void Server::unsetIpBanned(const std::string &ip_or_name)
4537 m_banmanager->remove(ip_or_name);
4540 std::string Server::getBanDescription(const std::string &ip_or_name)
4542 return m_banmanager->getBanDescription(ip_or_name);
4545 void Server::notifyPlayer(const char *name, const std::wstring &msg)
4547 Player *player = m_env->getPlayer(name);
4551 if (player->peer_id == PEER_ID_INEXISTENT)
4554 SendChatMessage(player->peer_id, msg);
4557 bool Server::showFormspec(const char *playername, const std::string &formspec, const std::string &formname)
4559 Player *player = m_env->getPlayer(playername);
4563 infostream<<"showFormspec: couldn't find player:"<<playername<<std::endl;
4567 SendShowFormspecMessage(player->peer_id, formspec, formname);
4571 u32 Server::hudAdd(Player *player, HudElement *form) {
4575 u32 id = player->addHud(form);
4577 SendHUDAdd(player->peer_id, id, form);
4582 bool Server::hudRemove(Player *player, u32 id) {
4586 HudElement* todel = player->removeHud(id);
4593 SendHUDRemove(player->peer_id, id);
4597 bool Server::hudChange(Player *player, u32 id, HudElementStat stat, void *data) {
4601 SendHUDChange(player->peer_id, id, stat, data);
4605 bool Server::hudSetFlags(Player *player, u32 flags, u32 mask) {
4609 SendHUDSetFlags(player->peer_id, flags, mask);
4610 player->hud_flags = flags;
4612 m_script->player_event(player->getPlayerSAO(),"hud_changed");
4616 bool Server::hudSetHotbarItemcount(Player *player, s32 hotbar_itemcount) {
4619 if (hotbar_itemcount <= 0 || hotbar_itemcount > HUD_HOTBAR_ITEMCOUNT_MAX)
4622 std::ostringstream os(std::ios::binary);
4623 writeS32(os, hotbar_itemcount);
4624 SendHUDSetParam(player->peer_id, HUD_PARAM_HOTBAR_ITEMCOUNT, os.str());
4628 void Server::hudSetHotbarImage(Player *player, std::string name) {
4632 SendHUDSetParam(player->peer_id, HUD_PARAM_HOTBAR_IMAGE, name);
4635 void Server::hudSetHotbarSelectedImage(Player *player, std::string name) {
4639 SendHUDSetParam(player->peer_id, HUD_PARAM_HOTBAR_SELECTED_IMAGE, name);
4642 bool Server::setLocalPlayerAnimations(Player *player, v2s32 animation_frames[4], f32 frame_speed)
4647 SendLocalPlayerAnimations(player->peer_id, animation_frames, frame_speed);
4651 bool Server::setPlayerEyeOffset(Player *player, v3f first, v3f third)
4656 SendEyeOffset(player->peer_id, first, third);
4660 bool Server::setSky(Player *player, const video::SColor &bgcolor,
4661 const std::string &type, const std::vector<std::string> ¶ms)
4666 SendSetSky(player->peer_id, bgcolor, type, params);
4670 bool Server::overrideDayNightRatio(Player *player, bool do_override,
4676 SendOverrideDayNightRatio(player->peer_id, do_override, ratio);
4680 void Server::notifyPlayers(const std::wstring &msg)
4682 SendChatMessage(PEER_ID_INEXISTENT,msg);
4685 void Server::spawnParticle(const char *playername, v3f pos,
4686 v3f velocity, v3f acceleration,
4687 float expirationtime, float size, bool
4688 collisiondetection, bool vertical, std::string texture)
4690 Player *player = m_env->getPlayer(playername);
4693 SendSpawnParticle(player->peer_id, pos, velocity, acceleration,
4694 expirationtime, size, collisiondetection, vertical, texture);
4697 void Server::spawnParticleAll(v3f pos, v3f velocity, v3f acceleration,
4698 float expirationtime, float size,
4699 bool collisiondetection, bool vertical, std::string texture)
4701 SendSpawnParticle(PEER_ID_INEXISTENT,pos, velocity, acceleration,
4702 expirationtime, size, collisiondetection, vertical, texture);
4705 u32 Server::addParticleSpawner(const char *playername,
4706 u16 amount, float spawntime,
4707 v3f minpos, v3f maxpos,
4708 v3f minvel, v3f maxvel,
4709 v3f minacc, v3f maxacc,
4710 float minexptime, float maxexptime,
4711 float minsize, float maxsize,
4712 bool collisiondetection, bool vertical, std::string texture)
4714 Player *player = m_env->getPlayer(playername);
4719 for(;;) // look for unused particlespawner id
4722 if (std::find(m_particlespawner_ids.begin(),
4723 m_particlespawner_ids.end(), id)
4724 == m_particlespawner_ids.end())
4726 m_particlespawner_ids.push_back(id);
4731 SendAddParticleSpawner(player->peer_id, amount, spawntime,
4732 minpos, maxpos, minvel, maxvel, minacc, maxacc,
4733 minexptime, maxexptime, minsize, maxsize,
4734 collisiondetection, vertical, texture, id);
4739 u32 Server::addParticleSpawnerAll(u16 amount, float spawntime,
4740 v3f minpos, v3f maxpos,
4741 v3f minvel, v3f maxvel,
4742 v3f minacc, v3f maxacc,
4743 float minexptime, float maxexptime,
4744 float minsize, float maxsize,
4745 bool collisiondetection, bool vertical, std::string texture)
4748 for(;;) // look for unused particlespawner id
4751 if (std::find(m_particlespawner_ids.begin(),
4752 m_particlespawner_ids.end(), id)
4753 == m_particlespawner_ids.end())
4755 m_particlespawner_ids.push_back(id);
4760 SendAddParticleSpawner(PEER_ID_INEXISTENT, amount, spawntime,
4761 minpos, maxpos, minvel, maxvel, minacc, maxacc,
4762 minexptime, maxexptime, minsize, maxsize,
4763 collisiondetection, vertical, texture, id);
4768 void Server::deleteParticleSpawner(const char *playername, u32 id)
4770 Player *player = m_env->getPlayer(playername);
4774 m_particlespawner_ids.erase(
4775 std::remove(m_particlespawner_ids.begin(),
4776 m_particlespawner_ids.end(), id),
4777 m_particlespawner_ids.end());
4778 SendDeleteParticleSpawner(player->peer_id, id);
4781 void Server::deleteParticleSpawnerAll(u32 id)
4783 m_particlespawner_ids.erase(
4784 std::remove(m_particlespawner_ids.begin(),
4785 m_particlespawner_ids.end(), id),
4786 m_particlespawner_ids.end());
4787 SendDeleteParticleSpawner(PEER_ID_INEXISTENT, id);
4790 Inventory* Server::createDetachedInventory(const std::string &name)
4792 if(m_detached_inventories.count(name) > 0){
4793 infostream<<"Server clearing detached inventory \""<<name<<"\""<<std::endl;
4794 delete m_detached_inventories[name];
4796 infostream<<"Server creating detached inventory \""<<name<<"\""<<std::endl;
4798 Inventory *inv = new Inventory(m_itemdef);
4800 m_detached_inventories[name] = inv;
4801 //TODO find a better way to do this
4802 sendDetachedInventory(name,PEER_ID_INEXISTENT);
4809 BoolScopeSet(bool *dst, bool val):
4812 m_orig_state = *m_dst;
4817 *m_dst = m_orig_state;
4824 // actions: time-reversed list
4825 // Return value: success/failure
4826 bool Server::rollbackRevertActions(const std::list<RollbackAction> &actions,
4827 std::list<std::string> *log)
4829 infostream<<"Server::rollbackRevertActions(len="<<actions.size()<<")"<<std::endl;
4830 ServerMap *map = (ServerMap*)(&m_env->getMap());
4831 // Disable rollback report sink while reverting
4832 BoolScopeSet rollback_scope_disable(&m_rollback_sink_enabled, false);
4834 // Fail if no actions to handle
4835 if(actions.empty()){
4836 log->push_back("Nothing to do.");
4843 for(std::list<RollbackAction>::const_iterator
4844 i = actions.begin();
4845 i != actions.end(); i++)
4847 const RollbackAction &action = *i;
4849 bool success = action.applyRevert(map, this, this);
4852 std::ostringstream os;
4853 os<<"Revert of step ("<<num_tried<<") "<<action.toString()<<" failed";
4854 infostream<<"Map::rollbackRevertActions(): "<<os.str()<<std::endl;
4856 log->push_back(os.str());
4858 std::ostringstream os;
4859 os<<"Successfully reverted step ("<<num_tried<<") "<<action.toString();
4860 infostream<<"Map::rollbackRevertActions(): "<<os.str()<<std::endl;
4862 log->push_back(os.str());
4866 infostream<<"Map::rollbackRevertActions(): "<<num_failed<<"/"<<num_tried
4867 <<" failed"<<std::endl;
4869 // Call it done if less than half failed
4870 return num_failed <= num_tried/2;
4873 // IGameDef interface
4875 IItemDefManager* Server::getItemDefManager()
4879 INodeDefManager* Server::getNodeDefManager()
4883 ICraftDefManager* Server::getCraftDefManager()
4887 ITextureSource* Server::getTextureSource()
4891 IShaderSource* Server::getShaderSource()
4895 u16 Server::allocateUnknownNodeId(const std::string &name)
4897 return m_nodedef->allocateDummy(name);
4899 ISoundManager* Server::getSoundManager()
4901 return &dummySoundManager;
4903 MtEventManager* Server::getEventManager()
4907 IRollbackReportSink* Server::getRollbackReportSink()
4909 if(!m_enable_rollback_recording)
4911 if(!m_rollback_sink_enabled)
4916 IWritableItemDefManager* Server::getWritableItemDefManager()
4920 IWritableNodeDefManager* Server::getWritableNodeDefManager()
4924 IWritableCraftDefManager* Server::getWritableCraftDefManager()
4929 const ModSpec* Server::getModSpec(const std::string &modname)
4931 for(std::vector<ModSpec>::iterator i = m_mods.begin();
4932 i != m_mods.end(); i++){
4933 const ModSpec &mod = *i;
4934 if(mod.name == modname)
4939 void Server::getModNames(std::list<std::string> &modlist)
4941 for(std::vector<ModSpec>::iterator i = m_mods.begin(); i != m_mods.end(); i++)
4943 modlist.push_back(i->name);
4946 std::string Server::getBuiltinLuaPath()
4948 return porting::path_share + DIR_DELIM + "builtin";
4951 v3f findSpawnPos(ServerMap &map)
4953 //return v3f(50,50,50)*BS;
4958 nodepos = v2s16(0,0);
4963 s16 water_level = map.getWaterLevel();
4965 // Try to find a good place a few times
4966 for(s32 i=0; i<1000; i++)
4969 // We're going to try to throw the player to this position
4970 v2s16 nodepos2d = v2s16(
4971 -range + (myrand() % (range * 2)),
4972 -range + (myrand() % (range * 2)));
4974 // Get ground height at point
4975 s16 groundheight = map.findGroundLevel(nodepos2d);
4976 if (groundheight <= water_level) // Don't go underwater
4978 if (groundheight > water_level + 6) // Don't go to high places
4981 nodepos = v3s16(nodepos2d.X, groundheight, nodepos2d.Y);
4982 bool is_good = false;
4984 for (s32 i = 0; i < 10; i++) {
4985 v3s16 blockpos = getNodeBlockPos(nodepos);
4986 map.emergeBlock(blockpos, true);
4987 content_t c = map.getNodeNoEx(nodepos).getContent();
4988 if (c == CONTENT_AIR || c == CONTENT_IGNORE) {
4990 if (air_count >= 2){
4998 // Found a good place
4999 //infostream<<"Searched through "<<i<<" places."<<std::endl;
5005 return intToFloat(nodepos, BS);
5008 PlayerSAO* Server::emergePlayer(const char *name, u16 peer_id)
5010 RemotePlayer *player = NULL;
5011 bool newplayer = false;
5014 Try to get an existing player
5016 player = static_cast<RemotePlayer*>(m_env->getPlayer(name));
5018 // If player is already connected, cancel
5019 if(player != NULL && player->peer_id != 0)
5021 infostream<<"emergePlayer(): Player already connected"<<std::endl;
5026 If player with the wanted peer_id already exists, cancel.
5028 if(m_env->getPlayer(peer_id) != NULL)
5030 infostream<<"emergePlayer(): Player with wrong name but same"
5031 " peer_id already exists"<<std::endl;
5036 Create a new player if it doesn't exist yet
5041 player = new RemotePlayer(this);
5042 player->updateName(name);
5044 /* Set player position */
5045 infostream<<"Server: Finding spawn place for player \""
5046 <<name<<"\""<<std::endl;
5047 v3f pos = findSpawnPos(m_env->getServerMap());
5048 player->setPosition(pos);
5050 /* Add player to environment */
5051 m_env->addPlayer(player);
5055 Create a new player active object
5057 PlayerSAO *playersao = new PlayerSAO(m_env, player, peer_id,
5058 getPlayerEffectivePrivs(player->getName()),
5061 /* Clean up old HUD elements from previous sessions */
5064 /* Add object to environment */
5065 m_env->addActiveObject(playersao);
5069 m_script->on_newplayer(playersao);
5074 void dedicated_server_loop(Server &server, bool &kill)
5076 DSTACK(__FUNCTION_NAME);
5078 verbosestream<<"dedicated_server_loop()"<<std::endl;
5080 IntervalLimiter m_profiler_interval;
5084 float steplen = g_settings->getFloat("dedicated_server_step");
5085 // This is kind of a hack but can be done like this
5086 // because server.step() is very light
5088 ScopeProfiler sp(g_profiler, "dedicated server sleep");
5089 sleep_ms((int)(steplen*1000.0));
5091 server.step(steplen);
5093 if(server.getShutdownRequested() || kill)
5095 infostream<<"Dedicated server quitting"<<std::endl;
5097 if(g_settings->getBool("server_announce") == true)
5098 ServerList::sendAnnounce("delete");
5106 float profiler_print_interval =
5107 g_settings->getFloat("profiler_print_interval");
5108 if(profiler_print_interval != 0)
5110 if(m_profiler_interval.step(steplen, profiler_print_interval))
5112 infostream<<"Profiler:"<<std::endl;
5113 g_profiler->print(infostream);
5114 g_profiler->clear();