3 Copyright (C) 2010-2013 celeron55, Perttu Ahola <celeron55@gmail.com>
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU Lesser General Public License as published by
7 the Free Software Foundation; either version 2.1 of the License, or
8 (at your option) any later version.
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU Lesser General Public License for more details.
15 You should have received a copy of the GNU Lesser General Public License along
16 with this program; if not, write to the Free Software Foundation, Inc.,
17 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
24 #include "clientserver.h"
26 #include "environment.h"
28 #include "jthread/jmutexautolock.h"
30 #include "constants.h"
36 #include "serverobject.h"
37 #include "genericobject.h"
41 #include "scripting_game.h"
48 #include "content_mapnode.h"
49 #include "content_nodemeta.h"
50 #include "content_abm.h"
51 #include "content_sao.h"
56 #include "sound.h" // dummySoundManager
57 #include "event_manager.h"
59 #include "serverlist.h"
60 #include "util/string.h"
61 #include "util/pointedthing.h"
62 #include "util/mathconstants.h"
64 #include "util/serialize.h"
65 #include "util/thread.h"
66 #include "defaultsettings.h"
68 class ClientNotFoundException : public BaseException
71 ClientNotFoundException(const char *s):
76 class ServerThread : public JThread
82 ServerThread(Server *server):
91 void * ServerThread::Thread()
93 log_register_thread("ServerThread");
95 DSTACK(__FUNCTION_NAME);
96 BEGIN_DEBUG_EXCEPTION_HANDLER
98 m_server->AsyncRunStep(true);
102 porting::setThreadName("ServerThread");
104 while(!StopRequested())
107 //TimeTaker timer("AsyncRunStep() + Receive()");
109 m_server->AsyncRunStep();
114 catch(con::NoIncomingDataException &e)
117 catch(con::PeerNotFoundException &e)
119 infostream<<"Server: PeerNotFoundException"<<std::endl;
121 catch(ClientNotFoundException &e)
124 catch(con::ConnectionBindFailed &e)
126 m_server->setAsyncFatalError(e.what());
130 m_server->setAsyncFatalError(e.what());
134 END_DEBUG_EXCEPTION_HANDLER(errorstream)
139 v3f ServerSoundParams::getPos(ServerEnvironment *env, bool *pos_exists) const
141 if(pos_exists) *pos_exists = false;
146 if(pos_exists) *pos_exists = true;
151 ServerActiveObject *sao = env->getActiveObject(object);
154 if(pos_exists) *pos_exists = true;
155 return sao->getBasePosition(); }
167 const std::string &path_world,
168 const SubgameSpec &gamespec,
169 bool simple_singleplayer_mode,
172 m_path_world(path_world),
173 m_gamespec(gamespec),
174 m_simple_singleplayer_mode(simple_singleplayer_mode),
175 m_async_fatal_error(""),
184 m_rollback_sink_enabled(true),
185 m_enable_rollback_recording(false),
188 m_itemdef(createItemDefManager()),
189 m_nodedef(createNodeDefManager()),
190 m_craftdef(createCraftDefManager()),
191 m_event(new EventManager()),
193 m_time_of_day_send_timer(0),
196 m_shutdown_requested(false),
197 m_ignore_map_edit_events(false),
198 m_ignore_map_edit_events_peer_id(0)
201 m_liquid_transform_timer = 0.0;
202 m_liquid_transform_every = 1.0;
203 m_print_info_timer = 0.0;
204 m_masterserver_timer = 0.0;
205 m_objectdata_timer = 0.0;
206 m_emergethread_trigger_timer = 0.0;
207 m_savemap_timer = 0.0;
210 m_lag = g_settings->getFloat("dedicated_server_step");
213 throw ServerError("Supplied empty world path");
215 if(!gamespec.isValid())
216 throw ServerError("Supplied invalid gamespec");
218 infostream<<"Server created for gameid \""<<m_gamespec.id<<"\"";
219 if(m_simple_singleplayer_mode)
220 infostream<<" in simple singleplayer mode"<<std::endl;
222 infostream<<std::endl;
223 infostream<<"- world: "<<m_path_world<<std::endl;
224 infostream<<"- game: "<<m_gamespec.path<<std::endl;
226 // Initialize default settings and override defaults with those provided
228 set_default_settings(g_settings);
229 Settings gamedefaults;
230 getGameMinetestConfig(gamespec.path, gamedefaults);
231 override_default_settings(g_settings, &gamedefaults);
233 // Create server thread
234 m_thread = new ServerThread(this);
236 // Create emerge manager
237 m_emerge = new EmergeManager(this);
239 // Create world if it doesn't exist
240 if(!initializeWorld(m_path_world, m_gamespec.id))
241 throw ServerError("Failed to initialize world");
243 // Create ban manager
244 std::string ban_path = m_path_world+DIR_DELIM+"ipban.txt";
245 m_banmanager = new BanManager(ban_path);
247 // Create rollback manager
248 std::string rollback_path = m_path_world+DIR_DELIM+"rollback.txt";
249 m_rollback = createRollbackManager(rollback_path, this);
251 ModConfiguration modconf(m_path_world);
252 m_mods = modconf.getMods();
253 std::vector<ModSpec> unsatisfied_mods = modconf.getUnsatisfiedMods();
254 // complain about mods with unsatisfied dependencies
255 if(!modconf.isConsistent())
257 for(std::vector<ModSpec>::iterator it = unsatisfied_mods.begin();
258 it != unsatisfied_mods.end(); ++it)
261 errorstream << "mod \"" << mod.name << "\" has unsatisfied dependencies: ";
262 for(std::set<std::string>::iterator dep_it = mod.unsatisfied_depends.begin();
263 dep_it != mod.unsatisfied_depends.end(); ++dep_it)
264 errorstream << " \"" << *dep_it << "\"";
265 errorstream << std::endl;
269 Settings worldmt_settings;
270 std::string worldmt = m_path_world + DIR_DELIM + "world.mt";
271 worldmt_settings.readConfigFile(worldmt.c_str());
272 std::vector<std::string> names = worldmt_settings.getNames();
273 std::set<std::string> load_mod_names;
274 for(std::vector<std::string>::iterator it = names.begin();
275 it != names.end(); ++it)
277 std::string name = *it;
278 if(name.compare(0,9,"load_mod_")==0 && worldmt_settings.getBool(name))
279 load_mod_names.insert(name.substr(9));
281 // complain about mods declared to be loaded, but not found
282 for(std::vector<ModSpec>::iterator it = m_mods.begin();
283 it != m_mods.end(); ++it)
284 load_mod_names.erase((*it).name);
285 for(std::vector<ModSpec>::iterator it = unsatisfied_mods.begin();
286 it != unsatisfied_mods.end(); ++it)
287 load_mod_names.erase((*it).name);
288 if(!load_mod_names.empty())
290 errorstream << "The following mods could not be found:";
291 for(std::set<std::string>::iterator it = load_mod_names.begin();
292 it != load_mod_names.end(); ++it)
293 errorstream << " \"" << (*it) << "\"";
294 errorstream << std::endl;
298 JMutexAutoLock envlock(m_env_mutex);
300 // Initialize scripting
301 infostream<<"Server: Initializing Lua"<<std::endl;
303 m_script = new GameScripting(this);
305 std::string scriptpath = getBuiltinLuaPath() + DIR_DELIM "init.lua";
307 if (!m_script->loadScript(scriptpath)) {
308 throw ModError("Failed to load and run " + scriptpath);
313 infostream<<"Server: Loading mods: ";
314 for(std::vector<ModSpec>::iterator i = m_mods.begin();
315 i != m_mods.end(); i++){
316 const ModSpec &mod = *i;
317 infostream<<mod.name<<" ";
319 infostream<<std::endl;
320 // Load and run "mod" scripts
321 for(std::vector<ModSpec>::iterator i = m_mods.begin();
322 i != m_mods.end(); i++){
323 const ModSpec &mod = *i;
324 std::string scriptpath = mod.path + DIR_DELIM + "init.lua";
325 infostream<<" ["<<padStringRight(mod.name, 12)<<"] [\""
326 <<scriptpath<<"\"]"<<std::endl;
327 bool success = m_script->loadMod(scriptpath, mod.name);
329 errorstream<<"Server: Failed to load and run "
330 <<scriptpath<<std::endl;
331 throw ModError("Failed to load and run "+scriptpath);
335 // Read Textures and calculate sha1 sums
338 // Apply item aliases in the node definition manager
339 m_nodedef->updateAliases(m_itemdef);
341 // Load the mapgen params from global settings now after any
342 // initial overrides have been set by the mods
343 m_emerge->loadMapgenParams();
345 // Initialize Environment
346 ServerMap *servermap = new ServerMap(path_world, this, m_emerge);
347 m_env = new ServerEnvironment(servermap, m_script, this, m_path_world);
349 m_clients.setEnv(m_env);
351 // Run some callbacks after the MG params have been set up but before activation
352 m_script->environment_OnMapgenInit(&m_emerge->params);
354 // Initialize mapgens
355 m_emerge->initMapgens();
357 // Give environment reference to scripting api
358 m_script->initializeEnvironment(m_env);
360 // Register us to receive map edit events
361 servermap->addEventReceiver(this);
363 // If file exists, load environment metadata
364 if(fs::PathExists(m_path_world + DIR_DELIM "env_meta.txt"))
366 infostream<<"Server: Loading environment metadata"<<std::endl;
370 // Add some test ActiveBlockModifiers to environment
371 add_legacy_abms(m_env, m_nodedef);
373 m_liquid_transform_every = g_settings->getFloat("liquid_update");
378 infostream<<"Server destructing"<<std::endl;
380 // Send shutdown message
381 SendChatMessage(PEER_ID_INEXISTENT, L"*** Server shutting down");
384 JMutexAutoLock envlock(m_env_mutex);
386 // Execute script shutdown hooks
387 m_script->on_shutdown();
389 infostream<<"Server: Saving players"<<std::endl;
390 m_env->saveLoadedPlayers();
392 infostream<<"Server: Saving environment metadata"<<std::endl;
400 // stop all emerge threads before deleting players that may have
401 // requested blocks to be emerged
402 m_emerge->stopThreads();
404 // Delete things in the reverse order of creation
407 // N.B. the EmergeManager should be deleted after the Environment since Map
408 // depends on EmergeManager to write its current params to the map meta
417 // Deinitialize scripting
418 infostream<<"Server: Deinitializing scripting"<<std::endl;
421 // Delete detached inventories
422 for (std::map<std::string, Inventory*>::iterator
423 i = m_detached_inventories.begin();
424 i != m_detached_inventories.end(); i++) {
429 void Server::start(Address bind_addr)
431 DSTACK(__FUNCTION_NAME);
432 infostream<<"Starting server on "
433 << bind_addr.serializeString() <<"..."<<std::endl;
435 // Stop thread if already running
438 // Initialize connection
439 m_con.SetTimeoutMs(30);
440 m_con.Serve(bind_addr);
445 // ASCII art for the win!
447 <<" .__ __ __ "<<std::endl
448 <<" _____ |__| ____ _____/ |_ ____ _______/ |_ "<<std::endl
449 <<" / \\| |/ \\_/ __ \\ __\\/ __ \\ / ___/\\ __\\"<<std::endl
450 <<"| Y Y \\ | | \\ ___/| | \\ ___/ \\___ \\ | | "<<std::endl
451 <<"|__|_| /__|___| /\\___ >__| \\___ >____ > |__| "<<std::endl
452 <<" \\/ \\/ \\/ \\/ \\/ "<<std::endl;
453 actionstream<<"World at ["<<m_path_world<<"]"<<std::endl;
454 actionstream<<"Server for gameid=\""<<m_gamespec.id
455 <<"\" listening on "<<bind_addr.serializeString()<<":"
456 <<bind_addr.getPort() << "."<<std::endl;
461 DSTACK(__FUNCTION_NAME);
463 infostream<<"Server: Stopping and waiting threads"<<std::endl;
465 // Stop threads (set run=false first so both start stopping)
467 //m_emergethread.setRun(false);
469 //m_emergethread.stop();
471 infostream<<"Server: Threads stopped"<<std::endl;
474 void Server::step(float dtime)
476 DSTACK(__FUNCTION_NAME);
481 JMutexAutoLock lock(m_step_dtime_mutex);
482 m_step_dtime += dtime;
484 // Throw if fatal error occurred in thread
485 std::string async_err = m_async_fatal_error.get();
487 throw ServerError(async_err);
491 void Server::AsyncRunStep(bool initial_step)
493 DSTACK(__FUNCTION_NAME);
495 g_profiler->add("Server::AsyncRunStep (num)", 1);
499 JMutexAutoLock lock1(m_step_dtime_mutex);
500 dtime = m_step_dtime;
504 // Send blocks to clients
508 if((dtime < 0.001) && (initial_step == false))
511 g_profiler->add("Server::AsyncRunStep with dtime (num)", 1);
513 //infostream<<"Server steps "<<dtime<<std::endl;
514 //infostream<<"Server::AsyncRunStep(): dtime="<<dtime<<std::endl;
517 JMutexAutoLock lock1(m_step_dtime_mutex);
518 m_step_dtime -= dtime;
525 m_uptime.set(m_uptime.get() + dtime);
531 Update time of day and overall game time
534 JMutexAutoLock envlock(m_env_mutex);
536 m_env->setTimeOfDaySpeed(g_settings->getFloat("time_speed"));
539 Send to clients at constant intervals
542 m_time_of_day_send_timer -= dtime;
543 if(m_time_of_day_send_timer < 0.0)
545 m_time_of_day_send_timer = g_settings->getFloat("time_send_interval");
546 u16 time = m_env->getTimeOfDay();
547 float time_speed = g_settings->getFloat("time_speed");
548 SendTimeOfDay(PEER_ID_INEXISTENT, time, time_speed);
553 JMutexAutoLock lock(m_env_mutex);
554 // Figure out and report maximum lag to environment
555 float max_lag = m_env->getMaxLagEstimate();
556 max_lag *= 0.9998; // Decrease slowly (about half per 5 minutes)
558 if(dtime > 0.1 && dtime > max_lag * 2.0)
559 infostream<<"Server: Maximum lag peaked to "<<dtime
563 m_env->reportMaxLagEstimate(max_lag);
565 ScopeProfiler sp(g_profiler, "SEnv step");
566 ScopeProfiler sp2(g_profiler, "SEnv step avg", SPT_AVG);
570 const float map_timer_and_unload_dtime = 2.92;
571 if(m_map_timer_and_unload_interval.step(dtime, map_timer_and_unload_dtime))
573 JMutexAutoLock lock(m_env_mutex);
574 // Run Map's timers and unload unused data
575 ScopeProfiler sp(g_profiler, "Server: map timer and unload");
576 m_env->getMap().timerUpdate(map_timer_and_unload_dtime,
577 g_settings->getFloat("server_unload_unused_data_timeout"));
588 JMutexAutoLock lock(m_env_mutex);
590 std::list<u16> clientids = m_clients.getClientIDs();
592 ScopeProfiler sp(g_profiler, "Server: handle players");
594 for(std::list<u16>::iterator
595 i = clientids.begin();
596 i != clientids.end(); ++i)
598 PlayerSAO *playersao = getPlayerSAO(*i);
599 if(playersao == NULL)
603 Handle player HPs (die if hp=0)
605 if(playersao->m_hp_not_sent && g_settings->getBool("enable_damage"))
607 if(playersao->getHP() == 0)
614 Send player breath if changed
616 if(playersao->m_breath_not_sent) {
617 SendPlayerBreath(*i);
621 Send player inventories if necessary
623 if(playersao->m_moved){
625 playersao->m_moved = false;
627 if(playersao->m_inventory_not_sent){
634 /* Transform liquids */
635 m_liquid_transform_timer += dtime;
636 if(m_liquid_transform_timer >= m_liquid_transform_every)
638 m_liquid_transform_timer -= m_liquid_transform_every;
640 JMutexAutoLock lock(m_env_mutex);
642 ScopeProfiler sp(g_profiler, "Server: liquid transform");
644 std::map<v3s16, MapBlock*> modified_blocks;
645 m_env->getMap().transformLiquids(modified_blocks);
650 core::map<v3s16, MapBlock*> lighting_modified_blocks;
651 ServerMap &map = ((ServerMap&)m_env->getMap());
652 map.updateLighting(modified_blocks, lighting_modified_blocks);
654 // Add blocks modified by lighting to modified_blocks
655 for(core::map<v3s16, MapBlock*>::Iterator
656 i = lighting_modified_blocks.getIterator();
657 i.atEnd() == false; i++)
659 MapBlock *block = i.getNode()->getValue();
660 modified_blocks.insert(block->getPos(), block);
664 Set the modified blocks unsent for all the clients
666 if(modified_blocks.size() > 0)
668 SetBlocksNotSent(modified_blocks);
671 m_clients.step(dtime);
673 m_lag += (m_lag > dtime ? -1 : 1) * dtime/100;
675 // send masterserver announce
677 float &counter = m_masterserver_timer;
678 if(!isSingleplayer() && (!counter || counter >= 300.0) &&
679 g_settings->getBool("server_announce"))
681 ServerList::sendAnnounce(counter ? "update" : "start",
682 m_clients.getPlayerNames(),
684 m_env->getGameTime(),
695 Check added and deleted active objects
698 //infostream<<"Server: Checking added and deleted active objects"<<std::endl;
699 JMutexAutoLock envlock(m_env_mutex);
702 std::map<u16, RemoteClient*> clients = m_clients.getClientList();
703 ScopeProfiler sp(g_profiler, "Server: checking added and deleted objs");
705 // Radius inside which objects are active
706 s16 radius = g_settings->getS16("active_object_send_range_blocks");
707 radius *= MAP_BLOCKSIZE;
709 for(std::map<u16, RemoteClient*>::iterator
711 i != clients.end(); ++i)
713 RemoteClient *client = i->second;
715 // If definitions and textures have not been sent, don't
716 // send objects either
717 if (client->getState() < CS_DefinitionsSent)
720 Player *player = m_env->getPlayer(client->peer_id);
723 // This can happen if the client timeouts somehow
724 /*infostream<<"WARNING: "<<__FUNCTION_NAME<<": Client "
726 <<" has no associated player"<<std::endl;*/
729 v3s16 pos = floatToInt(player->getPosition(), BS);
731 std::set<u16> removed_objects;
732 std::set<u16> added_objects;
733 m_env->getRemovedActiveObjects(pos, radius,
734 client->m_known_objects, removed_objects);
735 m_env->getAddedActiveObjects(pos, radius,
736 client->m_known_objects, added_objects);
738 // Ignore if nothing happened
739 if(removed_objects.size() == 0 && added_objects.size() == 0)
741 //infostream<<"active objects: none changed"<<std::endl;
745 std::string data_buffer;
749 // Handle removed objects
750 writeU16((u8*)buf, removed_objects.size());
751 data_buffer.append(buf, 2);
752 for(std::set<u16>::iterator
753 i = removed_objects.begin();
754 i != removed_objects.end(); ++i)
758 ServerActiveObject* obj = m_env->getActiveObject(id);
760 // Add to data buffer for sending
761 writeU16((u8*)buf, id);
762 data_buffer.append(buf, 2);
764 // Remove from known objects
765 client->m_known_objects.erase(id);
767 if(obj && obj->m_known_by_count > 0)
768 obj->m_known_by_count--;
771 // Handle added objects
772 writeU16((u8*)buf, added_objects.size());
773 data_buffer.append(buf, 2);
774 for(std::set<u16>::iterator
775 i = added_objects.begin();
776 i != added_objects.end(); ++i)
780 ServerActiveObject* obj = m_env->getActiveObject(id);
783 u8 type = ACTIVEOBJECT_TYPE_INVALID;
785 infostream<<"WARNING: "<<__FUNCTION_NAME
786 <<": NULL object"<<std::endl;
788 type = obj->getSendType();
790 // Add to data buffer for sending
791 writeU16((u8*)buf, id);
792 data_buffer.append(buf, 2);
793 writeU8((u8*)buf, type);
794 data_buffer.append(buf, 1);
797 data_buffer.append(serializeLongString(
798 obj->getClientInitializationData(client->net_proto_version)));
800 data_buffer.append(serializeLongString(""));
802 // Add to known objects
803 client->m_known_objects.insert(id);
806 obj->m_known_by_count++;
810 SharedBuffer<u8> reply(2 + data_buffer.size());
811 writeU16(&reply[0], TOCLIENT_ACTIVE_OBJECT_REMOVE_ADD);
812 memcpy((char*)&reply[2], data_buffer.c_str(),
815 m_clients.send(client->peer_id, 0, reply, true);
817 verbosestream<<"Server: Sent object remove/add: "
818 <<removed_objects.size()<<" removed, "
819 <<added_objects.size()<<" added, "
820 <<"packet size is "<<reply.getSize()<<std::endl;
825 Collect a list of all the objects known by the clients
826 and report it back to the environment.
829 core::map<u16, bool> all_known_objects;
831 for(core::map<u16, RemoteClient*>::Iterator
832 i = m_clients.getIterator();
833 i.atEnd() == false; i++)
835 RemoteClient *client = i.getNode()->getValue();
836 // Go through all known objects of client
837 for(core::map<u16, bool>::Iterator
838 i = client->m_known_objects.getIterator();
839 i.atEnd()==false; i++)
841 u16 id = i.getNode()->getKey();
842 all_known_objects[id] = true;
846 m_env->setKnownActiveObjects(whatever);
855 JMutexAutoLock envlock(m_env_mutex);
856 ScopeProfiler sp(g_profiler, "Server: sending object messages");
859 // Value = data sent by object
860 std::map<u16, std::list<ActiveObjectMessage>* > buffered_messages;
862 // Get active object messages from environment
865 ActiveObjectMessage aom = m_env->getActiveObjectMessage();
869 std::list<ActiveObjectMessage>* message_list = NULL;
870 std::map<u16, std::list<ActiveObjectMessage>* >::iterator n;
871 n = buffered_messages.find(aom.id);
872 if(n == buffered_messages.end())
874 message_list = new std::list<ActiveObjectMessage>;
875 buffered_messages[aom.id] = message_list;
879 message_list = n->second;
881 message_list->push_back(aom);
885 std::map<u16, RemoteClient*> clients = m_clients.getClientList();
886 // Route data to every client
887 for(std::map<u16, RemoteClient*>::iterator
889 i != clients.end(); ++i)
891 RemoteClient *client = i->second;
892 std::string reliable_data;
893 std::string unreliable_data;
894 // Go through all objects in message buffer
895 for(std::map<u16, std::list<ActiveObjectMessage>* >::iterator
896 j = buffered_messages.begin();
897 j != buffered_messages.end(); ++j)
899 // If object is not known by client, skip it
901 if(client->m_known_objects.find(id) == client->m_known_objects.end())
903 // Get message list of object
904 std::list<ActiveObjectMessage>* list = j->second;
905 // Go through every message
906 for(std::list<ActiveObjectMessage>::iterator
907 k = list->begin(); k != list->end(); ++k)
909 // Compose the full new data with header
910 ActiveObjectMessage aom = *k;
911 std::string new_data;
914 writeU16((u8*)&buf[0], aom.id);
915 new_data.append(buf, 2);
917 new_data += serializeString(aom.datastring);
918 // Add data to buffer
920 reliable_data += new_data;
922 unreliable_data += new_data;
926 reliable_data and unreliable_data are now ready.
929 if(reliable_data.size() > 0)
931 SharedBuffer<u8> reply(2 + reliable_data.size());
932 writeU16(&reply[0], TOCLIENT_ACTIVE_OBJECT_MESSAGES);
933 memcpy((char*)&reply[2], reliable_data.c_str(),
934 reliable_data.size());
936 m_clients.send(client->peer_id, 0, reply, true);
938 if(unreliable_data.size() > 0)
940 SharedBuffer<u8> reply(2 + unreliable_data.size());
941 writeU16(&reply[0], TOCLIENT_ACTIVE_OBJECT_MESSAGES);
942 memcpy((char*)&reply[2], unreliable_data.c_str(),
943 unreliable_data.size());
944 // Send as unreliable
945 m_clients.send(client->peer_id, 1, reply, false);
948 /*if(reliable_data.size() > 0 || unreliable_data.size() > 0)
950 infostream<<"Server: Size of object message data: "
951 <<"reliable: "<<reliable_data.size()
952 <<", unreliable: "<<unreliable_data.size()
958 // Clear buffered_messages
959 for(std::map<u16, std::list<ActiveObjectMessage>* >::iterator
960 i = buffered_messages.begin();
961 i != buffered_messages.end(); ++i)
968 Send queued-for-sending map edit events.
971 // We will be accessing the environment
972 JMutexAutoLock lock(m_env_mutex);
974 // Don't send too many at a time
977 // Single change sending is disabled if queue size is not small
978 bool disable_single_change_sending = false;
979 if(m_unsent_map_edit_queue.size() >= 4)
980 disable_single_change_sending = true;
982 int event_count = m_unsent_map_edit_queue.size();
984 // We'll log the amount of each
987 while(m_unsent_map_edit_queue.size() != 0)
989 MapEditEvent* event = m_unsent_map_edit_queue.pop_front();
991 // Players far away from the change are stored here.
992 // Instead of sending the changes, MapBlocks are set not sent
994 std::list<u16> far_players;
996 if(event->type == MEET_ADDNODE || event->type == MEET_SWAPNODE)
998 //infostream<<"Server: MEET_ADDNODE"<<std::endl;
999 prof.add("MEET_ADDNODE", 1);
1000 if(disable_single_change_sending)
1001 sendAddNode(event->p, event->n, event->already_known_by_peer,
1002 &far_players, 5, event->type == MEET_ADDNODE);
1004 sendAddNode(event->p, event->n, event->already_known_by_peer,
1005 &far_players, 30, event->type == MEET_ADDNODE);
1007 else if(event->type == MEET_REMOVENODE)
1009 //infostream<<"Server: MEET_REMOVENODE"<<std::endl;
1010 prof.add("MEET_REMOVENODE", 1);
1011 if(disable_single_change_sending)
1012 sendRemoveNode(event->p, event->already_known_by_peer,
1015 sendRemoveNode(event->p, event->already_known_by_peer,
1018 else if(event->type == MEET_BLOCK_NODE_METADATA_CHANGED)
1020 infostream<<"Server: MEET_BLOCK_NODE_METADATA_CHANGED"<<std::endl;
1021 prof.add("MEET_BLOCK_NODE_METADATA_CHANGED", 1);
1022 setBlockNotSent(event->p);
1024 else if(event->type == MEET_OTHER)
1026 infostream<<"Server: MEET_OTHER"<<std::endl;
1027 prof.add("MEET_OTHER", 1);
1028 for(std::set<v3s16>::iterator
1029 i = event->modified_blocks.begin();
1030 i != event->modified_blocks.end(); ++i)
1032 setBlockNotSent(*i);
1037 prof.add("unknown", 1);
1038 infostream<<"WARNING: Server: Unknown MapEditEvent "
1039 <<((u32)event->type)<<std::endl;
1043 Set blocks not sent to far players
1045 if(far_players.size() > 0)
1047 // Convert list format to that wanted by SetBlocksNotSent
1048 std::map<v3s16, MapBlock*> modified_blocks2;
1049 for(std::set<v3s16>::iterator
1050 i = event->modified_blocks.begin();
1051 i != event->modified_blocks.end(); ++i)
1053 modified_blocks2[*i] =
1054 m_env->getMap().getBlockNoCreateNoEx(*i);
1056 // Set blocks not sent
1057 for(std::list<u16>::iterator
1058 i = far_players.begin();
1059 i != far_players.end(); ++i)
1062 RemoteClient *client = getClient(peer_id);
1065 client->SetBlocksNotSent(modified_blocks2);
1071 /*// Don't send too many at a time
1073 if(count >= 1 && m_unsent_map_edit_queue.size() < 100)
1077 if(event_count >= 5){
1078 infostream<<"Server: MapEditEvents:"<<std::endl;
1079 prof.print(infostream);
1080 } else if(event_count != 0){
1081 verbosestream<<"Server: MapEditEvents:"<<std::endl;
1082 prof.print(verbosestream);
1088 Trigger emergethread (it somehow gets to a non-triggered but
1089 bysy state sometimes)
1092 float &counter = m_emergethread_trigger_timer;
1098 m_emerge->startThreads();
1100 // Update m_enable_rollback_recording here too
1101 m_enable_rollback_recording =
1102 g_settings->getBool("enable_rollback_recording");
1106 // Save map, players and auth stuff
1108 float &counter = m_savemap_timer;
1110 if(counter >= g_settings->getFloat("server_map_save_interval"))
1113 JMutexAutoLock lock(m_env_mutex);
1115 ScopeProfiler sp(g_profiler, "Server: saving stuff");
1118 if (m_banmanager->isModified()) {
1119 m_banmanager->save();
1122 // Save changed parts of map
1123 m_env->getMap().save(MOD_STATE_WRITE_NEEDED);
1126 m_env->saveLoadedPlayers();
1128 // Save environment metadata
1134 void Server::Receive()
1136 DSTACK(__FUNCTION_NAME);
1137 SharedBuffer<u8> data;
1141 datasize = m_con.Receive(peer_id,data);
1142 ProcessData(*data, datasize, peer_id);
1144 catch(con::InvalidIncomingDataException &e)
1146 infostream<<"Server::Receive(): "
1147 "InvalidIncomingDataException: what()="
1148 <<e.what()<<std::endl;
1150 catch(SerializationError &e) {
1151 infostream<<"Server::Receive(): "
1152 "SerializationError: what()="
1153 <<e.what()<<std::endl;
1155 catch(ClientStateError &e)
1157 errorstream << "ProcessData: peer=" << peer_id << e.what() << std::endl;
1158 DenyAccess(peer_id, L"Your client sent something server didn't expect."
1159 L"Try reconnecting or updating your client");
1161 catch(con::PeerNotFoundException &e)
1167 PlayerSAO* Server::StageTwoClientInit(u16 peer_id)
1169 std::string playername = "";
1170 PlayerSAO *playersao = NULL;
1172 RemoteClient* client = m_clients.lockedGetClientNoEx(peer_id, CS_InitDone);
1173 if (client != NULL) {
1174 playername = client->getName();
1175 playersao = emergePlayer(playername.c_str(), peer_id);
1179 RemotePlayer *player =
1180 static_cast<RemotePlayer*>(m_env->getPlayer(playername.c_str()));
1182 // If failed, cancel
1183 if((playersao == NULL) || (player == NULL))
1185 if(player && player->peer_id != 0){
1186 errorstream<<"Server: "<<playername<<": Failed to emerge player"
1187 <<" (player allocated to an another client)"<<std::endl;
1188 DenyAccess(peer_id, L"Another client is connected with this "
1189 L"name. If your client closed unexpectedly, try again in "
1192 errorstream<<"Server: "<<playername<<": Failed to emerge player"
1194 DenyAccess(peer_id, L"Could not allocate player.");
1200 Send complete position information
1202 SendMovePlayer(peer_id);
1205 SendPlayerPrivileges(peer_id);
1207 // Send inventory formspec
1208 SendPlayerInventoryFormspec(peer_id);
1211 UpdateCrafting(peer_id);
1212 SendInventory(peer_id);
1215 if(g_settings->getBool("enable_damage"))
1216 SendPlayerHP(peer_id);
1219 SendPlayerBreath(peer_id);
1221 // Show death screen if necessary
1223 SendDeathscreen(peer_id, false, v3f(0,0,0));
1225 // Note things in chat if not in simple singleplayer mode
1226 if(!m_simple_singleplayer_mode)
1228 // Send information about server to player in chat
1229 SendChatMessage(peer_id, getStatusString());
1231 // Send information about joining in chat
1233 std::wstring name = L"unknown";
1234 Player *player = m_env->getPlayer(peer_id);
1236 name = narrow_to_wide(player->getName());
1238 std::wstring message;
1241 message += L" joined the game.";
1242 SendChatMessage(PEER_ID_INEXISTENT,message);
1245 Address addr = getPeerAddress(player->peer_id);
1246 std::string ip_str = addr.serializeString();
1247 actionstream<<player->getName() <<" [" << ip_str << "] joins game. " << std::endl;
1252 std::vector<std::string> names = m_clients.getPlayerNames();
1254 actionstream<<player->getName() <<" joins game. List of players: ";
1256 for (std::vector<std::string>::iterator i = names.begin();
1257 i != names.end(); i++)
1259 actionstream << *i << " ";
1262 actionstream << player->getName() <<std::endl;
1267 void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
1269 DSTACK(__FUNCTION_NAME);
1270 // Environment is locked first.
1271 JMutexAutoLock envlock(m_env_mutex);
1273 ScopeProfiler sp(g_profiler, "Server::ProcessData");
1277 Address address = getPeerAddress(peer_id);
1278 addr_s = address.serializeString();
1280 // drop player if is ip is banned
1281 if(m_banmanager->isIpBanned(addr_s)){
1282 std::string ban_name = m_banmanager->getBanName(addr_s);
1283 infostream<<"Server: A banned client tried to connect from "
1284 <<addr_s<<"; banned name was "
1285 <<ban_name<<std::endl;
1286 // This actually doesn't seem to transfer to the client
1287 DenyAccess(peer_id, L"Your ip is banned. Banned name was "
1288 +narrow_to_wide(ban_name));
1292 catch(con::PeerNotFoundException &e)
1295 * no peer for this packet found
1296 * most common reason is peer timeout, e.g. peer didn't
1297 * respond for some time, your server was overloaded or
1300 infostream<<"Server::ProcessData(): Cancelling: peer "
1301 <<peer_id<<" not found"<<std::endl;
1311 ToServerCommand command = (ToServerCommand)readU16(&data[0]);
1313 if(command == TOSERVER_INIT)
1315 // [0] u16 TOSERVER_INIT
1316 // [2] u8 SER_FMT_VER_HIGHEST_READ
1317 // [3] u8[20] player_name
1318 // [23] u8[28] password <--- can be sent without this, from old versions
1320 if(datasize < 2+1+PLAYERNAME_SIZE)
1323 RemoteClient* client = getClient(peer_id, CS_Created);
1325 // If net_proto_version is set, this client has already been handled
1326 if(client->getState() > CS_Created)
1328 verbosestream<<"Server: Ignoring multiple TOSERVER_INITs from "
1329 <<addr_s<<" (peer_id="<<peer_id<<")"<<std::endl;
1333 verbosestream<<"Server: Got TOSERVER_INIT from "<<addr_s<<" (peer_id="
1334 <<peer_id<<")"<<std::endl;
1336 // Do not allow multiple players in simple singleplayer mode.
1337 // This isn't a perfect way to do it, but will suffice for now
1338 if(m_simple_singleplayer_mode && m_clients.getClientIDs().size() > 1){
1339 infostream<<"Server: Not allowing another client ("<<addr_s
1340 <<") to connect in simple singleplayer mode"<<std::endl;
1341 DenyAccess(peer_id, L"Running in simple singleplayer mode.");
1345 // First byte after command is maximum supported
1346 // serialization version
1347 u8 client_max = data[2];
1348 u8 our_max = SER_FMT_VER_HIGHEST_READ;
1349 // Use the highest version supported by both
1350 u8 deployed = std::min(client_max, our_max);
1351 // If it's lower than the lowest supported, give up.
1352 if(deployed < SER_FMT_VER_LOWEST)
1353 deployed = SER_FMT_VER_INVALID;
1355 if(deployed == SER_FMT_VER_INVALID)
1357 actionstream<<"Server: A mismatched client tried to connect from "
1358 <<addr_s<<std::endl;
1359 infostream<<"Server: Cannot negotiate serialization version with "
1360 <<addr_s<<std::endl;
1361 DenyAccess(peer_id, std::wstring(
1362 L"Your client's version is not supported.\n"
1363 L"Server version is ")
1364 + narrow_to_wide(minetest_version_simple) + L"."
1369 client->setPendingSerializationVersion(deployed);
1372 Read and check network protocol version
1375 u16 min_net_proto_version = 0;
1376 if(datasize >= 2+1+PLAYERNAME_SIZE+PASSWORD_SIZE+2)
1377 min_net_proto_version = readU16(&data[2+1+PLAYERNAME_SIZE+PASSWORD_SIZE]);
1379 // Use same version as minimum and maximum if maximum version field
1380 // doesn't exist (backwards compatibility)
1381 u16 max_net_proto_version = min_net_proto_version;
1382 if(datasize >= 2+1+PLAYERNAME_SIZE+PASSWORD_SIZE+2+2)
1383 max_net_proto_version = readU16(&data[2+1+PLAYERNAME_SIZE+PASSWORD_SIZE+2]);
1385 // Start with client's maximum version
1386 u16 net_proto_version = max_net_proto_version;
1388 // Figure out a working version if it is possible at all
1389 if(max_net_proto_version >= SERVER_PROTOCOL_VERSION_MIN ||
1390 min_net_proto_version <= SERVER_PROTOCOL_VERSION_MAX)
1392 // If maximum is larger than our maximum, go with our maximum
1393 if(max_net_proto_version > SERVER_PROTOCOL_VERSION_MAX)
1394 net_proto_version = SERVER_PROTOCOL_VERSION_MAX;
1395 // Else go with client's maximum
1397 net_proto_version = max_net_proto_version;
1400 verbosestream<<"Server: "<<addr_s<<": Protocol version: min: "
1401 <<min_net_proto_version<<", max: "<<max_net_proto_version
1402 <<", chosen: "<<net_proto_version<<std::endl;
1404 client->net_proto_version = net_proto_version;
1406 if(net_proto_version < SERVER_PROTOCOL_VERSION_MIN ||
1407 net_proto_version > SERVER_PROTOCOL_VERSION_MAX)
1409 actionstream<<"Server: A mismatched client tried to connect from "
1410 <<addr_s<<std::endl;
1411 DenyAccess(peer_id, std::wstring(
1412 L"Your client's version is not supported.\n"
1413 L"Server version is ")
1414 + narrow_to_wide(minetest_version_simple) + L",\n"
1415 + L"server's PROTOCOL_VERSION is "
1416 + narrow_to_wide(itos(SERVER_PROTOCOL_VERSION_MIN))
1418 + narrow_to_wide(itos(SERVER_PROTOCOL_VERSION_MAX))
1419 + L", client's PROTOCOL_VERSION is "
1420 + narrow_to_wide(itos(min_net_proto_version))
1422 + narrow_to_wide(itos(max_net_proto_version))
1427 if(g_settings->getBool("strict_protocol_version_checking"))
1429 if(net_proto_version != LATEST_PROTOCOL_VERSION)
1431 actionstream<<"Server: A mismatched (strict) client tried to "
1432 <<"connect from "<<addr_s<<std::endl;
1433 DenyAccess(peer_id, std::wstring(
1434 L"Your client's version is not supported.\n"
1435 L"Server version is ")
1436 + narrow_to_wide(minetest_version_simple) + L",\n"
1437 + L"server's PROTOCOL_VERSION (strict) is "
1438 + narrow_to_wide(itos(LATEST_PROTOCOL_VERSION))
1439 + L", client's PROTOCOL_VERSION is "
1440 + narrow_to_wide(itos(min_net_proto_version))
1442 + narrow_to_wide(itos(max_net_proto_version))
1453 char playername[PLAYERNAME_SIZE];
1454 for(u32 i=0; i<PLAYERNAME_SIZE-1; i++)
1456 playername[i] = data[3+i];
1458 playername[PLAYERNAME_SIZE-1] = 0;
1460 if(playername[0]=='\0')
1462 actionstream<<"Server: Player with an empty name "
1463 <<"tried to connect from "<<addr_s<<std::endl;
1464 DenyAccess(peer_id, L"Empty name");
1468 if(string_allowed(playername, PLAYERNAME_ALLOWED_CHARS)==false)
1470 actionstream<<"Server: Player with an invalid name "
1471 <<"tried to connect from "<<addr_s<<std::endl;
1472 DenyAccess(peer_id, L"Name contains unallowed characters");
1476 if(!isSingleplayer() && strcasecmp(playername, "singleplayer") == 0)
1478 actionstream<<"Server: Player with the name \"singleplayer\" "
1479 <<"tried to connect from "<<addr_s<<std::endl;
1480 DenyAccess(peer_id, L"Name is not allowed");
1486 if(m_script->on_prejoinplayer(playername, addr_s, reason))
1488 actionstream<<"Server: Player with the name \""<<playername<<"\" "
1489 <<"tried to connect from "<<addr_s<<" "
1490 <<"but it was disallowed for the following reason: "
1491 <<reason<<std::endl;
1492 DenyAccess(peer_id, narrow_to_wide(reason.c_str()));
1497 infostream<<"Server: New connection: \""<<playername<<"\" from "
1498 <<addr_s<<" (peer_id="<<peer_id<<")"<<std::endl;
1501 char given_password[PASSWORD_SIZE];
1502 if(datasize < 2+1+PLAYERNAME_SIZE+PASSWORD_SIZE)
1504 // old version - assume blank password
1505 given_password[0] = 0;
1509 for(u32 i=0; i<PASSWORD_SIZE-1; i++)
1511 given_password[i] = data[23+i];
1513 given_password[PASSWORD_SIZE-1] = 0;
1516 if(!base64_is_valid(given_password)){
1517 actionstream<<"Server: "<<playername
1518 <<" supplied invalid password hash"<<std::endl;
1519 DenyAccess(peer_id, L"Invalid password hash");
1523 // Enforce user limit.
1524 // Don't enforce for users that have some admin right
1525 if(m_clients.getClientIDs(CS_Created).size() >= g_settings->getU16("max_users") &&
1526 !checkPriv(playername, "server") &&
1527 !checkPriv(playername, "ban") &&
1528 !checkPriv(playername, "privs") &&
1529 !checkPriv(playername, "password") &&
1530 playername != g_settings->get("name"))
1532 actionstream<<"Server: "<<playername<<" tried to join, but there"
1533 <<" are already max_users="
1534 <<g_settings->getU16("max_users")<<" players."<<std::endl;
1535 DenyAccess(peer_id, L"Too many users.");
1539 std::string checkpwd; // Password hash to check against
1540 bool has_auth = m_script->getAuth(playername, &checkpwd, NULL);
1542 // If no authentication info exists for user, create it
1544 if(!isSingleplayer() &&
1545 g_settings->getBool("disallow_empty_password") &&
1546 std::string(given_password) == ""){
1547 actionstream<<"Server: "<<playername
1548 <<" supplied empty password"<<std::endl;
1549 DenyAccess(peer_id, L"Empty passwords are "
1550 L"disallowed. Set a password and try again.");
1553 std::wstring raw_default_password =
1554 narrow_to_wide(g_settings->get("default_password"));
1555 std::string initial_password =
1556 translatePassword(playername, raw_default_password);
1558 // If default_password is empty, allow any initial password
1559 if (raw_default_password.length() == 0)
1560 initial_password = given_password;
1562 m_script->createAuth(playername, initial_password);
1565 has_auth = m_script->getAuth(playername, &checkpwd, NULL);
1568 actionstream<<"Server: "<<playername<<" cannot be authenticated"
1569 <<" (auth handler does not work?)"<<std::endl;
1570 DenyAccess(peer_id, L"Not allowed to login");
1574 if(given_password != checkpwd){
1575 actionstream<<"Server: "<<playername<<" supplied wrong password"
1577 DenyAccess(peer_id, L"Wrong password");
1581 RemotePlayer *player =
1582 static_cast<RemotePlayer*>(m_env->getPlayer(playername));
1584 if(player && player->peer_id != 0){
1585 errorstream<<"Server: "<<playername<<": Failed to emerge player"
1586 <<" (player allocated to an another client)"<<std::endl;
1587 DenyAccess(peer_id, L"Another client is connected with this "
1588 L"name. If your client closed unexpectedly, try again in "
1592 m_clients.setPlayerName(peer_id,playername);
1595 Answer with a TOCLIENT_INIT
1598 SharedBuffer<u8> reply(2+1+6+8+4);
1599 writeU16(&reply[0], TOCLIENT_INIT);
1600 writeU8(&reply[2], deployed);
1601 //send dummy pos for legacy reasons only
1602 writeV3S16(&reply[2+1], floatToInt(v3f(0,0,0), BS));
1603 writeU64(&reply[2+1+6], m_env->getServerMap().getSeed());
1604 writeF1000(&reply[2+1+6+8], g_settings->getFloat("dedicated_server_step"));
1607 m_clients.send(peer_id, 0, reply, true);
1608 m_clients.event(peer_id, CSE_Init);
1614 if(command == TOSERVER_INIT2)
1617 verbosestream<<"Server: Got TOSERVER_INIT2 from "
1618 <<peer_id<<std::endl;
1620 m_clients.event(peer_id, CSE_GotInit2);
1621 u16 protocol_version = m_clients.getProtocolVersion(peer_id);
1624 ///// begin compatibility code
1625 PlayerSAO* playersao = NULL;
1626 if (protocol_version <= 22) {
1627 playersao = StageTwoClientInit(peer_id);
1629 if (playersao == NULL) {
1631 << "TOSERVER_INIT2 stage 2 client init failed for peer "
1632 << peer_id << std::endl;
1636 ///// end compatibility code
1639 Send some initialization data
1642 infostream<<"Server: Sending content to "
1643 <<getPlayerName(peer_id)<<std::endl;
1645 // Send player movement settings
1646 SendMovement(peer_id);
1648 // Send item definitions
1649 SendItemDef(peer_id, m_itemdef, protocol_version);
1651 // Send node definitions
1652 SendNodeDef(peer_id, m_nodedef, protocol_version);
1654 m_clients.event(peer_id, CSE_SetDefinitionsSent);
1656 // Send media announcement
1657 sendMediaAnnouncement(peer_id);
1659 // Send detached inventories
1660 sendDetachedInventories(peer_id);
1663 u16 time = m_env->getTimeOfDay();
1664 float time_speed = g_settings->getFloat("time_speed");
1665 SendTimeOfDay(peer_id, time, time_speed);
1667 ///// begin compatibility code
1668 if (protocol_version <= 22) {
1669 m_clients.event(peer_id, CSE_SetClientReady);
1670 m_script->on_joinplayer(playersao);
1672 ///// end compatibility code
1674 // Warnings about protocol version can be issued here
1675 if(getClient(peer_id)->net_proto_version < LATEST_PROTOCOL_VERSION)
1677 SendChatMessage(peer_id, L"# Server: WARNING: YOUR CLIENT'S "
1678 L"VERSION MAY NOT BE FULLY COMPATIBLE WITH THIS SERVER!");
1684 u8 peer_ser_ver = getClient(peer_id, CS_InitDone)->serialization_version;
1685 u16 peer_proto_ver = getClient(peer_id, CS_InitDone)->net_proto_version;
1687 if(peer_ser_ver == SER_FMT_VER_INVALID)
1689 errorstream<<"Server::ProcessData(): Cancelling: Peer"
1690 " serialization format invalid or not initialized."
1691 " Skipping incoming command="<<command<<std::endl;
1695 /* Handle commands relate to client startup */
1696 if(command == TOSERVER_REQUEST_MEDIA) {
1697 std::string datastring((char*)&data[2], datasize-2);
1698 std::istringstream is(datastring, std::ios_base::binary);
1700 std::list<std::string> tosend;
1701 u16 numfiles = readU16(is);
1703 infostream<<"Sending "<<numfiles<<" files to "
1704 <<getPlayerName(peer_id)<<std::endl;
1705 verbosestream<<"TOSERVER_REQUEST_MEDIA: "<<std::endl;
1707 for(int i = 0; i < numfiles; i++) {
1708 std::string name = deSerializeString(is);
1709 tosend.push_back(name);
1710 verbosestream<<"TOSERVER_REQUEST_MEDIA: requested file "
1714 sendRequestedMedia(peer_id, tosend);
1717 else if(command == TOSERVER_RECEIVED_MEDIA) {
1720 else if(command == TOSERVER_CLIENT_READY) {
1721 // clients <= protocol version 22 did not send ready message,
1722 // they're already initialized
1723 if (peer_proto_ver <= 22) {
1724 infostream << "Client sent message not expected by a "
1725 << "client using protocol version <= 22,"
1726 << "disconnecing peer_id: " << peer_id << std::endl;
1727 m_con.DisconnectPeer(peer_id);
1731 PlayerSAO* playersao = StageTwoClientInit(peer_id);
1733 if (playersao == NULL) {
1735 << "TOSERVER_CLIENT_READY stage 2 client init failed for peer_id: "
1736 << peer_id << std::endl;
1737 m_con.DisconnectPeer(peer_id);
1742 if(datasize < 2+8) {
1744 << "TOSERVER_CLIENT_READY client sent inconsistent data, disconnecting peer_id: "
1745 << peer_id << std::endl;
1746 m_con.DisconnectPeer(peer_id);
1750 m_clients.setClientVersion(
1752 data[2], data[3], data[4],
1753 std::string((char*) &data[8],(u16) data[6]));
1755 m_clients.event(peer_id, CSE_SetClientReady);
1756 m_script->on_joinplayer(playersao);
1759 else if(command == TOSERVER_GOTBLOCKS)
1772 u16 count = data[2];
1773 for(u16 i=0; i<count; i++)
1775 if((s16)datasize < 2+1+(i+1)*6)
1776 throw con::InvalidIncomingDataException
1777 ("GOTBLOCKS length is too short");
1778 v3s16 p = readV3S16(&data[2+1+i*6]);
1779 /*infostream<<"Server: GOTBLOCKS ("
1780 <<p.X<<","<<p.Y<<","<<p.Z<<")"<<std::endl;*/
1781 RemoteClient *client = getClient(peer_id);
1782 client->GotBlock(p);
1787 if (m_clients.getClientState(peer_id) < CS_Active)
1789 if (command == TOSERVER_PLAYERPOS) return;
1791 errorstream<<"Got packet command: " << command << " for peer id "
1792 << peer_id << " but client isn't active yet. Dropping packet "
1797 Player *player = m_env->getPlayer(peer_id);
1798 if(player == NULL) {
1799 errorstream<<"Server::ProcessData(): Cancelling: "
1800 "No player for peer_id="<<peer_id
1801 << " disconnecting peer!" <<std::endl;
1802 m_con.DisconnectPeer(peer_id);
1806 PlayerSAO *playersao = player->getPlayerSAO();
1807 if(playersao == NULL) {
1808 errorstream<<"Server::ProcessData(): Cancelling: "
1809 "No player object for peer_id="<<peer_id
1810 << " disconnecting peer!" <<std::endl;
1811 m_con.DisconnectPeer(peer_id);
1815 if(command == TOSERVER_PLAYERPOS)
1817 if(datasize < 2+12+12+4+4)
1821 v3s32 ps = readV3S32(&data[start+2]);
1822 v3s32 ss = readV3S32(&data[start+2+12]);
1823 f32 pitch = (f32)readS32(&data[2+12+12]) / 100.0;
1824 f32 yaw = (f32)readS32(&data[2+12+12+4]) / 100.0;
1826 if(datasize >= 2+12+12+4+4+4)
1827 keyPressed = (u32)readU32(&data[2+12+12+4+4]);
1828 v3f position((f32)ps.X/100., (f32)ps.Y/100., (f32)ps.Z/100.);
1829 v3f speed((f32)ss.X/100., (f32)ss.Y/100., (f32)ss.Z/100.);
1830 pitch = wrapDegrees(pitch);
1831 yaw = wrapDegrees(yaw);
1833 player->setPosition(position);
1834 player->setSpeed(speed);
1835 player->setPitch(pitch);
1836 player->setYaw(yaw);
1837 player->keyPressed=keyPressed;
1838 player->control.up = (bool)(keyPressed&1);
1839 player->control.down = (bool)(keyPressed&2);
1840 player->control.left = (bool)(keyPressed&4);
1841 player->control.right = (bool)(keyPressed&8);
1842 player->control.jump = (bool)(keyPressed&16);
1843 player->control.aux1 = (bool)(keyPressed&32);
1844 player->control.sneak = (bool)(keyPressed&64);
1845 player->control.LMB = (bool)(keyPressed&128);
1846 player->control.RMB = (bool)(keyPressed&256);
1848 bool cheated = playersao->checkMovementCheat();
1851 m_script->on_cheat(playersao, "moved_too_fast");
1854 /*infostream<<"Server::ProcessData(): Moved player "<<peer_id<<" to "
1855 <<"("<<position.X<<","<<position.Y<<","<<position.Z<<")"
1856 <<" pitch="<<pitch<<" yaw="<<yaw<<std::endl;*/
1858 else if(command == TOSERVER_DELETEDBLOCKS)
1871 u16 count = data[2];
1872 for(u16 i=0; i<count; i++)
1874 if((s16)datasize < 2+1+(i+1)*6)
1875 throw con::InvalidIncomingDataException
1876 ("DELETEDBLOCKS length is too short");
1877 v3s16 p = readV3S16(&data[2+1+i*6]);
1878 /*infostream<<"Server: DELETEDBLOCKS ("
1879 <<p.X<<","<<p.Y<<","<<p.Z<<")"<<std::endl;*/
1880 RemoteClient *client = getClient(peer_id);
1881 client->SetBlockNotSent(p);
1884 else if(command == TOSERVER_CLICK_OBJECT)
1886 infostream<<"Server: CLICK_OBJECT not supported anymore"<<std::endl;
1889 else if(command == TOSERVER_CLICK_ACTIVEOBJECT)
1891 infostream<<"Server: CLICK_ACTIVEOBJECT not supported anymore"<<std::endl;
1894 else if(command == TOSERVER_GROUND_ACTION)
1896 infostream<<"Server: GROUND_ACTION not supported anymore"<<std::endl;
1900 else if(command == TOSERVER_RELEASE)
1902 infostream<<"Server: RELEASE not supported anymore"<<std::endl;
1905 else if(command == TOSERVER_SIGNTEXT)
1907 infostream<<"Server: SIGNTEXT not supported anymore"
1911 else if(command == TOSERVER_SIGNNODETEXT)
1913 infostream<<"Server: SIGNNODETEXT not supported anymore"
1917 else if(command == TOSERVER_INVENTORY_ACTION)
1919 // Strip command and create a stream
1920 std::string datastring((char*)&data[2], datasize-2);
1921 verbosestream<<"TOSERVER_INVENTORY_ACTION: data="<<datastring<<std::endl;
1922 std::istringstream is(datastring, std::ios_base::binary);
1924 InventoryAction *a = InventoryAction::deSerialize(is);
1927 infostream<<"TOSERVER_INVENTORY_ACTION: "
1928 <<"InventoryAction::deSerialize() returned NULL"
1933 // If something goes wrong, this player is to blame
1934 RollbackScopeActor rollback_scope(m_rollback,
1935 std::string("player:")+player->getName());
1938 Note: Always set inventory not sent, to repair cases
1939 where the client made a bad prediction.
1943 Handle restrictions and special cases of the move action
1945 if(a->getType() == IACTION_MOVE)
1947 IMoveAction *ma = (IMoveAction*)a;
1949 ma->from_inv.applyCurrentPlayer(player->getName());
1950 ma->to_inv.applyCurrentPlayer(player->getName());
1952 setInventoryModified(ma->from_inv);
1953 setInventoryModified(ma->to_inv);
1955 bool from_inv_is_current_player =
1956 (ma->from_inv.type == InventoryLocation::PLAYER) &&
1957 (ma->from_inv.name == player->getName());
1959 bool to_inv_is_current_player =
1960 (ma->to_inv.type == InventoryLocation::PLAYER) &&
1961 (ma->to_inv.name == player->getName());
1964 Disable moving items out of craftpreview
1966 if(ma->from_list == "craftpreview")
1968 infostream<<"Ignoring IMoveAction from "
1969 <<(ma->from_inv.dump())<<":"<<ma->from_list
1970 <<" to "<<(ma->to_inv.dump())<<":"<<ma->to_list
1971 <<" because src is "<<ma->from_list<<std::endl;
1977 Disable moving items into craftresult and craftpreview
1979 if(ma->to_list == "craftpreview" || ma->to_list == "craftresult")
1981 infostream<<"Ignoring IMoveAction from "
1982 <<(ma->from_inv.dump())<<":"<<ma->from_list
1983 <<" to "<<(ma->to_inv.dump())<<":"<<ma->to_list
1984 <<" because dst is "<<ma->to_list<<std::endl;
1989 // Disallow moving items in elsewhere than player's inventory
1990 // if not allowed to interact
1991 if(!checkPriv(player->getName(), "interact") &&
1992 (!from_inv_is_current_player ||
1993 !to_inv_is_current_player))
1995 infostream<<"Cannot move outside of player's inventory: "
1996 <<"No interact privilege"<<std::endl;
2002 Handle restrictions and special cases of the drop action
2004 else if(a->getType() == IACTION_DROP)
2006 IDropAction *da = (IDropAction*)a;
2008 da->from_inv.applyCurrentPlayer(player->getName());
2010 setInventoryModified(da->from_inv);
2013 Disable dropping items out of craftpreview
2015 if(da->from_list == "craftpreview")
2017 infostream<<"Ignoring IDropAction from "
2018 <<(da->from_inv.dump())<<":"<<da->from_list
2019 <<" because src is "<<da->from_list<<std::endl;
2024 // Disallow dropping items if not allowed to interact
2025 if(!checkPriv(player->getName(), "interact"))
2032 Handle restrictions and special cases of the craft action
2034 else if(a->getType() == IACTION_CRAFT)
2036 ICraftAction *ca = (ICraftAction*)a;
2038 ca->craft_inv.applyCurrentPlayer(player->getName());
2040 setInventoryModified(ca->craft_inv);
2042 //bool craft_inv_is_current_player =
2043 // (ca->craft_inv.type == InventoryLocation::PLAYER) &&
2044 // (ca->craft_inv.name == player->getName());
2046 // Disallow crafting if not allowed to interact
2047 if(!checkPriv(player->getName(), "interact"))
2049 infostream<<"Cannot craft: "
2050 <<"No interact privilege"<<std::endl;
2057 a->apply(this, playersao, this);
2061 else if(command == TOSERVER_CHAT_MESSAGE)
2069 std::string datastring((char*)&data[2], datasize-2);
2070 std::istringstream is(datastring, std::ios_base::binary);
2073 is.read((char*)buf, 2);
2074 u16 len = readU16(buf);
2076 std::wstring message;
2077 for(u16 i=0; i<len; i++)
2079 is.read((char*)buf, 2);
2080 message += (wchar_t)readU16(buf);
2083 // If something goes wrong, this player is to blame
2084 RollbackScopeActor rollback_scope(m_rollback,
2085 std::string("player:")+player->getName());
2087 // Get player name of this client
2088 std::wstring name = narrow_to_wide(player->getName());
2091 bool ate = m_script->on_chat_message(player->getName(),
2092 wide_to_narrow(message));
2093 // If script ate the message, don't proceed
2097 // Line to send to players
2099 // Whether to send to the player that sent the line
2100 bool send_to_sender_only = false;
2102 // Commands are implemented in Lua, so only catch invalid
2103 // commands that were not "eaten" and send an error back
2104 if(message[0] == L'/')
2106 message = message.substr(1);
2107 send_to_sender_only = true;
2108 if(message.length() == 0)
2109 line += L"-!- Empty command";
2111 line += L"-!- Invalid command: " + str_split(message, L' ')[0];
2115 if(checkPriv(player->getName(), "shout")){
2121 line += L"-!- You don't have permission to shout.";
2122 send_to_sender_only = true;
2129 Send the message to sender
2131 if (send_to_sender_only)
2133 SendChatMessage(peer_id, line);
2136 Send the message to others
2140 actionstream<<"CHAT: "<<wide_to_narrow(line)<<std::endl;
2142 std::list<u16> clients = m_clients.getClientIDs();
2144 for(std::list<u16>::iterator
2145 i = clients.begin();
2146 i != clients.end(); ++i)
2149 SendChatMessage(*i, line);
2154 else if(command == TOSERVER_DAMAGE)
2156 std::string datastring((char*)&data[2], datasize-2);
2157 std::istringstream is(datastring, std::ios_base::binary);
2158 u8 damage = readU8(is);
2160 if(g_settings->getBool("enable_damage"))
2162 actionstream<<player->getName()<<" damaged by "
2163 <<(int)damage<<" hp at "<<PP(player->getPosition()/BS)
2166 playersao->setHP(playersao->getHP() - damage);
2168 if(playersao->getHP() == 0 && playersao->m_hp_not_sent)
2171 if(playersao->m_hp_not_sent)
2172 SendPlayerHP(peer_id);
2175 else if(command == TOSERVER_BREATH)
2177 std::string datastring((char*)&data[2], datasize-2);
2178 std::istringstream is(datastring, std::ios_base::binary);
2179 u16 breath = readU16(is);
2180 playersao->setBreath(breath);
2181 m_script->player_event(playersao,"breath_changed");
2183 else if(command == TOSERVER_PASSWORD)
2186 [0] u16 TOSERVER_PASSWORD
2187 [2] u8[28] old password
2188 [30] u8[28] new password
2191 if(datasize != 2+PASSWORD_SIZE*2)
2193 /*char password[PASSWORD_SIZE];
2194 for(u32 i=0; i<PASSWORD_SIZE-1; i++)
2195 password[i] = data[2+i];
2196 password[PASSWORD_SIZE-1] = 0;*/
2198 for(u32 i=0; i<PASSWORD_SIZE-1; i++)
2206 for(u32 i=0; i<PASSWORD_SIZE-1; i++)
2208 char c = data[2+PASSWORD_SIZE+i];
2214 if(!base64_is_valid(newpwd)){
2215 infostream<<"Server: "<<player->getName()<<" supplied invalid password hash"<<std::endl;
2216 // Wrong old password supplied!!
2217 SendChatMessage(peer_id, L"Invalid new password hash supplied. Password NOT changed.");
2221 infostream<<"Server: Client requests a password change from "
2222 <<"'"<<oldpwd<<"' to '"<<newpwd<<"'"<<std::endl;
2224 std::string playername = player->getName();
2226 std::string checkpwd;
2227 m_script->getAuth(playername, &checkpwd, NULL);
2229 if(oldpwd != checkpwd)
2231 infostream<<"Server: invalid old password"<<std::endl;
2232 // Wrong old password supplied!!
2233 SendChatMessage(peer_id, L"Invalid old password supplied. Password NOT changed.");
2237 bool success = m_script->setPassword(playername, newpwd);
2239 actionstream<<player->getName()<<" changes password"<<std::endl;
2240 SendChatMessage(peer_id, L"Password change successful.");
2242 actionstream<<player->getName()<<" tries to change password but "
2243 <<"it fails"<<std::endl;
2244 SendChatMessage(peer_id, L"Password change failed or inavailable.");
2247 else if(command == TOSERVER_PLAYERITEM)
2252 u16 item = readU16(&data[2]);
2253 playersao->setWieldIndex(item);
2255 else if(command == TOSERVER_RESPAWN)
2257 if(player->hp != 0 || !g_settings->getBool("enable_damage"))
2260 RespawnPlayer(peer_id);
2262 actionstream<<player->getName()<<" respawns at "
2263 <<PP(player->getPosition()/BS)<<std::endl;
2265 // ActiveObject is added to environment in AsyncRunStep after
2266 // the previous addition has been succesfully removed
2268 else if(command == TOSERVER_INTERACT)
2270 std::string datastring((char*)&data[2], datasize-2);
2271 std::istringstream is(datastring, std::ios_base::binary);
2277 [5] u32 length of the next item
2278 [9] serialized PointedThing
2280 0: start digging (from undersurface) or use
2281 1: stop digging (all parameters ignored)
2282 2: digging completed
2283 3: place block or item (to abovesurface)
2286 u8 action = readU8(is);
2287 u16 item_i = readU16(is);
2288 std::istringstream tmp_is(deSerializeLongString(is), std::ios::binary);
2289 PointedThing pointed;
2290 pointed.deSerialize(tmp_is);
2292 verbosestream<<"TOSERVER_INTERACT: action="<<(int)action<<", item="
2293 <<item_i<<", pointed="<<pointed.dump()<<std::endl;
2297 verbosestream<<"TOSERVER_INTERACT: "<<player->getName()
2298 <<" tried to interact, but is dead!"<<std::endl;
2302 v3f player_pos = playersao->getLastGoodPosition();
2304 // Update wielded item
2305 playersao->setWieldIndex(item_i);
2307 // Get pointed to node (undefined if not POINTEDTYPE_NODE)
2308 v3s16 p_under = pointed.node_undersurface;
2309 v3s16 p_above = pointed.node_abovesurface;
2311 // Get pointed to object (NULL if not POINTEDTYPE_OBJECT)
2312 ServerActiveObject *pointed_object = NULL;
2313 if(pointed.type == POINTEDTHING_OBJECT)
2315 pointed_object = m_env->getActiveObject(pointed.object_id);
2316 if(pointed_object == NULL)
2318 verbosestream<<"TOSERVER_INTERACT: "
2319 "pointed object is NULL"<<std::endl;
2325 v3f pointed_pos_under = player_pos;
2326 v3f pointed_pos_above = player_pos;
2327 if(pointed.type == POINTEDTHING_NODE)
2329 pointed_pos_under = intToFloat(p_under, BS);
2330 pointed_pos_above = intToFloat(p_above, BS);
2332 else if(pointed.type == POINTEDTHING_OBJECT)
2334 pointed_pos_under = pointed_object->getBasePosition();
2335 pointed_pos_above = pointed_pos_under;
2339 Check that target is reasonably close
2340 (only when digging or placing things)
2342 if(action == 0 || action == 2 || action == 3)
2344 float d = player_pos.getDistanceFrom(pointed_pos_under);
2345 float max_d = BS * 14; // Just some large enough value
2347 actionstream<<"Player "<<player->getName()
2348 <<" tried to access "<<pointed.dump()
2350 <<"d="<<d<<", max_d="<<max_d
2351 <<". ignoring."<<std::endl;
2352 // Re-send block to revert change on client-side
2353 RemoteClient *client = getClient(peer_id);
2354 v3s16 blockpos = getNodeBlockPos(floatToInt(pointed_pos_under, BS));
2355 client->SetBlockNotSent(blockpos);
2357 m_script->on_cheat(playersao, "interacted_too_far");
2364 Make sure the player is allowed to do it
2366 if(!checkPriv(player->getName(), "interact"))
2368 actionstream<<player->getName()<<" attempted to interact with "
2369 <<pointed.dump()<<" without 'interact' privilege"
2371 // Re-send block to revert change on client-side
2372 RemoteClient *client = getClient(peer_id);
2373 // Digging completed -> under
2375 v3s16 blockpos = getNodeBlockPos(floatToInt(pointed_pos_under, BS));
2376 client->SetBlockNotSent(blockpos);
2378 // Placement -> above
2380 v3s16 blockpos = getNodeBlockPos(floatToInt(pointed_pos_above, BS));
2381 client->SetBlockNotSent(blockpos);
2387 If something goes wrong, this player is to blame
2389 RollbackScopeActor rollback_scope(m_rollback,
2390 std::string("player:")+player->getName());
2393 0: start digging or punch object
2397 if(pointed.type == POINTEDTHING_NODE)
2400 NOTE: This can be used in the future to check if
2401 somebody is cheating, by checking the timing.
2403 MapNode n(CONTENT_IGNORE);
2406 n = m_env->getMap().getNode(p_under);
2408 catch(InvalidPositionException &e)
2410 infostream<<"Server: Not punching: Node not found."
2411 <<" Adding block to emerge queue."
2413 m_emerge->enqueueBlockEmerge(peer_id, getNodeBlockPos(p_above), false);
2415 if(n.getContent() != CONTENT_IGNORE)
2416 m_script->node_on_punch(p_under, n, playersao, pointed);
2418 playersao->noCheatDigStart(p_under);
2420 else if(pointed.type == POINTEDTHING_OBJECT)
2422 // Skip if object has been removed
2423 if(pointed_object->m_removed)
2426 actionstream<<player->getName()<<" punches object "
2427 <<pointed.object_id<<": "
2428 <<pointed_object->getDescription()<<std::endl;
2430 ItemStack punchitem = playersao->getWieldedItem();
2431 ToolCapabilities toolcap =
2432 punchitem.getToolCapabilities(m_itemdef);
2433 v3f dir = (pointed_object->getBasePosition() -
2434 (player->getPosition() + player->getEyeOffset())
2436 float time_from_last_punch =
2437 playersao->resetTimeFromLastPunch();
2438 pointed_object->punch(dir, &toolcap, playersao,
2439 time_from_last_punch);
2447 else if(action == 1)
2452 2: Digging completed
2454 else if(action == 2)
2456 // Only digging of nodes
2457 if(pointed.type == POINTEDTHING_NODE)
2459 MapNode n(CONTENT_IGNORE);
2462 n = m_env->getMap().getNode(p_under);
2464 catch(InvalidPositionException &e)
2466 infostream<<"Server: Not finishing digging: Node not found."
2467 <<" Adding block to emerge queue."
2469 m_emerge->enqueueBlockEmerge(peer_id, getNodeBlockPos(p_above), false);
2472 /* Cheat prevention */
2473 bool is_valid_dig = true;
2474 if(!isSingleplayer() && !g_settings->getBool("disable_anticheat"))
2476 v3s16 nocheat_p = playersao->getNoCheatDigPos();
2477 float nocheat_t = playersao->getNoCheatDigTime();
2478 playersao->noCheatDigEnd();
2479 // If player didn't start digging this, ignore dig
2480 if(nocheat_p != p_under){
2481 infostream<<"Server: NoCheat: "<<player->getName()
2482 <<" started digging "
2483 <<PP(nocheat_p)<<" and completed digging "
2484 <<PP(p_under)<<"; not digging."<<std::endl;
2485 is_valid_dig = false;
2487 m_script->on_cheat(playersao, "finished_unknown_dig");
2489 // Get player's wielded item
2490 ItemStack playeritem;
2491 InventoryList *mlist = playersao->getInventory()->getList("main");
2493 playeritem = mlist->getItem(playersao->getWieldIndex());
2494 ToolCapabilities playeritem_toolcap =
2495 playeritem.getToolCapabilities(m_itemdef);
2496 // Get diggability and expected digging time
2497 DigParams params = getDigParams(m_nodedef->get(n).groups,
2498 &playeritem_toolcap);
2499 // If can't dig, try hand
2500 if(!params.diggable){
2501 const ItemDefinition &hand = m_itemdef->get("");
2502 const ToolCapabilities *tp = hand.tool_capabilities;
2504 params = getDigParams(m_nodedef->get(n).groups, tp);
2506 // If can't dig, ignore dig
2507 if(!params.diggable){
2508 infostream<<"Server: NoCheat: "<<player->getName()
2509 <<" completed digging "<<PP(p_under)
2510 <<", which is not diggable with tool. not digging."
2512 is_valid_dig = false;
2514 m_script->on_cheat(playersao, "dug_unbreakable");
2516 // Check digging time
2517 // If already invalidated, we don't have to
2519 // Well not our problem then
2521 // Clean and long dig
2522 else if(params.time > 2.0 && nocheat_t * 1.2 > params.time){
2523 // All is good, but grab time from pool; don't care if
2524 // it's actually available
2525 playersao->getDigPool().grab(params.time);
2527 // Short or laggy dig
2528 // Try getting the time from pool
2529 else if(playersao->getDigPool().grab(params.time)){
2534 infostream<<"Server: NoCheat: "<<player->getName()
2535 <<" completed digging "<<PP(p_under)
2536 <<"too fast; not digging."<<std::endl;
2537 is_valid_dig = false;
2539 m_script->on_cheat(playersao, "dug_too_fast");
2543 /* Actually dig node */
2545 if(is_valid_dig && n.getContent() != CONTENT_IGNORE)
2546 m_script->node_on_dig(p_under, n, playersao);
2548 v3s16 blockpos = getNodeBlockPos(floatToInt(pointed_pos_under, BS));
2549 RemoteClient *client = getClient(peer_id);
2550 // Send unusual result (that is, node not being removed)
2551 if(m_env->getMap().getNodeNoEx(p_under).getContent() != CONTENT_AIR)
2553 // Re-send block to revert change on client-side
2554 client->SetBlockNotSent(blockpos);
2557 client->ResendBlockIfOnWire(blockpos);
2563 3: place block or right-click object
2565 else if(action == 3)
2567 ItemStack item = playersao->getWieldedItem();
2569 // Reset build time counter
2570 if(pointed.type == POINTEDTHING_NODE &&
2571 item.getDefinition(m_itemdef).type == ITEM_NODE)
2572 getClient(peer_id)->m_time_from_building = 0.0;
2574 if(pointed.type == POINTEDTHING_OBJECT)
2576 // Right click object
2578 // Skip if object has been removed
2579 if(pointed_object->m_removed)
2582 actionstream<<player->getName()<<" right-clicks object "
2583 <<pointed.object_id<<": "
2584 <<pointed_object->getDescription()<<std::endl;
2587 pointed_object->rightClick(playersao);
2589 else if(m_script->item_OnPlace(
2590 item, playersao, pointed))
2592 // Placement was handled in lua
2594 // Apply returned ItemStack
2595 playersao->setWieldedItem(item);
2598 // If item has node placement prediction, always send the
2599 // blocks to make sure the client knows what exactly happened
2600 RemoteClient *client = getClient(peer_id);
2601 v3s16 blockpos = getNodeBlockPos(floatToInt(pointed_pos_above, BS));
2602 v3s16 blockpos2 = getNodeBlockPos(floatToInt(pointed_pos_under, BS));
2603 if(item.getDefinition(m_itemdef).node_placement_prediction != "") {
2604 client->SetBlockNotSent(blockpos);
2605 if(blockpos2 != blockpos) {
2606 client->SetBlockNotSent(blockpos2);
2610 client->ResendBlockIfOnWire(blockpos);
2611 if(blockpos2 != blockpos) {
2612 client->ResendBlockIfOnWire(blockpos2);
2620 else if(action == 4)
2622 ItemStack item = playersao->getWieldedItem();
2624 actionstream<<player->getName()<<" uses "<<item.name
2625 <<", pointing at "<<pointed.dump()<<std::endl;
2627 if(m_script->item_OnUse(
2628 item, playersao, pointed))
2630 // Apply returned ItemStack
2631 playersao->setWieldedItem(item);
2638 Catch invalid actions
2642 infostream<<"WARNING: Server: Invalid action "
2643 <<action<<std::endl;
2646 else if(command == TOSERVER_REMOVED_SOUNDS)
2648 std::string datastring((char*)&data[2], datasize-2);
2649 std::istringstream is(datastring, std::ios_base::binary);
2651 int num = readU16(is);
2652 for(int k=0; k<num; k++){
2653 s32 id = readS32(is);
2654 std::map<s32, ServerPlayingSound>::iterator i =
2655 m_playing_sounds.find(id);
2656 if(i == m_playing_sounds.end())
2658 ServerPlayingSound &psound = i->second;
2659 psound.clients.erase(peer_id);
2660 if(psound.clients.size() == 0)
2661 m_playing_sounds.erase(i++);
2664 else if(command == TOSERVER_NODEMETA_FIELDS)
2666 std::string datastring((char*)&data[2], datasize-2);
2667 std::istringstream is(datastring, std::ios_base::binary);
2669 v3s16 p = readV3S16(is);
2670 std::string formname = deSerializeString(is);
2671 int num = readU16(is);
2672 std::map<std::string, std::string> fields;
2673 for(int k=0; k<num; k++){
2674 std::string fieldname = deSerializeString(is);
2675 std::string fieldvalue = deSerializeLongString(is);
2676 fields[fieldname] = fieldvalue;
2679 // If something goes wrong, this player is to blame
2680 RollbackScopeActor rollback_scope(m_rollback,
2681 std::string("player:")+player->getName());
2683 // Check the target node for rollback data; leave others unnoticed
2684 RollbackNode rn_old(&m_env->getMap(), p, this);
2686 m_script->node_on_receive_fields(p, formname, fields,playersao);
2688 // Report rollback data
2689 RollbackNode rn_new(&m_env->getMap(), p, this);
2690 if(rollback() && rn_new != rn_old){
2691 RollbackAction action;
2692 action.setSetNode(p, rn_old, rn_new);
2693 rollback()->reportAction(action);
2696 else if(command == TOSERVER_INVENTORY_FIELDS)
2698 std::string datastring((char*)&data[2], datasize-2);
2699 std::istringstream is(datastring, std::ios_base::binary);
2701 std::string formname = deSerializeString(is);
2702 int num = readU16(is);
2703 std::map<std::string, std::string> fields;
2704 for(int k=0; k<num; k++){
2705 std::string fieldname = deSerializeString(is);
2706 std::string fieldvalue = deSerializeLongString(is);
2707 fields[fieldname] = fieldvalue;
2710 m_script->on_playerReceiveFields(playersao, formname, fields);
2714 infostream<<"Server::ProcessData(): Ignoring "
2715 "unknown command "<<command<<std::endl;
2719 catch(SendFailedException &e)
2721 errorstream<<"Server::ProcessData(): SendFailedException: "
2727 void Server::setTimeOfDay(u32 time)
2729 m_env->setTimeOfDay(time);
2730 m_time_of_day_send_timer = 0;
2733 void Server::onMapEditEvent(MapEditEvent *event)
2735 //infostream<<"Server::onMapEditEvent()"<<std::endl;
2736 if(m_ignore_map_edit_events)
2738 if(m_ignore_map_edit_events_area.contains(event->getArea()))
2740 MapEditEvent *e = event->clone();
2741 m_unsent_map_edit_queue.push_back(e);
2744 Inventory* Server::getInventory(const InventoryLocation &loc)
2747 case InventoryLocation::UNDEFINED:
2750 case InventoryLocation::CURRENT_PLAYER:
2753 case InventoryLocation::PLAYER:
2755 Player *player = m_env->getPlayer(loc.name.c_str());
2758 PlayerSAO *playersao = player->getPlayerSAO();
2761 return playersao->getInventory();
2764 case InventoryLocation::NODEMETA:
2766 NodeMetadata *meta = m_env->getMap().getNodeMetadata(loc.p);
2769 return meta->getInventory();
2772 case InventoryLocation::DETACHED:
2774 if(m_detached_inventories.count(loc.name) == 0)
2776 return m_detached_inventories[loc.name];
2784 void Server::setInventoryModified(const InventoryLocation &loc)
2787 case InventoryLocation::UNDEFINED:
2790 case InventoryLocation::PLAYER:
2792 Player *player = m_env->getPlayer(loc.name.c_str());
2795 PlayerSAO *playersao = player->getPlayerSAO();
2798 playersao->m_inventory_not_sent = true;
2799 playersao->m_wielded_item_not_sent = true;
2802 case InventoryLocation::NODEMETA:
2804 v3s16 blockpos = getNodeBlockPos(loc.p);
2806 MapBlock *block = m_env->getMap().getBlockNoCreateNoEx(blockpos);
2808 block->raiseModified(MOD_STATE_WRITE_NEEDED);
2810 setBlockNotSent(blockpos);
2813 case InventoryLocation::DETACHED:
2815 sendDetachedInventory(loc.name,PEER_ID_INEXISTENT);
2823 void Server::SetBlocksNotSent(std::map<v3s16, MapBlock *>& block)
2825 std::list<u16> clients = m_clients.getClientIDs();
2827 // Set the modified blocks unsent for all the clients
2828 for (std::list<u16>::iterator
2829 i = clients.begin();
2830 i != clients.end(); ++i) {
2831 RemoteClient *client = m_clients.lockedGetClientNoEx(*i);
2833 client->SetBlocksNotSent(block);
2838 void Server::peerAdded(con::Peer *peer)
2840 DSTACK(__FUNCTION_NAME);
2841 verbosestream<<"Server::peerAdded(): peer->id="
2842 <<peer->id<<std::endl;
2845 c.type = con::PEER_ADDED;
2846 c.peer_id = peer->id;
2848 m_peer_change_queue.push_back(c);
2851 void Server::deletingPeer(con::Peer *peer, bool timeout)
2853 DSTACK(__FUNCTION_NAME);
2854 verbosestream<<"Server::deletingPeer(): peer->id="
2855 <<peer->id<<", timeout="<<timeout<<std::endl;
2857 m_clients.event(peer->id, CSE_Disconnect);
2859 c.type = con::PEER_REMOVED;
2860 c.peer_id = peer->id;
2861 c.timeout = timeout;
2862 m_peer_change_queue.push_back(c);
2865 bool Server::getClientConInfo(u16 peer_id, con::rtt_stat_type type, float* retval)
2867 *retval = m_con.getPeerStat(peer_id,type);
2868 if (*retval == -1) return false;
2872 bool Server::getClientInfo(
2881 std::string* vers_string
2884 *state = m_clients.getClientState(peer_id);
2886 RemoteClient* client = m_clients.lockedGetClientNoEx(peer_id, CS_Invalid);
2888 if (client == NULL) {
2893 *uptime = client->uptime();
2894 *ser_vers = client->serialization_version;
2895 *prot_vers = client->net_proto_version;
2897 *major = client->getMajor();
2898 *minor = client->getMinor();
2899 *patch = client->getPatch();
2900 *vers_string = client->getPatch();
2907 void Server::handlePeerChanges()
2909 while(m_peer_change_queue.size() > 0)
2911 con::PeerChange c = m_peer_change_queue.pop_front();
2913 verbosestream<<"Server: Handling peer change: "
2914 <<"id="<<c.peer_id<<", timeout="<<c.timeout
2919 case con::PEER_ADDED:
2920 m_clients.CreateClient(c.peer_id);
2923 case con::PEER_REMOVED:
2924 DeleteClient(c.peer_id, c.timeout?CDR_TIMEOUT:CDR_LEAVE);
2928 assert("Invalid peer change event received!" == 0);
2934 void Server::SendMovement(u16 peer_id)
2936 DSTACK(__FUNCTION_NAME);
2937 std::ostringstream os(std::ios_base::binary);
2939 writeU16(os, TOCLIENT_MOVEMENT);
2940 writeF1000(os, g_settings->getFloat("movement_acceleration_default"));
2941 writeF1000(os, g_settings->getFloat("movement_acceleration_air"));
2942 writeF1000(os, g_settings->getFloat("movement_acceleration_fast"));
2943 writeF1000(os, g_settings->getFloat("movement_speed_walk"));
2944 writeF1000(os, g_settings->getFloat("movement_speed_crouch"));
2945 writeF1000(os, g_settings->getFloat("movement_speed_fast"));
2946 writeF1000(os, g_settings->getFloat("movement_speed_climb"));
2947 writeF1000(os, g_settings->getFloat("movement_speed_jump"));
2948 writeF1000(os, g_settings->getFloat("movement_liquid_fluidity"));
2949 writeF1000(os, g_settings->getFloat("movement_liquid_fluidity_smooth"));
2950 writeF1000(os, g_settings->getFloat("movement_liquid_sink"));
2951 writeF1000(os, g_settings->getFloat("movement_gravity"));
2954 std::string s = os.str();
2955 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
2957 m_clients.send(peer_id, 0, data, true);
2960 void Server::SendHP(u16 peer_id, u8 hp)
2962 DSTACK(__FUNCTION_NAME);
2963 std::ostringstream os(std::ios_base::binary);
2965 writeU16(os, TOCLIENT_HP);
2969 std::string s = os.str();
2970 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
2972 m_clients.send(peer_id, 0, data, true);
2975 void Server::SendBreath(u16 peer_id, u16 breath)
2977 DSTACK(__FUNCTION_NAME);
2978 std::ostringstream os(std::ios_base::binary);
2980 writeU16(os, TOCLIENT_BREATH);
2981 writeU16(os, breath);
2984 std::string s = os.str();
2985 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
2987 m_clients.send(peer_id, 0, data, true);
2990 void Server::SendAccessDenied(u16 peer_id,const std::wstring &reason)
2992 DSTACK(__FUNCTION_NAME);
2993 std::ostringstream os(std::ios_base::binary);
2995 writeU16(os, TOCLIENT_ACCESS_DENIED);
2996 os<<serializeWideString(reason);
2999 std::string s = os.str();
3000 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3002 m_clients.send(peer_id, 0, data, true);
3005 void Server::SendDeathscreen(u16 peer_id,bool set_camera_point_target,
3006 v3f camera_point_target)
3008 DSTACK(__FUNCTION_NAME);
3009 std::ostringstream os(std::ios_base::binary);
3011 writeU16(os, TOCLIENT_DEATHSCREEN);
3012 writeU8(os, set_camera_point_target);
3013 writeV3F1000(os, camera_point_target);
3016 std::string s = os.str();
3017 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3019 m_clients.send(peer_id, 0, data, true);
3022 void Server::SendItemDef(u16 peer_id,
3023 IItemDefManager *itemdef, u16 protocol_version)
3025 DSTACK(__FUNCTION_NAME);
3026 std::ostringstream os(std::ios_base::binary);
3030 u32 length of the next item
3031 zlib-compressed serialized ItemDefManager
3033 writeU16(os, TOCLIENT_ITEMDEF);
3034 std::ostringstream tmp_os(std::ios::binary);
3035 itemdef->serialize(tmp_os, protocol_version);
3036 std::ostringstream tmp_os2(std::ios::binary);
3037 compressZlib(tmp_os.str(), tmp_os2);
3038 os<<serializeLongString(tmp_os2.str());
3041 std::string s = os.str();
3042 verbosestream<<"Server: Sending item definitions to id("<<peer_id
3043 <<"): size="<<s.size()<<std::endl;
3044 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3046 m_clients.send(peer_id, 0, data, true);
3049 void Server::SendNodeDef(u16 peer_id,
3050 INodeDefManager *nodedef, u16 protocol_version)
3052 DSTACK(__FUNCTION_NAME);
3053 std::ostringstream os(std::ios_base::binary);
3057 u32 length of the next item
3058 zlib-compressed serialized NodeDefManager
3060 writeU16(os, TOCLIENT_NODEDEF);
3061 std::ostringstream tmp_os(std::ios::binary);
3062 nodedef->serialize(tmp_os, protocol_version);
3063 std::ostringstream tmp_os2(std::ios::binary);
3064 compressZlib(tmp_os.str(), tmp_os2);
3065 os<<serializeLongString(tmp_os2.str());
3068 std::string s = os.str();
3069 verbosestream<<"Server: Sending node definitions to id("<<peer_id
3070 <<"): size="<<s.size()<<std::endl;
3071 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3073 m_clients.send(peer_id, 0, data, true);
3077 Non-static send methods
3080 void Server::SendInventory(u16 peer_id)
3082 DSTACK(__FUNCTION_NAME);
3084 PlayerSAO *playersao = getPlayerSAO(peer_id);
3087 playersao->m_inventory_not_sent = false;
3093 std::ostringstream os;
3094 playersao->getInventory()->serialize(os);
3096 std::string s = os.str();
3098 SharedBuffer<u8> data(s.size()+2);
3099 writeU16(&data[0], TOCLIENT_INVENTORY);
3100 memcpy(&data[2], s.c_str(), s.size());
3103 m_clients.send(peer_id, 0, data, true);
3106 void Server::SendChatMessage(u16 peer_id, const std::wstring &message)
3108 DSTACK(__FUNCTION_NAME);
3110 std::ostringstream os(std::ios_base::binary);
3114 writeU16(buf, TOCLIENT_CHAT_MESSAGE);
3115 os.write((char*)buf, 2);
3118 writeU16(buf, message.size());
3119 os.write((char*)buf, 2);
3122 for(u32 i=0; i<message.size(); i++)
3126 os.write((char*)buf, 2);
3130 std::string s = os.str();
3131 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3133 if (peer_id != PEER_ID_INEXISTENT)
3136 m_clients.send(peer_id, 0, data, true);
3140 m_clients.sendToAll(0,data,true);
3144 void Server::SendShowFormspecMessage(u16 peer_id, const std::string &formspec,
3145 const std::string &formname)
3147 DSTACK(__FUNCTION_NAME);
3149 std::ostringstream os(std::ios_base::binary);
3154 writeU16(buf, TOCLIENT_SHOW_FORMSPEC);
3155 os.write((char*)buf, 2);
3156 os<<serializeLongString(FORMSPEC_VERSION_STRING + formspec);
3157 os<<serializeString(formname);
3160 std::string s = os.str();
3161 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3163 m_clients.send(peer_id, 0, data, true);
3166 // Spawns a particle on peer with peer_id
3167 void Server::SendSpawnParticle(u16 peer_id, v3f pos, v3f velocity, v3f acceleration,
3168 float expirationtime, float size, bool collisiondetection,
3169 bool vertical, std::string texture)
3171 DSTACK(__FUNCTION_NAME);
3173 std::ostringstream os(std::ios_base::binary);
3174 writeU16(os, TOCLIENT_SPAWN_PARTICLE);
3175 writeV3F1000(os, pos);
3176 writeV3F1000(os, velocity);
3177 writeV3F1000(os, acceleration);
3178 writeF1000(os, expirationtime);
3179 writeF1000(os, size);
3180 writeU8(os, collisiondetection);
3181 os<<serializeLongString(texture);
3182 writeU8(os, vertical);
3185 std::string s = os.str();
3186 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3188 if (peer_id != PEER_ID_INEXISTENT)
3191 m_clients.send(peer_id, 0, data, true);
3195 m_clients.sendToAll(0,data,true);
3199 // Adds a ParticleSpawner on peer with peer_id
3200 void Server::SendAddParticleSpawner(u16 peer_id, u16 amount, float spawntime, v3f minpos, v3f maxpos,
3201 v3f minvel, v3f maxvel, v3f minacc, v3f maxacc, float minexptime, float maxexptime,
3202 float minsize, float maxsize, bool collisiondetection, bool vertical, std::string texture, u32 id)
3204 DSTACK(__FUNCTION_NAME);
3206 std::ostringstream os(std::ios_base::binary);
3207 writeU16(os, TOCLIENT_ADD_PARTICLESPAWNER);
3209 writeU16(os, amount);
3210 writeF1000(os, spawntime);
3211 writeV3F1000(os, minpos);
3212 writeV3F1000(os, maxpos);
3213 writeV3F1000(os, minvel);
3214 writeV3F1000(os, maxvel);
3215 writeV3F1000(os, minacc);
3216 writeV3F1000(os, maxacc);
3217 writeF1000(os, minexptime);
3218 writeF1000(os, maxexptime);
3219 writeF1000(os, minsize);
3220 writeF1000(os, maxsize);
3221 writeU8(os, collisiondetection);
3222 os<<serializeLongString(texture);
3224 writeU8(os, vertical);
3227 std::string s = os.str();
3228 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3230 if (peer_id != PEER_ID_INEXISTENT)
3233 m_clients.send(peer_id, 0, data, true);
3236 m_clients.sendToAll(0,data,true);
3240 void Server::SendDeleteParticleSpawner(u16 peer_id, u32 id)
3242 DSTACK(__FUNCTION_NAME);
3244 std::ostringstream os(std::ios_base::binary);
3245 writeU16(os, TOCLIENT_DELETE_PARTICLESPAWNER);
3250 std::string s = os.str();
3251 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3253 if (peer_id != PEER_ID_INEXISTENT) {
3255 m_clients.send(peer_id, 0, data, true);
3258 m_clients.sendToAll(0,data,true);
3263 void Server::SendHUDAdd(u16 peer_id, u32 id, HudElement *form)
3265 std::ostringstream os(std::ios_base::binary);
3268 writeU16(os, TOCLIENT_HUDADD);
3270 writeU8(os, (u8)form->type);
3271 writeV2F1000(os, form->pos);
3272 os << serializeString(form->name);
3273 writeV2F1000(os, form->scale);
3274 os << serializeString(form->text);
3275 writeU32(os, form->number);
3276 writeU32(os, form->item);
3277 writeU32(os, form->dir);
3278 writeV2F1000(os, form->align);
3279 writeV2F1000(os, form->offset);
3280 writeV3F1000(os, form->world_pos);
3281 writeV2S32(os,form->size);
3284 std::string s = os.str();
3285 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3287 m_clients.send(peer_id, 1, data, true);
3290 void Server::SendHUDRemove(u16 peer_id, u32 id)
3292 std::ostringstream os(std::ios_base::binary);
3295 writeU16(os, TOCLIENT_HUDRM);
3299 std::string s = os.str();
3300 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3303 m_clients.send(peer_id, 1, data, true);
3306 void Server::SendHUDChange(u16 peer_id, u32 id, HudElementStat stat, void *value)
3308 std::ostringstream os(std::ios_base::binary);
3311 writeU16(os, TOCLIENT_HUDCHANGE);
3313 writeU8(os, (u8)stat);
3316 case HUD_STAT_SCALE:
3317 case HUD_STAT_ALIGN:
3318 case HUD_STAT_OFFSET:
3319 writeV2F1000(os, *(v2f *)value);
3323 os << serializeString(*(std::string *)value);
3325 case HUD_STAT_WORLD_POS:
3326 writeV3F1000(os, *(v3f *)value);
3329 writeV2S32(os,*(v2s32 *)value);
3331 case HUD_STAT_NUMBER:
3335 writeU32(os, *(u32 *)value);
3340 std::string s = os.str();
3341 SharedBuffer<u8> data((u8 *)s.c_str(), s.size());
3343 m_clients.send(peer_id, 0, data, true);
3346 void Server::SendHUDSetFlags(u16 peer_id, u32 flags, u32 mask)
3348 std::ostringstream os(std::ios_base::binary);
3351 writeU16(os, TOCLIENT_HUD_SET_FLAGS);
3353 //////////////////////////// compatibility code to be removed //////////////
3354 flags &= ~(HUD_FLAG_HEALTHBAR_VISIBLE | HUD_FLAG_BREATHBAR_VISIBLE);
3355 ////////////////////////////////////////////////////////////////////////////
3356 writeU32(os, flags);
3360 std::string s = os.str();
3361 SharedBuffer<u8> data((u8 *)s.c_str(), s.size());
3363 m_clients.send(peer_id, 0, data, true);
3366 void Server::SendHUDSetParam(u16 peer_id, u16 param, const std::string &value)
3368 std::ostringstream os(std::ios_base::binary);
3371 writeU16(os, TOCLIENT_HUD_SET_PARAM);
3372 writeU16(os, param);
3373 os<<serializeString(value);
3376 std::string s = os.str();
3377 SharedBuffer<u8> data((u8 *)s.c_str(), s.size());
3379 m_clients.send(peer_id, 0, data, true);
3382 void Server::SendSetSky(u16 peer_id, const video::SColor &bgcolor,
3383 const std::string &type, const std::vector<std::string> ¶ms)
3385 std::ostringstream os(std::ios_base::binary);
3388 writeU16(os, TOCLIENT_SET_SKY);
3389 writeARGB8(os, bgcolor);
3390 os<<serializeString(type);
3391 writeU16(os, params.size());
3392 for(size_t i=0; i<params.size(); i++)
3393 os<<serializeString(params[i]);
3396 std::string s = os.str();
3397 SharedBuffer<u8> data((u8 *)s.c_str(), s.size());
3399 m_clients.send(peer_id, 0, data, true);
3402 void Server::SendOverrideDayNightRatio(u16 peer_id, bool do_override,
3405 std::ostringstream os(std::ios_base::binary);
3408 writeU16(os, TOCLIENT_OVERRIDE_DAY_NIGHT_RATIO);
3409 writeU8(os, do_override);
3410 writeU16(os, ratio*65535);
3413 std::string s = os.str();
3414 SharedBuffer<u8> data((u8 *)s.c_str(), s.size());
3416 m_clients.send(peer_id, 0, data, true);
3419 void Server::SendTimeOfDay(u16 peer_id, u16 time, f32 time_speed)
3421 DSTACK(__FUNCTION_NAME);
3424 SharedBuffer<u8> data(2+2+4);
3425 writeU16(&data[0], TOCLIENT_TIME_OF_DAY);
3426 writeU16(&data[2], time);
3427 writeF1000(&data[4], time_speed);
3429 if (peer_id == PEER_ID_INEXISTENT) {
3430 m_clients.sendToAll(0,data,true);
3434 m_clients.send(peer_id, 0, data, true);
3438 void Server::SendPlayerHP(u16 peer_id)
3440 DSTACK(__FUNCTION_NAME);
3441 PlayerSAO *playersao = getPlayerSAO(peer_id);
3443 playersao->m_hp_not_sent = false;
3444 SendHP(peer_id, playersao->getHP());
3445 m_script->player_event(playersao,"health_changed");
3447 // Send to other clients
3448 std::string str = gob_cmd_punched(playersao->readDamage(), playersao->getHP());
3449 ActiveObjectMessage aom(playersao->getId(), true, str);
3450 playersao->m_messages_out.push_back(aom);
3453 void Server::SendPlayerBreath(u16 peer_id)
3455 DSTACK(__FUNCTION_NAME);
3456 PlayerSAO *playersao = getPlayerSAO(peer_id);
3458 playersao->m_breath_not_sent = false;
3459 m_script->player_event(playersao,"breath_changed");
3460 SendBreath(peer_id, playersao->getBreath());
3463 void Server::SendMovePlayer(u16 peer_id)
3465 DSTACK(__FUNCTION_NAME);
3466 Player *player = m_env->getPlayer(peer_id);
3469 std::ostringstream os(std::ios_base::binary);
3470 writeU16(os, TOCLIENT_MOVE_PLAYER);
3471 writeV3F1000(os, player->getPosition());
3472 writeF1000(os, player->getPitch());
3473 writeF1000(os, player->getYaw());
3476 v3f pos = player->getPosition();
3477 f32 pitch = player->getPitch();
3478 f32 yaw = player->getYaw();
3479 verbosestream<<"Server: Sending TOCLIENT_MOVE_PLAYER"
3480 <<" pos=("<<pos.X<<","<<pos.Y<<","<<pos.Z<<")"
3487 std::string s = os.str();
3488 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3490 m_clients.send(peer_id, 0, data, true);
3493 void Server::SendLocalPlayerAnimations(u16 peer_id, v2s32 animation_frames[4], f32 animation_speed)
3495 std::ostringstream os(std::ios_base::binary);
3497 writeU16(os, TOCLIENT_LOCAL_PLAYER_ANIMATIONS);
3498 writeV2S32(os, animation_frames[0]);
3499 writeV2S32(os, animation_frames[1]);
3500 writeV2S32(os, animation_frames[2]);
3501 writeV2S32(os, animation_frames[3]);
3502 writeF1000(os, animation_speed);
3505 std::string s = os.str();
3506 SharedBuffer<u8> data((u8 *)s.c_str(), s.size());
3508 m_clients.send(peer_id, 0, data, true);
3511 void Server::SendEyeOffset(u16 peer_id, v3f first, v3f third)
3513 std::ostringstream os(std::ios_base::binary);
3515 writeU16(os, TOCLIENT_EYE_OFFSET);
3516 writeV3F1000(os, first);
3517 writeV3F1000(os, third);
3520 std::string s = os.str();
3521 SharedBuffer<u8> data((u8 *)s.c_str(), s.size());
3523 m_clients.send(peer_id, 0, data, true);
3525 void Server::SendPlayerPrivileges(u16 peer_id)
3527 Player *player = m_env->getPlayer(peer_id);
3529 if(player->peer_id == PEER_ID_INEXISTENT)
3532 std::set<std::string> privs;
3533 m_script->getAuth(player->getName(), NULL, &privs);
3535 std::ostringstream os(std::ios_base::binary);
3536 writeU16(os, TOCLIENT_PRIVILEGES);
3537 writeU16(os, privs.size());
3538 for(std::set<std::string>::const_iterator i = privs.begin();
3539 i != privs.end(); i++){
3540 os<<serializeString(*i);
3544 std::string s = os.str();
3545 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3547 m_clients.send(peer_id, 0, data, true);
3550 void Server::SendPlayerInventoryFormspec(u16 peer_id)
3552 Player *player = m_env->getPlayer(peer_id);
3554 if(player->peer_id == PEER_ID_INEXISTENT)
3557 std::ostringstream os(std::ios_base::binary);
3558 writeU16(os, TOCLIENT_INVENTORY_FORMSPEC);
3559 os<<serializeLongString(FORMSPEC_VERSION_STRING + player->inventory_formspec);
3562 std::string s = os.str();
3563 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3565 m_clients.send(peer_id, 0, data, true);
3568 s32 Server::playSound(const SimpleSoundSpec &spec,
3569 const ServerSoundParams ¶ms)
3571 // Find out initial position of sound
3572 bool pos_exists = false;
3573 v3f pos = params.getPos(m_env, &pos_exists);
3574 // If position is not found while it should be, cancel sound
3575 if(pos_exists != (params.type != ServerSoundParams::SSP_LOCAL))
3578 // Filter destination clients
3579 std::list<u16> dst_clients;
3580 if(params.to_player != "")
3582 Player *player = m_env->getPlayer(params.to_player.c_str());
3584 infostream<<"Server::playSound: Player \""<<params.to_player
3585 <<"\" not found"<<std::endl;
3588 if(player->peer_id == PEER_ID_INEXISTENT){
3589 infostream<<"Server::playSound: Player \""<<params.to_player
3590 <<"\" not connected"<<std::endl;
3593 dst_clients.push_back(player->peer_id);
3597 std::list<u16> clients = m_clients.getClientIDs();
3599 for(std::list<u16>::iterator
3600 i = clients.begin(); i != clients.end(); ++i)
3602 Player *player = m_env->getPlayer(*i);
3606 if(player->getPosition().getDistanceFrom(pos) >
3607 params.max_hear_distance)
3610 dst_clients.push_back(*i);
3613 if(dst_clients.size() == 0)
3617 s32 id = m_next_sound_id++;
3618 // The sound will exist as a reference in m_playing_sounds
3619 m_playing_sounds[id] = ServerPlayingSound();
3620 ServerPlayingSound &psound = m_playing_sounds[id];
3621 psound.params = params;
3622 for(std::list<u16>::iterator i = dst_clients.begin();
3623 i != dst_clients.end(); i++)
3624 psound.clients.insert(*i);
3626 std::ostringstream os(std::ios_base::binary);
3627 writeU16(os, TOCLIENT_PLAY_SOUND);
3629 os<<serializeString(spec.name);
3630 writeF1000(os, spec.gain * params.gain);
3631 writeU8(os, params.type);
3632 writeV3F1000(os, pos);
3633 writeU16(os, params.object);
3634 writeU8(os, params.loop);
3636 std::string s = os.str();
3637 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3639 for(std::list<u16>::iterator i = dst_clients.begin();
3640 i != dst_clients.end(); i++){
3642 m_clients.send(*i, 0, data, true);
3646 void Server::stopSound(s32 handle)
3648 // Get sound reference
3649 std::map<s32, ServerPlayingSound>::iterator i =
3650 m_playing_sounds.find(handle);
3651 if(i == m_playing_sounds.end())
3653 ServerPlayingSound &psound = i->second;
3655 std::ostringstream os(std::ios_base::binary);
3656 writeU16(os, TOCLIENT_STOP_SOUND);
3657 writeS32(os, handle);
3659 std::string s = os.str();
3660 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3662 for(std::set<u16>::iterator i = psound.clients.begin();
3663 i != psound.clients.end(); i++){
3665 m_clients.send(*i, 0, data, true);
3667 // Remove sound reference
3668 m_playing_sounds.erase(i);
3671 void Server::sendRemoveNode(v3s16 p, u16 ignore_id,
3672 std::list<u16> *far_players, float far_d_nodes)
3674 float maxd = far_d_nodes*BS;
3675 v3f p_f = intToFloat(p, BS);
3679 SharedBuffer<u8> reply(replysize);
3680 writeU16(&reply[0], TOCLIENT_REMOVENODE);
3681 writeS16(&reply[2], p.X);
3682 writeS16(&reply[4], p.Y);
3683 writeS16(&reply[6], p.Z);
3685 std::list<u16> clients = m_clients.getClientIDs();
3686 for(std::list<u16>::iterator
3687 i = clients.begin();
3688 i != clients.end(); ++i)
3693 Player *player = m_env->getPlayer(*i);
3696 // If player is far away, only set modified blocks not sent
3697 v3f player_pos = player->getPosition();
3698 if(player_pos.getDistanceFrom(p_f) > maxd)
3700 far_players->push_back(*i);
3707 m_clients.send(*i, 0, reply, true);
3711 void Server::sendAddNode(v3s16 p, MapNode n, u16 ignore_id,
3712 std::list<u16> *far_players, float far_d_nodes,
3713 bool remove_metadata)
3715 float maxd = far_d_nodes*BS;
3716 v3f p_f = intToFloat(p, BS);
3718 std::list<u16> clients = m_clients.getClientIDs();
3719 for(std::list<u16>::iterator
3720 i = clients.begin();
3721 i != clients.end(); ++i)
3727 Player *player = m_env->getPlayer(*i);
3730 // If player is far away, only set modified blocks not sent
3731 v3f player_pos = player->getPosition();
3732 if(player_pos.getDistanceFrom(p_f) > maxd)
3734 far_players->push_back(*i);
3739 SharedBuffer<u8> reply(0);
3741 RemoteClient* client = m_clients.lockedGetClientNoEx(*i);
3745 u32 replysize = 9 + MapNode::serializedLength(client->serialization_version);
3746 reply = SharedBuffer<u8>(replysize);
3747 writeU16(&reply[0], TOCLIENT_ADDNODE);
3748 writeS16(&reply[2], p.X);
3749 writeS16(&reply[4], p.Y);
3750 writeS16(&reply[6], p.Z);
3751 n.serialize(&reply[8], client->serialization_version);
3752 u32 index = 8 + MapNode::serializedLength(client->serialization_version);
3753 writeU8(&reply[index], remove_metadata ? 0 : 1);
3755 if (!remove_metadata) {
3756 if (client->net_proto_version <= 21) {
3757 // Old clients always clear metadata; fix it
3758 // by sending the full block again.
3759 client->SetBlockNotSent(p);
3766 if (reply.getSize() > 0)
3767 m_clients.send(*i, 0, reply, true);
3771 void Server::setBlockNotSent(v3s16 p)
3773 std::list<u16> clients = m_clients.getClientIDs();
3775 for(std::list<u16>::iterator
3776 i = clients.begin();
3777 i != clients.end(); ++i)
3779 RemoteClient *client = m_clients.lockedGetClientNoEx(*i);
3780 client->SetBlockNotSent(p);
3785 void Server::SendBlockNoLock(u16 peer_id, MapBlock *block, u8 ver, u16 net_proto_version)
3787 DSTACK(__FUNCTION_NAME);
3789 v3s16 p = block->getPos();
3793 bool completely_air = true;
3794 for(s16 z0=0; z0<MAP_BLOCKSIZE; z0++)
3795 for(s16 x0=0; x0<MAP_BLOCKSIZE; x0++)
3796 for(s16 y0=0; y0<MAP_BLOCKSIZE; y0++)
3798 if(block->getNodeNoEx(v3s16(x0,y0,z0)).d != CONTENT_AIR)
3800 completely_air = false;
3801 x0 = y0 = z0 = MAP_BLOCKSIZE; // Break out
3806 infostream<<"Server: Sending block ("<<p.X<<","<<p.Y<<","<<p.Z<<"): ";
3808 infostream<<"[completely air] ";
3809 infostream<<std::endl;
3813 Create a packet with the block in the right format
3816 std::ostringstream os(std::ios_base::binary);
3817 block->serialize(os, ver, false);
3818 block->serializeNetworkSpecific(os, net_proto_version);
3819 std::string s = os.str();
3820 SharedBuffer<u8> blockdata((u8*)s.c_str(), s.size());
3822 u32 replysize = 8 + blockdata.getSize();
3823 SharedBuffer<u8> reply(replysize);
3824 writeU16(&reply[0], TOCLIENT_BLOCKDATA);
3825 writeS16(&reply[2], p.X);
3826 writeS16(&reply[4], p.Y);
3827 writeS16(&reply[6], p.Z);
3828 memcpy(&reply[8], *blockdata, blockdata.getSize());
3830 /*infostream<<"Server: Sending block ("<<p.X<<","<<p.Y<<","<<p.Z<<")"
3831 <<": \tpacket size: "<<replysize<<std::endl;*/
3836 m_clients.send(peer_id, 2, reply, true);
3839 void Server::SendBlocks(float dtime)
3841 DSTACK(__FUNCTION_NAME);
3843 JMutexAutoLock envlock(m_env_mutex);
3844 //TODO check if one big lock could be faster then multiple small ones
3846 ScopeProfiler sp(g_profiler, "Server: sel and send blocks to clients");
3848 std::vector<PrioritySortedBlockTransfer> queue;
3850 s32 total_sending = 0;
3853 ScopeProfiler sp(g_profiler, "Server: selecting blocks for sending");
3855 std::list<u16> clients = m_clients.getClientIDs();
3858 for(std::list<u16>::iterator
3859 i = clients.begin();
3860 i != clients.end(); ++i)
3862 RemoteClient *client = m_clients.lockedGetClientNoEx(*i, CS_Active);
3867 total_sending += client->SendingCount();
3868 client->GetNextBlocks(m_env,m_emerge, dtime, queue);
3874 // Lowest priority number comes first.
3875 // Lowest is most important.
3876 std::sort(queue.begin(), queue.end());
3879 for(u32 i=0; i<queue.size(); i++)
3881 //TODO: Calculate limit dynamically
3882 if(total_sending >= g_settings->getS32
3883 ("max_simultaneous_block_sends_server_total"))
3886 PrioritySortedBlockTransfer q = queue[i];
3888 MapBlock *block = NULL;
3891 block = m_env->getMap().getBlockNoCreate(q.pos);
3893 catch(InvalidPositionException &e)
3898 RemoteClient *client = m_clients.lockedGetClientNoEx(q.peer_id, CS_Active);
3903 SendBlockNoLock(q.peer_id, block, client->serialization_version, client->net_proto_version);
3905 client->SentBlock(q.pos);
3911 void Server::fillMediaCache()
3913 DSTACK(__FUNCTION_NAME);
3915 infostream<<"Server: Calculating media file checksums"<<std::endl;
3917 // Collect all media file paths
3918 std::list<std::string> paths;
3919 for(std::vector<ModSpec>::iterator i = m_mods.begin();
3920 i != m_mods.end(); i++){
3921 const ModSpec &mod = *i;
3922 paths.push_back(mod.path + DIR_DELIM + "textures");
3923 paths.push_back(mod.path + DIR_DELIM + "sounds");
3924 paths.push_back(mod.path + DIR_DELIM + "media");
3925 paths.push_back(mod.path + DIR_DELIM + "models");
3927 paths.push_back(porting::path_user + DIR_DELIM + "textures" + DIR_DELIM + "server");
3929 // Collect media file information from paths into cache
3930 for(std::list<std::string>::iterator i = paths.begin();
3931 i != paths.end(); i++)
3933 std::string mediapath = *i;
3934 std::vector<fs::DirListNode> dirlist = fs::GetDirListing(mediapath);
3935 for(u32 j=0; j<dirlist.size(); j++){
3936 if(dirlist[j].dir) // Ignode dirs
3938 std::string filename = dirlist[j].name;
3939 // If name contains illegal characters, ignore the file
3940 if(!string_allowed(filename, TEXTURENAME_ALLOWED_CHARS)){
3941 infostream<<"Server: ignoring illegal file name: \""
3942 <<filename<<"\""<<std::endl;
3945 // If name is not in a supported format, ignore it
3946 const char *supported_ext[] = {
3947 ".png", ".jpg", ".bmp", ".tga",
3948 ".pcx", ".ppm", ".psd", ".wal", ".rgb",
3950 ".x", ".b3d", ".md2", ".obj",
3953 if(removeStringEnd(filename, supported_ext) == ""){
3954 infostream<<"Server: ignoring unsupported file extension: \""
3955 <<filename<<"\""<<std::endl;
3958 // Ok, attempt to load the file and add to cache
3959 std::string filepath = mediapath + DIR_DELIM + filename;
3961 std::ifstream fis(filepath.c_str(), std::ios_base::binary);
3962 if(fis.good() == false){
3963 errorstream<<"Server::fillMediaCache(): Could not open \""
3964 <<filename<<"\" for reading"<<std::endl;
3967 std::ostringstream tmp_os(std::ios_base::binary);
3971 fis.read(buf, 1024);
3972 std::streamsize len = fis.gcount();
3973 tmp_os.write(buf, len);
3982 errorstream<<"Server::fillMediaCache(): Failed to read \""
3983 <<filename<<"\""<<std::endl;
3986 if(tmp_os.str().length() == 0){
3987 errorstream<<"Server::fillMediaCache(): Empty file \""
3988 <<filepath<<"\""<<std::endl;
3993 sha1.addBytes(tmp_os.str().c_str(), tmp_os.str().length());
3995 unsigned char *digest = sha1.getDigest();
3996 std::string sha1_base64 = base64_encode(digest, 20);
3997 std::string sha1_hex = hex_encode((char*)digest, 20);
4001 this->m_media[filename] = MediaInfo(filepath, sha1_base64);
4002 verbosestream<<"Server: "<<sha1_hex<<" is "<<filename<<std::endl;
4007 struct SendableMediaAnnouncement
4010 std::string sha1_digest;
4012 SendableMediaAnnouncement(const std::string &name_="",
4013 const std::string &sha1_digest_=""):
4015 sha1_digest(sha1_digest_)
4019 void Server::sendMediaAnnouncement(u16 peer_id)
4021 DSTACK(__FUNCTION_NAME);
4023 verbosestream<<"Server: Announcing files to id("<<peer_id<<")"
4026 std::list<SendableMediaAnnouncement> file_announcements;
4028 for(std::map<std::string, MediaInfo>::iterator i = m_media.begin();
4029 i != m_media.end(); i++){
4031 file_announcements.push_back(
4032 SendableMediaAnnouncement(i->first, i->second.sha1_digest));
4036 std::ostringstream os(std::ios_base::binary);
4044 u16 length of sha1_digest
4049 writeU16(os, TOCLIENT_ANNOUNCE_MEDIA);
4050 writeU16(os, file_announcements.size());
4052 for(std::list<SendableMediaAnnouncement>::iterator
4053 j = file_announcements.begin();
4054 j != file_announcements.end(); ++j){
4055 os<<serializeString(j->name);
4056 os<<serializeString(j->sha1_digest);
4058 os<<serializeString(g_settings->get("remote_media"));
4061 std::string s = os.str();
4062 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
4065 m_clients.send(peer_id, 0, data, true);
4068 struct SendableMedia
4074 SendableMedia(const std::string &name_="", const std::string &path_="",
4075 const std::string &data_=""):
4082 void Server::sendRequestedMedia(u16 peer_id,
4083 const std::list<std::string> &tosend)
4085 DSTACK(__FUNCTION_NAME);
4087 verbosestream<<"Server::sendRequestedMedia(): "
4088 <<"Sending files to client"<<std::endl;
4092 // Put 5kB in one bunch (this is not accurate)
4093 u32 bytes_per_bunch = 5000;
4095 std::vector< std::list<SendableMedia> > file_bunches;
4096 file_bunches.push_back(std::list<SendableMedia>());
4098 u32 file_size_bunch_total = 0;
4100 for(std::list<std::string>::const_iterator i = tosend.begin();
4101 i != tosend.end(); ++i)
4103 const std::string &name = *i;
4105 if(m_media.find(name) == m_media.end()){
4106 errorstream<<"Server::sendRequestedMedia(): Client asked for "
4107 <<"unknown file \""<<(name)<<"\""<<std::endl;
4111 //TODO get path + name
4112 std::string tpath = m_media[name].path;
4115 std::ifstream fis(tpath.c_str(), std::ios_base::binary);
4116 if(fis.good() == false){
4117 errorstream<<"Server::sendRequestedMedia(): Could not open \""
4118 <<tpath<<"\" for reading"<<std::endl;
4121 std::ostringstream tmp_os(std::ios_base::binary);
4125 fis.read(buf, 1024);
4126 std::streamsize len = fis.gcount();
4127 tmp_os.write(buf, len);
4128 file_size_bunch_total += len;
4137 errorstream<<"Server::sendRequestedMedia(): Failed to read \""
4138 <<name<<"\""<<std::endl;
4141 /*infostream<<"Server::sendRequestedMedia(): Loaded \""
4142 <<tname<<"\""<<std::endl;*/
4144 file_bunches[file_bunches.size()-1].push_back(
4145 SendableMedia(name, tpath, tmp_os.str()));
4147 // Start next bunch if got enough data
4148 if(file_size_bunch_total >= bytes_per_bunch){
4149 file_bunches.push_back(std::list<SendableMedia>());
4150 file_size_bunch_total = 0;
4155 /* Create and send packets */
4157 u32 num_bunches = file_bunches.size();
4158 for(u32 i=0; i<num_bunches; i++)
4160 std::ostringstream os(std::ios_base::binary);
4164 u16 total number of texture bunches
4165 u16 index of this bunch
4166 u32 number of files in this bunch
4175 writeU16(os, TOCLIENT_MEDIA);
4176 writeU16(os, num_bunches);
4178 writeU32(os, file_bunches[i].size());
4180 for(std::list<SendableMedia>::iterator
4181 j = file_bunches[i].begin();
4182 j != file_bunches[i].end(); ++j){
4183 os<<serializeString(j->name);
4184 os<<serializeLongString(j->data);
4188 std::string s = os.str();
4189 verbosestream<<"Server::sendRequestedMedia(): bunch "
4190 <<i<<"/"<<num_bunches
4191 <<" files="<<file_bunches[i].size()
4192 <<" size=" <<s.size()<<std::endl;
4193 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
4195 m_clients.send(peer_id, 2, data, true);
4199 void Server::sendDetachedInventory(const std::string &name, u16 peer_id)
4201 if(m_detached_inventories.count(name) == 0){
4202 errorstream<<__FUNCTION_NAME<<": \""<<name<<"\" not found"<<std::endl;
4205 Inventory *inv = m_detached_inventories[name];
4207 std::ostringstream os(std::ios_base::binary);
4208 writeU16(os, TOCLIENT_DETACHED_INVENTORY);
4209 os<<serializeString(name);
4213 std::string s = os.str();
4214 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
4216 if (peer_id != PEER_ID_INEXISTENT)
4219 m_clients.send(peer_id, 0, data, true);
4223 m_clients.sendToAll(0,data,true);
4227 void Server::sendDetachedInventories(u16 peer_id)
4229 DSTACK(__FUNCTION_NAME);
4231 for(std::map<std::string, Inventory*>::iterator
4232 i = m_detached_inventories.begin();
4233 i != m_detached_inventories.end(); i++){
4234 const std::string &name = i->first;
4235 //Inventory *inv = i->second;
4236 sendDetachedInventory(name, peer_id);
4244 void Server::DiePlayer(u16 peer_id)
4246 DSTACK(__FUNCTION_NAME);
4248 PlayerSAO *playersao = getPlayerSAO(peer_id);
4251 infostream<<"Server::DiePlayer(): Player "
4252 <<playersao->getPlayer()->getName()
4253 <<" dies"<<std::endl;
4255 playersao->setHP(0);
4257 // Trigger scripted stuff
4258 m_script->on_dieplayer(playersao);
4260 SendPlayerHP(peer_id);
4261 SendDeathscreen(peer_id, false, v3f(0,0,0));
4264 void Server::RespawnPlayer(u16 peer_id)
4266 DSTACK(__FUNCTION_NAME);
4268 PlayerSAO *playersao = getPlayerSAO(peer_id);
4271 infostream<<"Server::RespawnPlayer(): Player "
4272 <<playersao->getPlayer()->getName()
4273 <<" respawns"<<std::endl;
4275 playersao->setHP(PLAYER_MAX_HP);
4277 bool repositioned = m_script->on_respawnplayer(playersao);
4279 v3f pos = findSpawnPos(m_env->getServerMap());
4280 playersao->setPos(pos);
4284 void Server::DenyAccess(u16 peer_id, const std::wstring &reason)
4286 DSTACK(__FUNCTION_NAME);
4288 SendAccessDenied(peer_id, reason);
4289 m_clients.event(peer_id, CSE_SetDenied);
4290 m_con.DisconnectPeer(peer_id);
4293 void Server::DeleteClient(u16 peer_id, ClientDeletionReason reason)
4295 DSTACK(__FUNCTION_NAME);
4296 std::wstring message;
4299 Clear references to playing sounds
4301 for(std::map<s32, ServerPlayingSound>::iterator
4302 i = m_playing_sounds.begin();
4303 i != m_playing_sounds.end();)
4305 ServerPlayingSound &psound = i->second;
4306 psound.clients.erase(peer_id);
4307 if(psound.clients.size() == 0)
4308 m_playing_sounds.erase(i++);
4313 Player *player = m_env->getPlayer(peer_id);
4315 // Collect information about leaving in chat
4317 if(player != NULL && reason != CDR_DENY)
4319 std::wstring name = narrow_to_wide(player->getName());
4322 message += L" left the game.";
4323 if(reason == CDR_TIMEOUT)
4324 message += L" (timed out)";
4328 /* Run scripts and remove from environment */
4332 PlayerSAO *playersao = player->getPlayerSAO();
4335 m_script->on_leaveplayer(playersao);
4337 playersao->disconnected();
4345 if(player != NULL && reason != CDR_DENY)
4347 std::ostringstream os(std::ios_base::binary);
4348 std::list<u16> clients = m_clients.getClientIDs();
4350 for(std::list<u16>::iterator
4351 i = clients.begin();
4352 i != clients.end(); ++i)
4355 Player *player = m_env->getPlayer(*i);
4358 // Get name of player
4359 os<<player->getName()<<" ";
4362 actionstream<<player->getName()<<" "
4363 <<(reason==CDR_TIMEOUT?"times out.":"leaves game.")
4364 <<" List of players: "<<os.str()<<std::endl;
4368 JMutexAutoLock env_lock(m_env_mutex);
4369 m_clients.DeleteClient(peer_id);
4373 // Send leave chat message to all remaining clients
4374 if(message.length() != 0)
4375 SendChatMessage(PEER_ID_INEXISTENT,message);
4378 void Server::UpdateCrafting(u16 peer_id)
4380 DSTACK(__FUNCTION_NAME);
4382 Player* player = m_env->getPlayer(peer_id);
4385 // Get a preview for crafting
4387 InventoryLocation loc;
4388 loc.setPlayer(player->getName());
4389 getCraftingResult(&player->inventory, preview, false, this);
4390 m_env->getScriptIface()->item_CraftPredict(preview, player->getPlayerSAO(), (&player->inventory)->getList("craft"), loc);
4392 // Put the new preview in
4393 InventoryList *plist = player->inventory.getList("craftpreview");
4395 assert(plist->getSize() >= 1);
4396 plist->changeItem(0, preview);
4399 RemoteClient* Server::getClient(u16 peer_id, ClientState state_min)
4401 RemoteClient *client = getClientNoEx(peer_id,state_min);
4403 throw ClientNotFoundException("Client not found");
4407 RemoteClient* Server::getClientNoEx(u16 peer_id, ClientState state_min)
4409 return m_clients.getClientNoEx(peer_id, state_min);
4412 std::string Server::getPlayerName(u16 peer_id)
4414 Player *player = m_env->getPlayer(peer_id);
4416 return "[id="+itos(peer_id)+"]";
4417 return player->getName();
4420 PlayerSAO* Server::getPlayerSAO(u16 peer_id)
4422 Player *player = m_env->getPlayer(peer_id);
4425 return player->getPlayerSAO();
4428 std::wstring Server::getStatusString()
4430 std::wostringstream os(std::ios_base::binary);
4433 os<<L"version="<<narrow_to_wide(minetest_version_simple);
4435 os<<L", uptime="<<m_uptime.get();
4437 os<<L", max_lag="<<m_env->getMaxLagEstimate();
4438 // Information about clients
4441 std::list<u16> clients = m_clients.getClientIDs();
4442 for(std::list<u16>::iterator i = clients.begin();
4443 i != clients.end(); ++i)
4446 Player *player = m_env->getPlayer(*i);
4447 // Get name of player
4448 std::wstring name = L"unknown";
4450 name = narrow_to_wide(player->getName());
4451 // Add name to information string
4459 if(((ServerMap*)(&m_env->getMap()))->isSavingEnabled() == false)
4460 os<<std::endl<<L"# Server: "<<" WARNING: Map saving is disabled.";
4461 if(g_settings->get("motd") != "")
4462 os<<std::endl<<L"# Server: "<<narrow_to_wide(g_settings->get("motd"));
4466 std::set<std::string> Server::getPlayerEffectivePrivs(const std::string &name)
4468 std::set<std::string> privs;
4469 m_script->getAuth(name, NULL, &privs);
4473 bool Server::checkPriv(const std::string &name, const std::string &priv)
4475 std::set<std::string> privs = getPlayerEffectivePrivs(name);
4476 return (privs.count(priv) != 0);
4479 void Server::reportPrivsModified(const std::string &name)
4482 std::list<u16> clients = m_clients.getClientIDs();
4483 for(std::list<u16>::iterator
4484 i = clients.begin();
4485 i != clients.end(); ++i){
4486 Player *player = m_env->getPlayer(*i);
4487 reportPrivsModified(player->getName());
4490 Player *player = m_env->getPlayer(name.c_str());
4493 SendPlayerPrivileges(player->peer_id);
4494 PlayerSAO *sao = player->getPlayerSAO();
4497 sao->updatePrivileges(
4498 getPlayerEffectivePrivs(name),
4503 void Server::reportInventoryFormspecModified(const std::string &name)
4505 Player *player = m_env->getPlayer(name.c_str());
4508 SendPlayerInventoryFormspec(player->peer_id);
4511 void Server::setIpBanned(const std::string &ip, const std::string &name)
4513 m_banmanager->add(ip, name);
4516 void Server::unsetIpBanned(const std::string &ip_or_name)
4518 m_banmanager->remove(ip_or_name);
4521 std::string Server::getBanDescription(const std::string &ip_or_name)
4523 return m_banmanager->getBanDescription(ip_or_name);
4526 void Server::notifyPlayer(const char *name, const std::wstring &msg)
4528 Player *player = m_env->getPlayer(name);
4532 if (player->peer_id == PEER_ID_INEXISTENT)
4535 SendChatMessage(player->peer_id, msg);
4538 bool Server::showFormspec(const char *playername, const std::string &formspec, const std::string &formname)
4540 Player *player = m_env->getPlayer(playername);
4544 infostream<<"showFormspec: couldn't find player:"<<playername<<std::endl;
4548 SendShowFormspecMessage(player->peer_id, formspec, formname);
4552 u32 Server::hudAdd(Player *player, HudElement *form) {
4556 u32 id = player->addHud(form);
4558 SendHUDAdd(player->peer_id, id, form);
4563 bool Server::hudRemove(Player *player, u32 id) {
4567 HudElement* todel = player->removeHud(id);
4574 SendHUDRemove(player->peer_id, id);
4578 bool Server::hudChange(Player *player, u32 id, HudElementStat stat, void *data) {
4582 SendHUDChange(player->peer_id, id, stat, data);
4586 bool Server::hudSetFlags(Player *player, u32 flags, u32 mask) {
4590 SendHUDSetFlags(player->peer_id, flags, mask);
4591 player->hud_flags = flags;
4593 PlayerSAO* playersao = player->getPlayerSAO();
4595 if (playersao == NULL)
4598 m_script->player_event(playersao, "hud_changed");
4602 bool Server::hudSetHotbarItemcount(Player *player, s32 hotbar_itemcount) {
4605 if (hotbar_itemcount <= 0 || hotbar_itemcount > HUD_HOTBAR_ITEMCOUNT_MAX)
4608 std::ostringstream os(std::ios::binary);
4609 writeS32(os, hotbar_itemcount);
4610 SendHUDSetParam(player->peer_id, HUD_PARAM_HOTBAR_ITEMCOUNT, os.str());
4614 void Server::hudSetHotbarImage(Player *player, std::string name) {
4618 SendHUDSetParam(player->peer_id, HUD_PARAM_HOTBAR_IMAGE, name);
4621 void Server::hudSetHotbarSelectedImage(Player *player, std::string name) {
4625 SendHUDSetParam(player->peer_id, HUD_PARAM_HOTBAR_SELECTED_IMAGE, name);
4628 bool Server::setLocalPlayerAnimations(Player *player, v2s32 animation_frames[4], f32 frame_speed)
4633 SendLocalPlayerAnimations(player->peer_id, animation_frames, frame_speed);
4637 bool Server::setPlayerEyeOffset(Player *player, v3f first, v3f third)
4642 SendEyeOffset(player->peer_id, first, third);
4646 bool Server::setSky(Player *player, const video::SColor &bgcolor,
4647 const std::string &type, const std::vector<std::string> ¶ms)
4652 SendSetSky(player->peer_id, bgcolor, type, params);
4656 bool Server::overrideDayNightRatio(Player *player, bool do_override,
4662 SendOverrideDayNightRatio(player->peer_id, do_override, ratio);
4666 void Server::notifyPlayers(const std::wstring &msg)
4668 SendChatMessage(PEER_ID_INEXISTENT,msg);
4671 void Server::spawnParticle(const char *playername, v3f pos,
4672 v3f velocity, v3f acceleration,
4673 float expirationtime, float size, bool
4674 collisiondetection, bool vertical, std::string texture)
4676 Player *player = m_env->getPlayer(playername);
4679 SendSpawnParticle(player->peer_id, pos, velocity, acceleration,
4680 expirationtime, size, collisiondetection, vertical, texture);
4683 void Server::spawnParticleAll(v3f pos, v3f velocity, v3f acceleration,
4684 float expirationtime, float size,
4685 bool collisiondetection, bool vertical, std::string texture)
4687 SendSpawnParticle(PEER_ID_INEXISTENT,pos, velocity, acceleration,
4688 expirationtime, size, collisiondetection, vertical, texture);
4691 u32 Server::addParticleSpawner(const char *playername,
4692 u16 amount, float spawntime,
4693 v3f minpos, v3f maxpos,
4694 v3f minvel, v3f maxvel,
4695 v3f minacc, v3f maxacc,
4696 float minexptime, float maxexptime,
4697 float minsize, float maxsize,
4698 bool collisiondetection, bool vertical, std::string texture)
4700 Player *player = m_env->getPlayer(playername);
4705 for(;;) // look for unused particlespawner id
4708 if (std::find(m_particlespawner_ids.begin(),
4709 m_particlespawner_ids.end(), id)
4710 == m_particlespawner_ids.end())
4712 m_particlespawner_ids.push_back(id);
4717 SendAddParticleSpawner(player->peer_id, amount, spawntime,
4718 minpos, maxpos, minvel, maxvel, minacc, maxacc,
4719 minexptime, maxexptime, minsize, maxsize,
4720 collisiondetection, vertical, texture, id);
4725 u32 Server::addParticleSpawnerAll(u16 amount, float spawntime,
4726 v3f minpos, v3f maxpos,
4727 v3f minvel, v3f maxvel,
4728 v3f minacc, v3f maxacc,
4729 float minexptime, float maxexptime,
4730 float minsize, float maxsize,
4731 bool collisiondetection, bool vertical, std::string texture)
4734 for(;;) // look for unused particlespawner id
4737 if (std::find(m_particlespawner_ids.begin(),
4738 m_particlespawner_ids.end(), id)
4739 == m_particlespawner_ids.end())
4741 m_particlespawner_ids.push_back(id);
4746 SendAddParticleSpawner(PEER_ID_INEXISTENT, amount, spawntime,
4747 minpos, maxpos, minvel, maxvel, minacc, maxacc,
4748 minexptime, maxexptime, minsize, maxsize,
4749 collisiondetection, vertical, texture, id);
4754 void Server::deleteParticleSpawner(const char *playername, u32 id)
4756 Player *player = m_env->getPlayer(playername);
4760 m_particlespawner_ids.erase(
4761 std::remove(m_particlespawner_ids.begin(),
4762 m_particlespawner_ids.end(), id),
4763 m_particlespawner_ids.end());
4764 SendDeleteParticleSpawner(player->peer_id, id);
4767 void Server::deleteParticleSpawnerAll(u32 id)
4769 m_particlespawner_ids.erase(
4770 std::remove(m_particlespawner_ids.begin(),
4771 m_particlespawner_ids.end(), id),
4772 m_particlespawner_ids.end());
4773 SendDeleteParticleSpawner(PEER_ID_INEXISTENT, id);
4776 Inventory* Server::createDetachedInventory(const std::string &name)
4778 if(m_detached_inventories.count(name) > 0){
4779 infostream<<"Server clearing detached inventory \""<<name<<"\""<<std::endl;
4780 delete m_detached_inventories[name];
4782 infostream<<"Server creating detached inventory \""<<name<<"\""<<std::endl;
4784 Inventory *inv = new Inventory(m_itemdef);
4786 m_detached_inventories[name] = inv;
4787 //TODO find a better way to do this
4788 sendDetachedInventory(name,PEER_ID_INEXISTENT);
4795 BoolScopeSet(bool *dst, bool val):
4798 m_orig_state = *m_dst;
4803 *m_dst = m_orig_state;
4810 // actions: time-reversed list
4811 // Return value: success/failure
4812 bool Server::rollbackRevertActions(const std::list<RollbackAction> &actions,
4813 std::list<std::string> *log)
4815 infostream<<"Server::rollbackRevertActions(len="<<actions.size()<<")"<<std::endl;
4816 ServerMap *map = (ServerMap*)(&m_env->getMap());
4817 // Disable rollback report sink while reverting
4818 BoolScopeSet rollback_scope_disable(&m_rollback_sink_enabled, false);
4820 // Fail if no actions to handle
4821 if(actions.empty()){
4822 log->push_back("Nothing to do.");
4829 for(std::list<RollbackAction>::const_iterator
4830 i = actions.begin();
4831 i != actions.end(); i++)
4833 const RollbackAction &action = *i;
4835 bool success = action.applyRevert(map, this, this);
4838 std::ostringstream os;
4839 os<<"Revert of step ("<<num_tried<<") "<<action.toString()<<" failed";
4840 infostream<<"Map::rollbackRevertActions(): "<<os.str()<<std::endl;
4842 log->push_back(os.str());
4844 std::ostringstream os;
4845 os<<"Successfully reverted step ("<<num_tried<<") "<<action.toString();
4846 infostream<<"Map::rollbackRevertActions(): "<<os.str()<<std::endl;
4848 log->push_back(os.str());
4852 infostream<<"Map::rollbackRevertActions(): "<<num_failed<<"/"<<num_tried
4853 <<" failed"<<std::endl;
4855 // Call it done if less than half failed
4856 return num_failed <= num_tried/2;
4859 // IGameDef interface
4861 IItemDefManager* Server::getItemDefManager()
4865 INodeDefManager* Server::getNodeDefManager()
4869 ICraftDefManager* Server::getCraftDefManager()
4873 ITextureSource* Server::getTextureSource()
4877 IShaderSource* Server::getShaderSource()
4881 u16 Server::allocateUnknownNodeId(const std::string &name)
4883 return m_nodedef->allocateDummy(name);
4885 ISoundManager* Server::getSoundManager()
4887 return &dummySoundManager;
4889 MtEventManager* Server::getEventManager()
4893 IRollbackReportSink* Server::getRollbackReportSink()
4895 if(!m_enable_rollback_recording)
4897 if(!m_rollback_sink_enabled)
4902 IWritableItemDefManager* Server::getWritableItemDefManager()
4906 IWritableNodeDefManager* Server::getWritableNodeDefManager()
4910 IWritableCraftDefManager* Server::getWritableCraftDefManager()
4915 const ModSpec* Server::getModSpec(const std::string &modname)
4917 for(std::vector<ModSpec>::iterator i = m_mods.begin();
4918 i != m_mods.end(); i++){
4919 const ModSpec &mod = *i;
4920 if(mod.name == modname)
4925 void Server::getModNames(std::list<std::string> &modlist)
4927 for(std::vector<ModSpec>::iterator i = m_mods.begin(); i != m_mods.end(); i++)
4929 modlist.push_back(i->name);
4932 std::string Server::getBuiltinLuaPath()
4934 return porting::path_share + DIR_DELIM + "builtin";
4937 v3f findSpawnPos(ServerMap &map)
4939 //return v3f(50,50,50)*BS;
4944 nodepos = v2s16(0,0);
4949 s16 water_level = map.getWaterLevel();
4951 // Try to find a good place a few times
4952 for(s32 i=0; i<1000; i++)
4955 // We're going to try to throw the player to this position
4956 v2s16 nodepos2d = v2s16(
4957 -range + (myrand() % (range * 2)),
4958 -range + (myrand() % (range * 2)));
4960 // Get ground height at point
4961 s16 groundheight = map.findGroundLevel(nodepos2d);
4962 if (groundheight <= water_level) // Don't go underwater
4964 if (groundheight > water_level + 6) // Don't go to high places
4967 nodepos = v3s16(nodepos2d.X, groundheight, nodepos2d.Y);
4968 bool is_good = false;
4970 for (s32 i = 0; i < 10; i++) {
4971 v3s16 blockpos = getNodeBlockPos(nodepos);
4972 map.emergeBlock(blockpos, true);
4973 content_t c = map.getNodeNoEx(nodepos).getContent();
4974 if (c == CONTENT_AIR || c == CONTENT_IGNORE) {
4976 if (air_count >= 2){
4984 // Found a good place
4985 //infostream<<"Searched through "<<i<<" places."<<std::endl;
4991 return intToFloat(nodepos, BS);
4994 PlayerSAO* Server::emergePlayer(const char *name, u16 peer_id)
4996 RemotePlayer *player = NULL;
4997 bool newplayer = false;
5000 Try to get an existing player
5002 player = static_cast<RemotePlayer*>(m_env->getPlayer(name));
5004 // If player is already connected, cancel
5005 if(player != NULL && player->peer_id != 0)
5007 infostream<<"emergePlayer(): Player already connected"<<std::endl;
5012 If player with the wanted peer_id already exists, cancel.
5014 if(m_env->getPlayer(peer_id) != NULL)
5016 infostream<<"emergePlayer(): Player with wrong name but same"
5017 " peer_id already exists"<<std::endl;
5021 // Load player if it isn't already loaded
5023 player = static_cast<RemotePlayer*>(m_env->loadPlayer(name));
5026 // Create player if it doesn't exist
5029 player = new RemotePlayer(this);
5030 player->updateName(name);
5031 /* Set player position */
5032 infostream<<"Server: Finding spawn place for player \""
5033 <<name<<"\""<<std::endl;
5034 v3f pos = findSpawnPos(m_env->getServerMap());
5035 player->setPosition(pos);
5037 /* Add player to environment */
5038 m_env->addPlayer(player);
5041 // Create a new player active object
5042 PlayerSAO *playersao = new PlayerSAO(m_env, player, peer_id,
5043 getPlayerEffectivePrivs(player->getName()),
5046 /* Clean up old HUD elements from previous sessions */
5049 /* Add object to environment */
5050 m_env->addActiveObject(playersao);
5054 m_script->on_newplayer(playersao);
5060 void dedicated_server_loop(Server &server, bool &kill)
5062 DSTACK(__FUNCTION_NAME);
5064 verbosestream<<"dedicated_server_loop()"<<std::endl;
5066 IntervalLimiter m_profiler_interval;
5070 float steplen = g_settings->getFloat("dedicated_server_step");
5071 // This is kind of a hack but can be done like this
5072 // because server.step() is very light
5074 ScopeProfiler sp(g_profiler, "dedicated server sleep");
5075 sleep_ms((int)(steplen*1000.0));
5077 server.step(steplen);
5079 if(server.getShutdownRequested() || kill)
5081 infostream<<"Dedicated server quitting"<<std::endl;
5083 if(g_settings->getBool("server_announce") == true)
5084 ServerList::sendAnnounce("delete");
5092 float profiler_print_interval =
5093 g_settings->getFloat("profiler_print_interval");
5094 if(profiler_print_interval != 0)
5096 if(m_profiler_interval.step(steplen, profiler_print_interval))
5098 infostream<<"Profiler:"<<std::endl;
5099 g_profiler->print(infostream);
5100 g_profiler->clear();