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 // Perform pending node name resolutions
342 m_nodedef->getResolver()->resolveNodes();
344 // Load the mapgen params from global settings now after any
345 // initial overrides have been set by the mods
346 m_emerge->loadMapgenParams();
348 // Initialize Environment
349 ServerMap *servermap = new ServerMap(path_world, this, m_emerge);
350 m_env = new ServerEnvironment(servermap, m_script, this, m_path_world);
352 m_clients.setEnv(m_env);
354 // Run some callbacks after the MG params have been set up but before activation
355 m_script->environment_OnMapgenInit(&m_emerge->params);
357 // Initialize mapgens
358 m_emerge->initMapgens();
360 // Give environment reference to scripting api
361 m_script->initializeEnvironment(m_env);
363 // Register us to receive map edit events
364 servermap->addEventReceiver(this);
366 // If file exists, load environment metadata
367 if(fs::PathExists(m_path_world + DIR_DELIM "env_meta.txt"))
369 infostream<<"Server: Loading environment metadata"<<std::endl;
373 // Add some test ActiveBlockModifiers to environment
374 add_legacy_abms(m_env, m_nodedef);
376 m_liquid_transform_every = g_settings->getFloat("liquid_update");
381 infostream<<"Server destructing"<<std::endl;
383 // Send shutdown message
384 SendChatMessage(PEER_ID_INEXISTENT, L"*** Server shutting down");
387 JMutexAutoLock envlock(m_env_mutex);
389 // Execute script shutdown hooks
390 m_script->on_shutdown();
392 infostream<<"Server: Saving players"<<std::endl;
393 m_env->saveLoadedPlayers();
395 infostream<<"Server: Saving environment metadata"<<std::endl;
403 // stop all emerge threads before deleting players that may have
404 // requested blocks to be emerged
405 m_emerge->stopThreads();
407 // Delete things in the reverse order of creation
410 // N.B. the EmergeManager should be deleted after the Environment since Map
411 // depends on EmergeManager to write its current params to the map meta
420 // Deinitialize scripting
421 infostream<<"Server: Deinitializing scripting"<<std::endl;
424 // Delete detached inventories
425 for (std::map<std::string, Inventory*>::iterator
426 i = m_detached_inventories.begin();
427 i != m_detached_inventories.end(); i++) {
432 void Server::start(Address bind_addr)
434 DSTACK(__FUNCTION_NAME);
435 infostream<<"Starting server on "
436 << bind_addr.serializeString() <<"..."<<std::endl;
438 // Stop thread if already running
441 // Initialize connection
442 m_con.SetTimeoutMs(30);
443 m_con.Serve(bind_addr);
448 // ASCII art for the win!
450 <<" .__ __ __ "<<std::endl
451 <<" _____ |__| ____ _____/ |_ ____ _______/ |_ "<<std::endl
452 <<" / \\| |/ \\_/ __ \\ __\\/ __ \\ / ___/\\ __\\"<<std::endl
453 <<"| Y Y \\ | | \\ ___/| | \\ ___/ \\___ \\ | | "<<std::endl
454 <<"|__|_| /__|___| /\\___ >__| \\___ >____ > |__| "<<std::endl
455 <<" \\/ \\/ \\/ \\/ \\/ "<<std::endl;
456 actionstream<<"World at ["<<m_path_world<<"]"<<std::endl;
457 actionstream<<"Server for gameid=\""<<m_gamespec.id
458 <<"\" listening on "<<bind_addr.serializeString()<<":"
459 <<bind_addr.getPort() << "."<<std::endl;
464 DSTACK(__FUNCTION_NAME);
466 infostream<<"Server: Stopping and waiting threads"<<std::endl;
468 // Stop threads (set run=false first so both start stopping)
470 //m_emergethread.setRun(false);
472 //m_emergethread.stop();
474 infostream<<"Server: Threads stopped"<<std::endl;
477 void Server::step(float dtime)
479 DSTACK(__FUNCTION_NAME);
484 JMutexAutoLock lock(m_step_dtime_mutex);
485 m_step_dtime += dtime;
487 // Throw if fatal error occurred in thread
488 std::string async_err = m_async_fatal_error.get();
490 throw ServerError(async_err);
494 void Server::AsyncRunStep(bool initial_step)
496 DSTACK(__FUNCTION_NAME);
498 g_profiler->add("Server::AsyncRunStep (num)", 1);
502 JMutexAutoLock lock1(m_step_dtime_mutex);
503 dtime = m_step_dtime;
507 // Send blocks to clients
511 if((dtime < 0.001) && (initial_step == false))
514 g_profiler->add("Server::AsyncRunStep with dtime (num)", 1);
516 //infostream<<"Server steps "<<dtime<<std::endl;
517 //infostream<<"Server::AsyncRunStep(): dtime="<<dtime<<std::endl;
520 JMutexAutoLock lock1(m_step_dtime_mutex);
521 m_step_dtime -= dtime;
528 m_uptime.set(m_uptime.get() + dtime);
534 Update time of day and overall game time
537 JMutexAutoLock envlock(m_env_mutex);
539 m_env->setTimeOfDaySpeed(g_settings->getFloat("time_speed"));
542 Send to clients at constant intervals
545 m_time_of_day_send_timer -= dtime;
546 if(m_time_of_day_send_timer < 0.0)
548 m_time_of_day_send_timer = g_settings->getFloat("time_send_interval");
549 u16 time = m_env->getTimeOfDay();
550 float time_speed = g_settings->getFloat("time_speed");
551 SendTimeOfDay(PEER_ID_INEXISTENT, time, time_speed);
556 JMutexAutoLock lock(m_env_mutex);
557 // Figure out and report maximum lag to environment
558 float max_lag = m_env->getMaxLagEstimate();
559 max_lag *= 0.9998; // Decrease slowly (about half per 5 minutes)
561 if(dtime > 0.1 && dtime > max_lag * 2.0)
562 infostream<<"Server: Maximum lag peaked to "<<dtime
566 m_env->reportMaxLagEstimate(max_lag);
568 ScopeProfiler sp(g_profiler, "SEnv step");
569 ScopeProfiler sp2(g_profiler, "SEnv step avg", SPT_AVG);
573 const float map_timer_and_unload_dtime = 2.92;
574 if(m_map_timer_and_unload_interval.step(dtime, map_timer_and_unload_dtime))
576 JMutexAutoLock lock(m_env_mutex);
577 // Run Map's timers and unload unused data
578 ScopeProfiler sp(g_profiler, "Server: map timer and unload");
579 m_env->getMap().timerUpdate(map_timer_and_unload_dtime,
580 g_settings->getFloat("server_unload_unused_data_timeout"));
591 JMutexAutoLock lock(m_env_mutex);
593 std::list<u16> clientids = m_clients.getClientIDs();
595 ScopeProfiler sp(g_profiler, "Server: handle players");
597 for(std::list<u16>::iterator
598 i = clientids.begin();
599 i != clientids.end(); ++i)
601 PlayerSAO *playersao = getPlayerSAO(*i);
602 if(playersao == NULL)
606 Handle player HPs (die if hp=0)
608 if(playersao->m_hp_not_sent && g_settings->getBool("enable_damage"))
610 if(playersao->getHP() == 0)
617 Send player breath if changed
619 if(playersao->m_breath_not_sent) {
620 SendPlayerBreath(*i);
624 Send player inventories if necessary
626 if(playersao->m_moved){
628 playersao->m_moved = false;
630 if(playersao->m_inventory_not_sent){
637 /* Transform liquids */
638 m_liquid_transform_timer += dtime;
639 if(m_liquid_transform_timer >= m_liquid_transform_every)
641 m_liquid_transform_timer -= m_liquid_transform_every;
643 JMutexAutoLock lock(m_env_mutex);
645 ScopeProfiler sp(g_profiler, "Server: liquid transform");
647 std::map<v3s16, MapBlock*> modified_blocks;
648 m_env->getMap().transformLiquids(modified_blocks);
653 core::map<v3s16, MapBlock*> lighting_modified_blocks;
654 ServerMap &map = ((ServerMap&)m_env->getMap());
655 map.updateLighting(modified_blocks, lighting_modified_blocks);
657 // Add blocks modified by lighting to modified_blocks
658 for(core::map<v3s16, MapBlock*>::Iterator
659 i = lighting_modified_blocks.getIterator();
660 i.atEnd() == false; i++)
662 MapBlock *block = i.getNode()->getValue();
663 modified_blocks.insert(block->getPos(), block);
667 Set the modified blocks unsent for all the clients
669 if(modified_blocks.size() > 0)
671 SetBlocksNotSent(modified_blocks);
674 m_clients.step(dtime);
676 m_lag += (m_lag > dtime ? -1 : 1) * dtime/100;
678 // send masterserver announce
680 float &counter = m_masterserver_timer;
681 if(!isSingleplayer() && (!counter || counter >= 300.0) &&
682 g_settings->getBool("server_announce"))
684 ServerList::sendAnnounce(counter ? "update" : "start",
685 m_clients.getPlayerNames(),
687 m_env->getGameTime(),
698 Check added and deleted active objects
701 //infostream<<"Server: Checking added and deleted active objects"<<std::endl;
702 JMutexAutoLock envlock(m_env_mutex);
705 std::map<u16, RemoteClient*> clients = m_clients.getClientList();
706 ScopeProfiler sp(g_profiler, "Server: checking added and deleted objs");
708 // Radius inside which objects are active
709 s16 radius = g_settings->getS16("active_object_send_range_blocks");
710 radius *= MAP_BLOCKSIZE;
712 for(std::map<u16, RemoteClient*>::iterator
714 i != clients.end(); ++i)
716 RemoteClient *client = i->second;
718 // If definitions and textures have not been sent, don't
719 // send objects either
720 if (client->getState() < CS_DefinitionsSent)
723 Player *player = m_env->getPlayer(client->peer_id);
726 // This can happen if the client timeouts somehow
727 /*infostream<<"WARNING: "<<__FUNCTION_NAME<<": Client "
729 <<" has no associated player"<<std::endl;*/
732 v3s16 pos = floatToInt(player->getPosition(), BS);
734 std::set<u16> removed_objects;
735 std::set<u16> added_objects;
736 m_env->getRemovedActiveObjects(pos, radius,
737 client->m_known_objects, removed_objects);
738 m_env->getAddedActiveObjects(pos, radius,
739 client->m_known_objects, added_objects);
741 // Ignore if nothing happened
742 if(removed_objects.size() == 0 && added_objects.size() == 0)
744 //infostream<<"active objects: none changed"<<std::endl;
748 std::string data_buffer;
752 // Handle removed objects
753 writeU16((u8*)buf, removed_objects.size());
754 data_buffer.append(buf, 2);
755 for(std::set<u16>::iterator
756 i = removed_objects.begin();
757 i != removed_objects.end(); ++i)
761 ServerActiveObject* obj = m_env->getActiveObject(id);
763 // Add to data buffer for sending
764 writeU16((u8*)buf, id);
765 data_buffer.append(buf, 2);
767 // Remove from known objects
768 client->m_known_objects.erase(id);
770 if(obj && obj->m_known_by_count > 0)
771 obj->m_known_by_count--;
774 // Handle added objects
775 writeU16((u8*)buf, added_objects.size());
776 data_buffer.append(buf, 2);
777 for(std::set<u16>::iterator
778 i = added_objects.begin();
779 i != added_objects.end(); ++i)
783 ServerActiveObject* obj = m_env->getActiveObject(id);
786 u8 type = ACTIVEOBJECT_TYPE_INVALID;
788 infostream<<"WARNING: "<<__FUNCTION_NAME
789 <<": NULL object"<<std::endl;
791 type = obj->getSendType();
793 // Add to data buffer for sending
794 writeU16((u8*)buf, id);
795 data_buffer.append(buf, 2);
796 writeU8((u8*)buf, type);
797 data_buffer.append(buf, 1);
800 data_buffer.append(serializeLongString(
801 obj->getClientInitializationData(client->net_proto_version)));
803 data_buffer.append(serializeLongString(""));
805 // Add to known objects
806 client->m_known_objects.insert(id);
809 obj->m_known_by_count++;
813 SharedBuffer<u8> reply(2 + data_buffer.size());
814 writeU16(&reply[0], TOCLIENT_ACTIVE_OBJECT_REMOVE_ADD);
815 memcpy((char*)&reply[2], data_buffer.c_str(),
818 m_clients.send(client->peer_id, 0, reply, true);
820 verbosestream<<"Server: Sent object remove/add: "
821 <<removed_objects.size()<<" removed, "
822 <<added_objects.size()<<" added, "
823 <<"packet size is "<<reply.getSize()<<std::endl;
828 Collect a list of all the objects known by the clients
829 and report it back to the environment.
832 core::map<u16, bool> all_known_objects;
834 for(core::map<u16, RemoteClient*>::Iterator
835 i = m_clients.getIterator();
836 i.atEnd() == false; i++)
838 RemoteClient *client = i.getNode()->getValue();
839 // Go through all known objects of client
840 for(core::map<u16, bool>::Iterator
841 i = client->m_known_objects.getIterator();
842 i.atEnd()==false; i++)
844 u16 id = i.getNode()->getKey();
845 all_known_objects[id] = true;
849 m_env->setKnownActiveObjects(whatever);
858 JMutexAutoLock envlock(m_env_mutex);
859 ScopeProfiler sp(g_profiler, "Server: sending object messages");
862 // Value = data sent by object
863 std::map<u16, std::list<ActiveObjectMessage>* > buffered_messages;
865 // Get active object messages from environment
868 ActiveObjectMessage aom = m_env->getActiveObjectMessage();
872 std::list<ActiveObjectMessage>* message_list = NULL;
873 std::map<u16, std::list<ActiveObjectMessage>* >::iterator n;
874 n = buffered_messages.find(aom.id);
875 if(n == buffered_messages.end())
877 message_list = new std::list<ActiveObjectMessage>;
878 buffered_messages[aom.id] = message_list;
882 message_list = n->second;
884 message_list->push_back(aom);
888 std::map<u16, RemoteClient*> clients = m_clients.getClientList();
889 // Route data to every client
890 for(std::map<u16, RemoteClient*>::iterator
892 i != clients.end(); ++i)
894 RemoteClient *client = i->second;
895 std::string reliable_data;
896 std::string unreliable_data;
897 // Go through all objects in message buffer
898 for(std::map<u16, std::list<ActiveObjectMessage>* >::iterator
899 j = buffered_messages.begin();
900 j != buffered_messages.end(); ++j)
902 // If object is not known by client, skip it
904 if(client->m_known_objects.find(id) == client->m_known_objects.end())
906 // Get message list of object
907 std::list<ActiveObjectMessage>* list = j->second;
908 // Go through every message
909 for(std::list<ActiveObjectMessage>::iterator
910 k = list->begin(); k != list->end(); ++k)
912 // Compose the full new data with header
913 ActiveObjectMessage aom = *k;
914 std::string new_data;
917 writeU16((u8*)&buf[0], aom.id);
918 new_data.append(buf, 2);
920 new_data += serializeString(aom.datastring);
921 // Add data to buffer
923 reliable_data += new_data;
925 unreliable_data += new_data;
929 reliable_data and unreliable_data are now ready.
932 if(reliable_data.size() > 0)
934 SharedBuffer<u8> reply(2 + reliable_data.size());
935 writeU16(&reply[0], TOCLIENT_ACTIVE_OBJECT_MESSAGES);
936 memcpy((char*)&reply[2], reliable_data.c_str(),
937 reliable_data.size());
939 m_clients.send(client->peer_id, 0, reply, true);
941 if(unreliable_data.size() > 0)
943 SharedBuffer<u8> reply(2 + unreliable_data.size());
944 writeU16(&reply[0], TOCLIENT_ACTIVE_OBJECT_MESSAGES);
945 memcpy((char*)&reply[2], unreliable_data.c_str(),
946 unreliable_data.size());
947 // Send as unreliable
948 m_clients.send(client->peer_id, 1, reply, false);
951 /*if(reliable_data.size() > 0 || unreliable_data.size() > 0)
953 infostream<<"Server: Size of object message data: "
954 <<"reliable: "<<reliable_data.size()
955 <<", unreliable: "<<unreliable_data.size()
961 // Clear buffered_messages
962 for(std::map<u16, std::list<ActiveObjectMessage>* >::iterator
963 i = buffered_messages.begin();
964 i != buffered_messages.end(); ++i)
971 Send queued-for-sending map edit events.
974 // We will be accessing the environment
975 JMutexAutoLock lock(m_env_mutex);
977 // Don't send too many at a time
980 // Single change sending is disabled if queue size is not small
981 bool disable_single_change_sending = false;
982 if(m_unsent_map_edit_queue.size() >= 4)
983 disable_single_change_sending = true;
985 int event_count = m_unsent_map_edit_queue.size();
987 // We'll log the amount of each
990 while(m_unsent_map_edit_queue.size() != 0)
992 MapEditEvent* event = m_unsent_map_edit_queue.pop_front();
994 // Players far away from the change are stored here.
995 // Instead of sending the changes, MapBlocks are set not sent
997 std::list<u16> far_players;
999 if(event->type == MEET_ADDNODE || event->type == MEET_SWAPNODE)
1001 //infostream<<"Server: MEET_ADDNODE"<<std::endl;
1002 prof.add("MEET_ADDNODE", 1);
1003 if(disable_single_change_sending)
1004 sendAddNode(event->p, event->n, event->already_known_by_peer,
1005 &far_players, 5, event->type == MEET_ADDNODE);
1007 sendAddNode(event->p, event->n, event->already_known_by_peer,
1008 &far_players, 30, event->type == MEET_ADDNODE);
1010 else if(event->type == MEET_REMOVENODE)
1012 //infostream<<"Server: MEET_REMOVENODE"<<std::endl;
1013 prof.add("MEET_REMOVENODE", 1);
1014 if(disable_single_change_sending)
1015 sendRemoveNode(event->p, event->already_known_by_peer,
1018 sendRemoveNode(event->p, event->already_known_by_peer,
1021 else if(event->type == MEET_BLOCK_NODE_METADATA_CHANGED)
1023 infostream<<"Server: MEET_BLOCK_NODE_METADATA_CHANGED"<<std::endl;
1024 prof.add("MEET_BLOCK_NODE_METADATA_CHANGED", 1);
1025 setBlockNotSent(event->p);
1027 else if(event->type == MEET_OTHER)
1029 infostream<<"Server: MEET_OTHER"<<std::endl;
1030 prof.add("MEET_OTHER", 1);
1031 for(std::set<v3s16>::iterator
1032 i = event->modified_blocks.begin();
1033 i != event->modified_blocks.end(); ++i)
1035 setBlockNotSent(*i);
1040 prof.add("unknown", 1);
1041 infostream<<"WARNING: Server: Unknown MapEditEvent "
1042 <<((u32)event->type)<<std::endl;
1046 Set blocks not sent to far players
1048 if(far_players.size() > 0)
1050 // Convert list format to that wanted by SetBlocksNotSent
1051 std::map<v3s16, MapBlock*> modified_blocks2;
1052 for(std::set<v3s16>::iterator
1053 i = event->modified_blocks.begin();
1054 i != event->modified_blocks.end(); ++i)
1056 modified_blocks2[*i] =
1057 m_env->getMap().getBlockNoCreateNoEx(*i);
1059 // Set blocks not sent
1060 for(std::list<u16>::iterator
1061 i = far_players.begin();
1062 i != far_players.end(); ++i)
1065 RemoteClient *client = getClient(peer_id);
1068 client->SetBlocksNotSent(modified_blocks2);
1074 /*// Don't send too many at a time
1076 if(count >= 1 && m_unsent_map_edit_queue.size() < 100)
1080 if(event_count >= 5){
1081 infostream<<"Server: MapEditEvents:"<<std::endl;
1082 prof.print(infostream);
1083 } else if(event_count != 0){
1084 verbosestream<<"Server: MapEditEvents:"<<std::endl;
1085 prof.print(verbosestream);
1091 Trigger emergethread (it somehow gets to a non-triggered but
1092 bysy state sometimes)
1095 float &counter = m_emergethread_trigger_timer;
1101 m_emerge->startThreads();
1103 // Update m_enable_rollback_recording here too
1104 m_enable_rollback_recording =
1105 g_settings->getBool("enable_rollback_recording");
1109 // Save map, players and auth stuff
1111 float &counter = m_savemap_timer;
1113 if(counter >= g_settings->getFloat("server_map_save_interval"))
1116 JMutexAutoLock lock(m_env_mutex);
1118 ScopeProfiler sp(g_profiler, "Server: saving stuff");
1121 if (m_banmanager->isModified()) {
1122 m_banmanager->save();
1125 // Save changed parts of map
1126 m_env->getMap().save(MOD_STATE_WRITE_NEEDED);
1129 m_env->saveLoadedPlayers();
1131 // Save environment metadata
1137 void Server::Receive()
1139 DSTACK(__FUNCTION_NAME);
1140 SharedBuffer<u8> data;
1144 datasize = m_con.Receive(peer_id,data);
1145 ProcessData(*data, datasize, peer_id);
1147 catch(con::InvalidIncomingDataException &e)
1149 infostream<<"Server::Receive(): "
1150 "InvalidIncomingDataException: what()="
1151 <<e.what()<<std::endl;
1153 catch(SerializationError &e) {
1154 infostream<<"Server::Receive(): "
1155 "SerializationError: what()="
1156 <<e.what()<<std::endl;
1158 catch(ClientStateError &e)
1160 errorstream << "ProcessData: peer=" << peer_id << e.what() << std::endl;
1161 DenyAccess(peer_id, L"Your client sent something server didn't expect."
1162 L"Try reconnecting or updating your client");
1164 catch(con::PeerNotFoundException &e)
1170 PlayerSAO* Server::StageTwoClientInit(u16 peer_id)
1172 std::string playername = "";
1173 PlayerSAO *playersao = NULL;
1176 RemoteClient* client = m_clients.lockedGetClientNoEx(peer_id, CS_InitDone);
1177 if (client != NULL) {
1178 playername = client->getName();
1179 playersao = emergePlayer(playername.c_str(), peer_id);
1181 } catch (std::exception &e) {
1187 RemotePlayer *player =
1188 static_cast<RemotePlayer*>(m_env->getPlayer(playername.c_str()));
1190 // If failed, cancel
1191 if((playersao == NULL) || (player == NULL))
1193 if(player && player->peer_id != 0){
1194 errorstream<<"Server: "<<playername<<": Failed to emerge player"
1195 <<" (player allocated to an another client)"<<std::endl;
1196 DenyAccess(peer_id, L"Another client is connected with this "
1197 L"name. If your client closed unexpectedly, try again in "
1200 errorstream<<"Server: "<<playername<<": Failed to emerge player"
1202 DenyAccess(peer_id, L"Could not allocate player.");
1208 Send complete position information
1210 SendMovePlayer(peer_id);
1213 SendPlayerPrivileges(peer_id);
1215 // Send inventory formspec
1216 SendPlayerInventoryFormspec(peer_id);
1219 UpdateCrafting(peer_id);
1220 SendInventory(peer_id);
1223 if(g_settings->getBool("enable_damage"))
1224 SendPlayerHP(peer_id);
1227 SendPlayerBreath(peer_id);
1229 // Show death screen if necessary
1231 SendDeathscreen(peer_id, false, v3f(0,0,0));
1233 // Note things in chat if not in simple singleplayer mode
1234 if(!m_simple_singleplayer_mode)
1236 // Send information about server to player in chat
1237 SendChatMessage(peer_id, getStatusString());
1239 // Send information about joining in chat
1241 std::wstring name = L"unknown";
1242 Player *player = m_env->getPlayer(peer_id);
1244 name = narrow_to_wide(player->getName());
1246 std::wstring message;
1249 message += L" joined the game.";
1250 SendChatMessage(PEER_ID_INEXISTENT,message);
1253 Address addr = getPeerAddress(player->peer_id);
1254 std::string ip_str = addr.serializeString();
1255 actionstream<<player->getName() <<" [" << ip_str << "] joins game. " << std::endl;
1260 std::vector<std::string> names = m_clients.getPlayerNames();
1262 actionstream<<player->getName() <<" joins game. List of players: ";
1264 for (std::vector<std::string>::iterator i = names.begin();
1265 i != names.end(); i++)
1267 actionstream << *i << " ";
1270 actionstream << player->getName() <<std::endl;
1275 void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
1277 DSTACK(__FUNCTION_NAME);
1278 // Environment is locked first.
1279 JMutexAutoLock envlock(m_env_mutex);
1281 ScopeProfiler sp(g_profiler, "Server::ProcessData");
1285 Address address = getPeerAddress(peer_id);
1286 addr_s = address.serializeString();
1288 // drop player if is ip is banned
1289 if(m_banmanager->isIpBanned(addr_s)){
1290 std::string ban_name = m_banmanager->getBanName(addr_s);
1291 infostream<<"Server: A banned client tried to connect from "
1292 <<addr_s<<"; banned name was "
1293 <<ban_name<<std::endl;
1294 // This actually doesn't seem to transfer to the client
1295 DenyAccess(peer_id, L"Your ip is banned. Banned name was "
1296 +narrow_to_wide(ban_name));
1300 catch(con::PeerNotFoundException &e)
1303 * no peer for this packet found
1304 * most common reason is peer timeout, e.g. peer didn't
1305 * respond for some time, your server was overloaded or
1308 infostream<<"Server::ProcessData(): Cancelling: peer "
1309 <<peer_id<<" not found"<<std::endl;
1319 ToServerCommand command = (ToServerCommand)readU16(&data[0]);
1321 if(command == TOSERVER_INIT)
1323 // [0] u16 TOSERVER_INIT
1324 // [2] u8 SER_FMT_VER_HIGHEST_READ
1325 // [3] u8[20] player_name
1326 // [23] u8[28] password <--- can be sent without this, from old versions
1328 if(datasize < 2+1+PLAYERNAME_SIZE)
1331 RemoteClient* client = getClient(peer_id, CS_Created);
1333 // If net_proto_version is set, this client has already been handled
1334 if(client->getState() > CS_Created)
1336 verbosestream<<"Server: Ignoring multiple TOSERVER_INITs from "
1337 <<addr_s<<" (peer_id="<<peer_id<<")"<<std::endl;
1341 verbosestream<<"Server: Got TOSERVER_INIT from "<<addr_s<<" (peer_id="
1342 <<peer_id<<")"<<std::endl;
1344 // Do not allow multiple players in simple singleplayer mode.
1345 // This isn't a perfect way to do it, but will suffice for now
1346 if(m_simple_singleplayer_mode && m_clients.getClientIDs().size() > 1){
1347 infostream<<"Server: Not allowing another client ("<<addr_s
1348 <<") to connect in simple singleplayer mode"<<std::endl;
1349 DenyAccess(peer_id, L"Running in simple singleplayer mode.");
1353 // First byte after command is maximum supported
1354 // serialization version
1355 u8 client_max = data[2];
1356 u8 our_max = SER_FMT_VER_HIGHEST_READ;
1357 // Use the highest version supported by both
1358 u8 deployed = std::min(client_max, our_max);
1359 // If it's lower than the lowest supported, give up.
1360 if(deployed < SER_FMT_VER_LOWEST)
1361 deployed = SER_FMT_VER_INVALID;
1363 if(deployed == SER_FMT_VER_INVALID)
1365 actionstream<<"Server: A mismatched client tried to connect from "
1366 <<addr_s<<std::endl;
1367 infostream<<"Server: Cannot negotiate serialization version with "
1368 <<addr_s<<std::endl;
1369 DenyAccess(peer_id, std::wstring(
1370 L"Your client's version is not supported.\n"
1371 L"Server version is ")
1372 + narrow_to_wide(minetest_version_simple) + L"."
1377 client->setPendingSerializationVersion(deployed);
1380 Read and check network protocol version
1383 u16 min_net_proto_version = 0;
1384 if(datasize >= 2+1+PLAYERNAME_SIZE+PASSWORD_SIZE+2)
1385 min_net_proto_version = readU16(&data[2+1+PLAYERNAME_SIZE+PASSWORD_SIZE]);
1387 // Use same version as minimum and maximum if maximum version field
1388 // doesn't exist (backwards compatibility)
1389 u16 max_net_proto_version = min_net_proto_version;
1390 if(datasize >= 2+1+PLAYERNAME_SIZE+PASSWORD_SIZE+2+2)
1391 max_net_proto_version = readU16(&data[2+1+PLAYERNAME_SIZE+PASSWORD_SIZE+2]);
1393 // Start with client's maximum version
1394 u16 net_proto_version = max_net_proto_version;
1396 // Figure out a working version if it is possible at all
1397 if(max_net_proto_version >= SERVER_PROTOCOL_VERSION_MIN ||
1398 min_net_proto_version <= SERVER_PROTOCOL_VERSION_MAX)
1400 // If maximum is larger than our maximum, go with our maximum
1401 if(max_net_proto_version > SERVER_PROTOCOL_VERSION_MAX)
1402 net_proto_version = SERVER_PROTOCOL_VERSION_MAX;
1403 // Else go with client's maximum
1405 net_proto_version = max_net_proto_version;
1408 verbosestream<<"Server: "<<addr_s<<": Protocol version: min: "
1409 <<min_net_proto_version<<", max: "<<max_net_proto_version
1410 <<", chosen: "<<net_proto_version<<std::endl;
1412 client->net_proto_version = net_proto_version;
1414 if(net_proto_version < SERVER_PROTOCOL_VERSION_MIN ||
1415 net_proto_version > SERVER_PROTOCOL_VERSION_MAX)
1417 actionstream<<"Server: A mismatched client tried to connect from "
1418 <<addr_s<<std::endl;
1419 DenyAccess(peer_id, std::wstring(
1420 L"Your client's version is not supported.\n"
1421 L"Server version is ")
1422 + narrow_to_wide(minetest_version_simple) + L",\n"
1423 + L"server's PROTOCOL_VERSION is "
1424 + narrow_to_wide(itos(SERVER_PROTOCOL_VERSION_MIN))
1426 + narrow_to_wide(itos(SERVER_PROTOCOL_VERSION_MAX))
1427 + L", client's PROTOCOL_VERSION is "
1428 + narrow_to_wide(itos(min_net_proto_version))
1430 + narrow_to_wide(itos(max_net_proto_version))
1435 if(g_settings->getBool("strict_protocol_version_checking"))
1437 if(net_proto_version != LATEST_PROTOCOL_VERSION)
1439 actionstream<<"Server: A mismatched (strict) client tried to "
1440 <<"connect from "<<addr_s<<std::endl;
1441 DenyAccess(peer_id, std::wstring(
1442 L"Your client's version is not supported.\n"
1443 L"Server version is ")
1444 + narrow_to_wide(minetest_version_simple) + L",\n"
1445 + L"server's PROTOCOL_VERSION (strict) is "
1446 + narrow_to_wide(itos(LATEST_PROTOCOL_VERSION))
1447 + L", client's PROTOCOL_VERSION is "
1448 + narrow_to_wide(itos(min_net_proto_version))
1450 + narrow_to_wide(itos(max_net_proto_version))
1459 char playername[PLAYERNAME_SIZE];
1460 unsigned int playername_length = 0;
1461 for (; playername_length < PLAYERNAME_SIZE; playername_length++ ) {
1462 playername[playername_length] = data[3+playername_length];
1463 if (data[3+playername_length] == 0)
1467 if (playername_length == PLAYERNAME_SIZE) {
1468 actionstream<<"Server: Player with name exceeding max length "
1469 <<"tried to connect from "<<addr_s<<std::endl;
1470 DenyAccess(peer_id, L"Name too long");
1475 if(playername[0]=='\0')
1477 actionstream<<"Server: Player with an empty name "
1478 <<"tried to connect from "<<addr_s<<std::endl;
1479 DenyAccess(peer_id, L"Empty name");
1483 if(string_allowed(playername, PLAYERNAME_ALLOWED_CHARS)==false)
1485 actionstream<<"Server: Player with an invalid name "
1486 <<"tried to connect from "<<addr_s<<std::endl;
1487 DenyAccess(peer_id, L"Name contains unallowed characters");
1491 if(!isSingleplayer() && strcasecmp(playername, "singleplayer") == 0)
1493 actionstream<<"Server: Player with the name \"singleplayer\" "
1494 <<"tried to connect from "<<addr_s<<std::endl;
1495 DenyAccess(peer_id, L"Name is not allowed");
1501 if(m_script->on_prejoinplayer(playername, addr_s, reason))
1503 actionstream<<"Server: Player with the name \""<<playername<<"\" "
1504 <<"tried to connect from "<<addr_s<<" "
1505 <<"but it was disallowed for the following reason: "
1506 <<reason<<std::endl;
1507 DenyAccess(peer_id, narrow_to_wide(reason.c_str()));
1512 infostream<<"Server: New connection: \""<<playername<<"\" from "
1513 <<addr_s<<" (peer_id="<<peer_id<<")"<<std::endl;
1516 char given_password[PASSWORD_SIZE];
1517 if(datasize < 2+1+PLAYERNAME_SIZE+PASSWORD_SIZE)
1519 // old version - assume blank password
1520 given_password[0] = 0;
1524 for(u32 i=0; i<PASSWORD_SIZE-1; i++)
1526 given_password[i] = data[23+i];
1528 given_password[PASSWORD_SIZE-1] = 0;
1531 if(!base64_is_valid(given_password)){
1532 actionstream<<"Server: "<<playername
1533 <<" supplied invalid password hash"<<std::endl;
1534 DenyAccess(peer_id, L"Invalid password hash");
1538 // Enforce user limit.
1539 // Don't enforce for users that have some admin right
1540 if(m_clients.getClientIDs(CS_Created).size() >= g_settings->getU16("max_users") &&
1541 !checkPriv(playername, "server") &&
1542 !checkPriv(playername, "ban") &&
1543 !checkPriv(playername, "privs") &&
1544 !checkPriv(playername, "password") &&
1545 playername != g_settings->get("name"))
1547 actionstream<<"Server: "<<playername<<" tried to join, but there"
1548 <<" are already max_users="
1549 <<g_settings->getU16("max_users")<<" players."<<std::endl;
1550 DenyAccess(peer_id, L"Too many users.");
1554 std::string checkpwd; // Password hash to check against
1555 bool has_auth = m_script->getAuth(playername, &checkpwd, NULL);
1557 // If no authentication info exists for user, create it
1559 if(!isSingleplayer() &&
1560 g_settings->getBool("disallow_empty_password") &&
1561 std::string(given_password) == ""){
1562 actionstream<<"Server: "<<playername
1563 <<" supplied empty password"<<std::endl;
1564 DenyAccess(peer_id, L"Empty passwords are "
1565 L"disallowed. Set a password and try again.");
1568 std::wstring raw_default_password =
1569 narrow_to_wide(g_settings->get("default_password"));
1570 std::string initial_password =
1571 translatePassword(playername, raw_default_password);
1573 // If default_password is empty, allow any initial password
1574 if (raw_default_password.length() == 0)
1575 initial_password = given_password;
1577 m_script->createAuth(playername, initial_password);
1580 has_auth = m_script->getAuth(playername, &checkpwd, NULL);
1583 actionstream<<"Server: "<<playername<<" cannot be authenticated"
1584 <<" (auth handler does not work?)"<<std::endl;
1585 DenyAccess(peer_id, L"Not allowed to login");
1589 if(given_password != checkpwd){
1590 actionstream<<"Server: "<<playername<<" supplied wrong password"
1592 DenyAccess(peer_id, L"Wrong password");
1596 RemotePlayer *player =
1597 static_cast<RemotePlayer*>(m_env->getPlayer(playername));
1599 if(player && player->peer_id != 0){
1600 errorstream<<"Server: "<<playername<<": Failed to emerge player"
1601 <<" (player allocated to an another client)"<<std::endl;
1602 DenyAccess(peer_id, L"Another client is connected with this "
1603 L"name. If your client closed unexpectedly, try again in "
1607 m_clients.setPlayerName(peer_id,playername);
1610 Answer with a TOCLIENT_INIT
1613 SharedBuffer<u8> reply(2+1+6+8+4);
1614 writeU16(&reply[0], TOCLIENT_INIT);
1615 writeU8(&reply[2], deployed);
1616 //send dummy pos for legacy reasons only
1617 writeV3S16(&reply[2+1], floatToInt(v3f(0,0,0), BS));
1618 writeU64(&reply[2+1+6], m_env->getServerMap().getSeed());
1619 writeF1000(&reply[2+1+6+8], g_settings->getFloat("dedicated_server_step"));
1622 m_clients.send(peer_id, 0, reply, true);
1623 m_clients.event(peer_id, CSE_Init);
1629 if(command == TOSERVER_INIT2)
1632 verbosestream<<"Server: Got TOSERVER_INIT2 from "
1633 <<peer_id<<std::endl;
1635 m_clients.event(peer_id, CSE_GotInit2);
1636 u16 protocol_version = m_clients.getProtocolVersion(peer_id);
1639 ///// begin compatibility code
1640 PlayerSAO* playersao = NULL;
1641 if (protocol_version <= 22) {
1642 playersao = StageTwoClientInit(peer_id);
1644 if (playersao == NULL) {
1646 << "TOSERVER_INIT2 stage 2 client init failed for peer "
1647 << peer_id << std::endl;
1651 ///// end compatibility code
1654 Send some initialization data
1657 infostream<<"Server: Sending content to "
1658 <<getPlayerName(peer_id)<<std::endl;
1660 // Send player movement settings
1661 SendMovement(peer_id);
1663 // Send item definitions
1664 SendItemDef(peer_id, m_itemdef, protocol_version);
1666 // Send node definitions
1667 SendNodeDef(peer_id, m_nodedef, protocol_version);
1669 m_clients.event(peer_id, CSE_SetDefinitionsSent);
1671 // Send media announcement
1672 sendMediaAnnouncement(peer_id);
1674 // Send detached inventories
1675 sendDetachedInventories(peer_id);
1678 u16 time = m_env->getTimeOfDay();
1679 float time_speed = g_settings->getFloat("time_speed");
1680 SendTimeOfDay(peer_id, time, time_speed);
1682 ///// begin compatibility code
1683 if (protocol_version <= 22) {
1684 m_clients.event(peer_id, CSE_SetClientReady);
1685 m_script->on_joinplayer(playersao);
1687 ///// end compatibility code
1689 // Warnings about protocol version can be issued here
1690 if(getClient(peer_id)->net_proto_version < LATEST_PROTOCOL_VERSION)
1692 SendChatMessage(peer_id, L"# Server: WARNING: YOUR CLIENT'S "
1693 L"VERSION MAY NOT BE FULLY COMPATIBLE WITH THIS SERVER!");
1699 u8 peer_ser_ver = getClient(peer_id, CS_InitDone)->serialization_version;
1700 u16 peer_proto_ver = getClient(peer_id, CS_InitDone)->net_proto_version;
1702 if(peer_ser_ver == SER_FMT_VER_INVALID)
1704 errorstream<<"Server::ProcessData(): Cancelling: Peer"
1705 " serialization format invalid or not initialized."
1706 " Skipping incoming command="<<command<<std::endl;
1710 /* Handle commands relate to client startup */
1711 if(command == TOSERVER_REQUEST_MEDIA) {
1712 std::string datastring((char*)&data[2], datasize-2);
1713 std::istringstream is(datastring, std::ios_base::binary);
1715 std::list<std::string> tosend;
1716 u16 numfiles = readU16(is);
1718 infostream<<"Sending "<<numfiles<<" files to "
1719 <<getPlayerName(peer_id)<<std::endl;
1720 verbosestream<<"TOSERVER_REQUEST_MEDIA: "<<std::endl;
1722 for(int i = 0; i < numfiles; i++) {
1723 std::string name = deSerializeString(is);
1724 tosend.push_back(name);
1725 verbosestream<<"TOSERVER_REQUEST_MEDIA: requested file "
1729 sendRequestedMedia(peer_id, tosend);
1732 else if(command == TOSERVER_RECEIVED_MEDIA) {
1735 else if(command == TOSERVER_CLIENT_READY) {
1736 // clients <= protocol version 22 did not send ready message,
1737 // they're already initialized
1738 if (peer_proto_ver <= 22) {
1739 infostream << "Client sent message not expected by a "
1740 << "client using protocol version <= 22,"
1741 << "disconnecing peer_id: " << peer_id << std::endl;
1742 m_con.DisconnectPeer(peer_id);
1746 PlayerSAO* playersao = StageTwoClientInit(peer_id);
1748 if (playersao == NULL) {
1750 << "TOSERVER_CLIENT_READY stage 2 client init failed for peer_id: "
1751 << peer_id << std::endl;
1752 m_con.DisconnectPeer(peer_id);
1757 if(datasize < 2+8) {
1759 << "TOSERVER_CLIENT_READY client sent inconsistent data, disconnecting peer_id: "
1760 << peer_id << std::endl;
1761 m_con.DisconnectPeer(peer_id);
1765 m_clients.setClientVersion(
1767 data[2], data[3], data[4],
1768 std::string((char*) &data[8],(u16) data[6]));
1770 m_clients.event(peer_id, CSE_SetClientReady);
1771 m_script->on_joinplayer(playersao);
1774 else if(command == TOSERVER_GOTBLOCKS)
1787 u16 count = data[2];
1788 for(u16 i=0; i<count; i++)
1790 if((s16)datasize < 2+1+(i+1)*6)
1791 throw con::InvalidIncomingDataException
1792 ("GOTBLOCKS length is too short");
1793 v3s16 p = readV3S16(&data[2+1+i*6]);
1794 /*infostream<<"Server: GOTBLOCKS ("
1795 <<p.X<<","<<p.Y<<","<<p.Z<<")"<<std::endl;*/
1796 RemoteClient *client = getClient(peer_id);
1797 client->GotBlock(p);
1802 if (m_clients.getClientState(peer_id) < CS_Active)
1804 if (command == TOSERVER_PLAYERPOS) return;
1806 errorstream<<"Got packet command: " << command << " for peer id "
1807 << peer_id << " but client isn't active yet. Dropping packet "
1812 Player *player = m_env->getPlayer(peer_id);
1813 if(player == NULL) {
1814 errorstream<<"Server::ProcessData(): Cancelling: "
1815 "No player for peer_id="<<peer_id
1816 << " disconnecting peer!" <<std::endl;
1817 m_con.DisconnectPeer(peer_id);
1821 PlayerSAO *playersao = player->getPlayerSAO();
1822 if(playersao == NULL) {
1823 errorstream<<"Server::ProcessData(): Cancelling: "
1824 "No player object for peer_id="<<peer_id
1825 << " disconnecting peer!" <<std::endl;
1826 m_con.DisconnectPeer(peer_id);
1830 if(command == TOSERVER_PLAYERPOS)
1832 if(datasize < 2+12+12+4+4)
1836 v3s32 ps = readV3S32(&data[start+2]);
1837 v3s32 ss = readV3S32(&data[start+2+12]);
1838 f32 pitch = (f32)readS32(&data[2+12+12]) / 100.0;
1839 f32 yaw = (f32)readS32(&data[2+12+12+4]) / 100.0;
1841 if(datasize >= 2+12+12+4+4+4)
1842 keyPressed = (u32)readU32(&data[2+12+12+4+4]);
1843 v3f position((f32)ps.X/100., (f32)ps.Y/100., (f32)ps.Z/100.);
1844 v3f speed((f32)ss.X/100., (f32)ss.Y/100., (f32)ss.Z/100.);
1845 pitch = wrapDegrees(pitch);
1846 yaw = wrapDegrees(yaw);
1848 player->setPosition(position);
1849 player->setSpeed(speed);
1850 player->setPitch(pitch);
1851 player->setYaw(yaw);
1852 player->keyPressed=keyPressed;
1853 player->control.up = (bool)(keyPressed&1);
1854 player->control.down = (bool)(keyPressed&2);
1855 player->control.left = (bool)(keyPressed&4);
1856 player->control.right = (bool)(keyPressed&8);
1857 player->control.jump = (bool)(keyPressed&16);
1858 player->control.aux1 = (bool)(keyPressed&32);
1859 player->control.sneak = (bool)(keyPressed&64);
1860 player->control.LMB = (bool)(keyPressed&128);
1861 player->control.RMB = (bool)(keyPressed&256);
1863 bool cheated = playersao->checkMovementCheat();
1866 m_script->on_cheat(playersao, "moved_too_fast");
1869 /*infostream<<"Server::ProcessData(): Moved player "<<peer_id<<" to "
1870 <<"("<<position.X<<","<<position.Y<<","<<position.Z<<")"
1871 <<" pitch="<<pitch<<" yaw="<<yaw<<std::endl;*/
1873 else if(command == TOSERVER_DELETEDBLOCKS)
1886 u16 count = data[2];
1887 for(u16 i=0; i<count; i++)
1889 if((s16)datasize < 2+1+(i+1)*6)
1890 throw con::InvalidIncomingDataException
1891 ("DELETEDBLOCKS length is too short");
1892 v3s16 p = readV3S16(&data[2+1+i*6]);
1893 /*infostream<<"Server: DELETEDBLOCKS ("
1894 <<p.X<<","<<p.Y<<","<<p.Z<<")"<<std::endl;*/
1895 RemoteClient *client = getClient(peer_id);
1896 client->SetBlockNotSent(p);
1899 else if(command == TOSERVER_CLICK_OBJECT)
1901 infostream<<"Server: CLICK_OBJECT not supported anymore"<<std::endl;
1904 else if(command == TOSERVER_CLICK_ACTIVEOBJECT)
1906 infostream<<"Server: CLICK_ACTIVEOBJECT not supported anymore"<<std::endl;
1909 else if(command == TOSERVER_GROUND_ACTION)
1911 infostream<<"Server: GROUND_ACTION not supported anymore"<<std::endl;
1915 else if(command == TOSERVER_RELEASE)
1917 infostream<<"Server: RELEASE not supported anymore"<<std::endl;
1920 else if(command == TOSERVER_SIGNTEXT)
1922 infostream<<"Server: SIGNTEXT not supported anymore"
1926 else if(command == TOSERVER_SIGNNODETEXT)
1928 infostream<<"Server: SIGNNODETEXT not supported anymore"
1932 else if(command == TOSERVER_INVENTORY_ACTION)
1934 // Strip command and create a stream
1935 std::string datastring((char*)&data[2], datasize-2);
1936 verbosestream<<"TOSERVER_INVENTORY_ACTION: data="<<datastring<<std::endl;
1937 std::istringstream is(datastring, std::ios_base::binary);
1939 InventoryAction *a = InventoryAction::deSerialize(is);
1942 infostream<<"TOSERVER_INVENTORY_ACTION: "
1943 <<"InventoryAction::deSerialize() returned NULL"
1948 // If something goes wrong, this player is to blame
1949 RollbackScopeActor rollback_scope(m_rollback,
1950 std::string("player:")+player->getName());
1953 Note: Always set inventory not sent, to repair cases
1954 where the client made a bad prediction.
1958 Handle restrictions and special cases of the move action
1960 if(a->getType() == IACTION_MOVE)
1962 IMoveAction *ma = (IMoveAction*)a;
1964 ma->from_inv.applyCurrentPlayer(player->getName());
1965 ma->to_inv.applyCurrentPlayer(player->getName());
1967 setInventoryModified(ma->from_inv);
1968 setInventoryModified(ma->to_inv);
1970 bool from_inv_is_current_player =
1971 (ma->from_inv.type == InventoryLocation::PLAYER) &&
1972 (ma->from_inv.name == player->getName());
1974 bool to_inv_is_current_player =
1975 (ma->to_inv.type == InventoryLocation::PLAYER) &&
1976 (ma->to_inv.name == player->getName());
1979 Disable moving items out of craftpreview
1981 if(ma->from_list == "craftpreview")
1983 infostream<<"Ignoring IMoveAction from "
1984 <<(ma->from_inv.dump())<<":"<<ma->from_list
1985 <<" to "<<(ma->to_inv.dump())<<":"<<ma->to_list
1986 <<" because src is "<<ma->from_list<<std::endl;
1992 Disable moving items into craftresult and craftpreview
1994 if(ma->to_list == "craftpreview" || ma->to_list == "craftresult")
1996 infostream<<"Ignoring IMoveAction from "
1997 <<(ma->from_inv.dump())<<":"<<ma->from_list
1998 <<" to "<<(ma->to_inv.dump())<<":"<<ma->to_list
1999 <<" because dst is "<<ma->to_list<<std::endl;
2004 // Disallow moving items in elsewhere than player's inventory
2005 // if not allowed to interact
2006 if(!checkPriv(player->getName(), "interact") &&
2007 (!from_inv_is_current_player ||
2008 !to_inv_is_current_player))
2010 infostream<<"Cannot move outside of player's inventory: "
2011 <<"No interact privilege"<<std::endl;
2017 Handle restrictions and special cases of the drop action
2019 else if(a->getType() == IACTION_DROP)
2021 IDropAction *da = (IDropAction*)a;
2023 da->from_inv.applyCurrentPlayer(player->getName());
2025 setInventoryModified(da->from_inv);
2028 Disable dropping items out of craftpreview
2030 if(da->from_list == "craftpreview")
2032 infostream<<"Ignoring IDropAction from "
2033 <<(da->from_inv.dump())<<":"<<da->from_list
2034 <<" because src is "<<da->from_list<<std::endl;
2039 // Disallow dropping items if not allowed to interact
2040 if(!checkPriv(player->getName(), "interact"))
2047 Handle restrictions and special cases of the craft action
2049 else if(a->getType() == IACTION_CRAFT)
2051 ICraftAction *ca = (ICraftAction*)a;
2053 ca->craft_inv.applyCurrentPlayer(player->getName());
2055 setInventoryModified(ca->craft_inv);
2057 //bool craft_inv_is_current_player =
2058 // (ca->craft_inv.type == InventoryLocation::PLAYER) &&
2059 // (ca->craft_inv.name == player->getName());
2061 // Disallow crafting if not allowed to interact
2062 if(!checkPriv(player->getName(), "interact"))
2064 infostream<<"Cannot craft: "
2065 <<"No interact privilege"<<std::endl;
2072 a->apply(this, playersao, this);
2076 else if(command == TOSERVER_CHAT_MESSAGE)
2084 std::string datastring((char*)&data[2], datasize-2);
2085 std::istringstream is(datastring, std::ios_base::binary);
2088 is.read((char*)buf, 2);
2089 u16 len = readU16(buf);
2091 std::wstring message;
2092 for(u16 i=0; i<len; i++)
2094 is.read((char*)buf, 2);
2095 message += (wchar_t)readU16(buf);
2098 // If something goes wrong, this player is to blame
2099 RollbackScopeActor rollback_scope(m_rollback,
2100 std::string("player:")+player->getName());
2102 // Get player name of this client
2103 std::wstring name = narrow_to_wide(player->getName());
2106 bool ate = m_script->on_chat_message(player->getName(),
2107 wide_to_narrow(message));
2108 // If script ate the message, don't proceed
2112 // Line to send to players
2114 // Whether to send to the player that sent the line
2115 bool send_to_sender_only = false;
2117 // Commands are implemented in Lua, so only catch invalid
2118 // commands that were not "eaten" and send an error back
2119 if(message[0] == L'/')
2121 message = message.substr(1);
2122 send_to_sender_only = true;
2123 if(message.length() == 0)
2124 line += L"-!- Empty command";
2126 line += L"-!- Invalid command: " + str_split(message, L' ')[0];
2130 if(checkPriv(player->getName(), "shout")){
2136 line += L"-!- You don't have permission to shout.";
2137 send_to_sender_only = true;
2144 Send the message to sender
2146 if (send_to_sender_only)
2148 SendChatMessage(peer_id, line);
2151 Send the message to others
2155 actionstream<<"CHAT: "<<wide_to_narrow(line)<<std::endl;
2157 std::list<u16> clients = m_clients.getClientIDs();
2159 for(std::list<u16>::iterator
2160 i = clients.begin();
2161 i != clients.end(); ++i)
2164 SendChatMessage(*i, line);
2169 else if(command == TOSERVER_DAMAGE)
2171 std::string datastring((char*)&data[2], datasize-2);
2172 std::istringstream is(datastring, std::ios_base::binary);
2173 u8 damage = readU8(is);
2175 if(g_settings->getBool("enable_damage"))
2177 actionstream<<player->getName()<<" damaged by "
2178 <<(int)damage<<" hp at "<<PP(player->getPosition()/BS)
2181 playersao->setHP(playersao->getHP() - damage);
2183 if(playersao->getHP() == 0 && playersao->m_hp_not_sent)
2186 if(playersao->m_hp_not_sent)
2187 SendPlayerHP(peer_id);
2190 else if(command == TOSERVER_BREATH)
2192 std::string datastring((char*)&data[2], datasize-2);
2193 std::istringstream is(datastring, std::ios_base::binary);
2194 u16 breath = readU16(is);
2195 playersao->setBreath(breath);
2196 m_script->player_event(playersao,"breath_changed");
2198 else if(command == TOSERVER_PASSWORD)
2201 [0] u16 TOSERVER_PASSWORD
2202 [2] u8[28] old password
2203 [30] u8[28] new password
2206 if(datasize != 2+PASSWORD_SIZE*2)
2208 /*char password[PASSWORD_SIZE];
2209 for(u32 i=0; i<PASSWORD_SIZE-1; i++)
2210 password[i] = data[2+i];
2211 password[PASSWORD_SIZE-1] = 0;*/
2213 for(u32 i=0; i<PASSWORD_SIZE-1; i++)
2221 for(u32 i=0; i<PASSWORD_SIZE-1; i++)
2223 char c = data[2+PASSWORD_SIZE+i];
2229 if(!base64_is_valid(newpwd)){
2230 infostream<<"Server: "<<player->getName()<<" supplied invalid password hash"<<std::endl;
2231 // Wrong old password supplied!!
2232 SendChatMessage(peer_id, L"Invalid new password hash supplied. Password NOT changed.");
2236 infostream<<"Server: Client requests a password change from "
2237 <<"'"<<oldpwd<<"' to '"<<newpwd<<"'"<<std::endl;
2239 std::string playername = player->getName();
2241 std::string checkpwd;
2242 m_script->getAuth(playername, &checkpwd, NULL);
2244 if(oldpwd != checkpwd)
2246 infostream<<"Server: invalid old password"<<std::endl;
2247 // Wrong old password supplied!!
2248 SendChatMessage(peer_id, L"Invalid old password supplied. Password NOT changed.");
2252 bool success = m_script->setPassword(playername, newpwd);
2254 actionstream<<player->getName()<<" changes password"<<std::endl;
2255 SendChatMessage(peer_id, L"Password change successful.");
2257 actionstream<<player->getName()<<" tries to change password but "
2258 <<"it fails"<<std::endl;
2259 SendChatMessage(peer_id, L"Password change failed or inavailable.");
2262 else if(command == TOSERVER_PLAYERITEM)
2267 u16 item = readU16(&data[2]);
2268 playersao->setWieldIndex(item);
2270 else if(command == TOSERVER_RESPAWN)
2272 if(player->hp != 0 || !g_settings->getBool("enable_damage"))
2275 RespawnPlayer(peer_id);
2277 actionstream<<player->getName()<<" respawns at "
2278 <<PP(player->getPosition()/BS)<<std::endl;
2280 // ActiveObject is added to environment in AsyncRunStep after
2281 // the previous addition has been succesfully removed
2283 else if(command == TOSERVER_INTERACT)
2285 std::string datastring((char*)&data[2], datasize-2);
2286 std::istringstream is(datastring, std::ios_base::binary);
2292 [5] u32 length of the next item
2293 [9] serialized PointedThing
2295 0: start digging (from undersurface) or use
2296 1: stop digging (all parameters ignored)
2297 2: digging completed
2298 3: place block or item (to abovesurface)
2301 u8 action = readU8(is);
2302 u16 item_i = readU16(is);
2303 std::istringstream tmp_is(deSerializeLongString(is), std::ios::binary);
2304 PointedThing pointed;
2305 pointed.deSerialize(tmp_is);
2307 verbosestream<<"TOSERVER_INTERACT: action="<<(int)action<<", item="
2308 <<item_i<<", pointed="<<pointed.dump()<<std::endl;
2312 verbosestream<<"TOSERVER_INTERACT: "<<player->getName()
2313 <<" tried to interact, but is dead!"<<std::endl;
2317 v3f player_pos = playersao->getLastGoodPosition();
2319 // Update wielded item
2320 playersao->setWieldIndex(item_i);
2322 // Get pointed to node (undefined if not POINTEDTYPE_NODE)
2323 v3s16 p_under = pointed.node_undersurface;
2324 v3s16 p_above = pointed.node_abovesurface;
2326 // Get pointed to object (NULL if not POINTEDTYPE_OBJECT)
2327 ServerActiveObject *pointed_object = NULL;
2328 if(pointed.type == POINTEDTHING_OBJECT)
2330 pointed_object = m_env->getActiveObject(pointed.object_id);
2331 if(pointed_object == NULL)
2333 verbosestream<<"TOSERVER_INTERACT: "
2334 "pointed object is NULL"<<std::endl;
2340 v3f pointed_pos_under = player_pos;
2341 v3f pointed_pos_above = player_pos;
2342 if(pointed.type == POINTEDTHING_NODE)
2344 pointed_pos_under = intToFloat(p_under, BS);
2345 pointed_pos_above = intToFloat(p_above, BS);
2347 else if(pointed.type == POINTEDTHING_OBJECT)
2349 pointed_pos_under = pointed_object->getBasePosition();
2350 pointed_pos_above = pointed_pos_under;
2354 Check that target is reasonably close
2355 (only when digging or placing things)
2357 if(action == 0 || action == 2 || action == 3)
2359 float d = player_pos.getDistanceFrom(pointed_pos_under);
2360 float max_d = BS * 14; // Just some large enough value
2362 actionstream<<"Player "<<player->getName()
2363 <<" tried to access "<<pointed.dump()
2365 <<"d="<<d<<", max_d="<<max_d
2366 <<". ignoring."<<std::endl;
2367 // Re-send block to revert change on client-side
2368 RemoteClient *client = getClient(peer_id);
2369 v3s16 blockpos = getNodeBlockPos(floatToInt(pointed_pos_under, BS));
2370 client->SetBlockNotSent(blockpos);
2372 m_script->on_cheat(playersao, "interacted_too_far");
2379 Make sure the player is allowed to do it
2381 if(!checkPriv(player->getName(), "interact"))
2383 actionstream<<player->getName()<<" attempted to interact with "
2384 <<pointed.dump()<<" without 'interact' privilege"
2386 // Re-send block to revert change on client-side
2387 RemoteClient *client = getClient(peer_id);
2388 // Digging completed -> under
2390 v3s16 blockpos = getNodeBlockPos(floatToInt(pointed_pos_under, BS));
2391 client->SetBlockNotSent(blockpos);
2393 // Placement -> above
2395 v3s16 blockpos = getNodeBlockPos(floatToInt(pointed_pos_above, BS));
2396 client->SetBlockNotSent(blockpos);
2402 If something goes wrong, this player is to blame
2404 RollbackScopeActor rollback_scope(m_rollback,
2405 std::string("player:")+player->getName());
2408 0: start digging or punch object
2412 if(pointed.type == POINTEDTHING_NODE)
2415 NOTE: This can be used in the future to check if
2416 somebody is cheating, by checking the timing.
2418 MapNode n(CONTENT_IGNORE);
2421 n = m_env->getMap().getNode(p_under);
2423 catch(InvalidPositionException &e)
2425 infostream<<"Server: Not punching: Node not found."
2426 <<" Adding block to emerge queue."
2428 m_emerge->enqueueBlockEmerge(peer_id, getNodeBlockPos(p_above), false);
2430 if(n.getContent() != CONTENT_IGNORE)
2431 m_script->node_on_punch(p_under, n, playersao, pointed);
2433 playersao->noCheatDigStart(p_under);
2435 else if(pointed.type == POINTEDTHING_OBJECT)
2437 // Skip if object has been removed
2438 if(pointed_object->m_removed)
2441 actionstream<<player->getName()<<" punches object "
2442 <<pointed.object_id<<": "
2443 <<pointed_object->getDescription()<<std::endl;
2445 ItemStack punchitem = playersao->getWieldedItem();
2446 ToolCapabilities toolcap =
2447 punchitem.getToolCapabilities(m_itemdef);
2448 v3f dir = (pointed_object->getBasePosition() -
2449 (player->getPosition() + player->getEyeOffset())
2451 float time_from_last_punch =
2452 playersao->resetTimeFromLastPunch();
2453 pointed_object->punch(dir, &toolcap, playersao,
2454 time_from_last_punch);
2462 else if(action == 1)
2467 2: Digging completed
2469 else if(action == 2)
2471 // Only digging of nodes
2472 if(pointed.type == POINTEDTHING_NODE)
2474 MapNode n(CONTENT_IGNORE);
2477 n = m_env->getMap().getNode(p_under);
2479 catch(InvalidPositionException &e)
2481 infostream<<"Server: Not finishing digging: Node not found."
2482 <<" Adding block to emerge queue."
2484 m_emerge->enqueueBlockEmerge(peer_id, getNodeBlockPos(p_above), false);
2487 /* Cheat prevention */
2488 bool is_valid_dig = true;
2489 if(!isSingleplayer() && !g_settings->getBool("disable_anticheat"))
2491 v3s16 nocheat_p = playersao->getNoCheatDigPos();
2492 float nocheat_t = playersao->getNoCheatDigTime();
2493 playersao->noCheatDigEnd();
2494 // If player didn't start digging this, ignore dig
2495 if(nocheat_p != p_under){
2496 infostream<<"Server: NoCheat: "<<player->getName()
2497 <<" started digging "
2498 <<PP(nocheat_p)<<" and completed digging "
2499 <<PP(p_under)<<"; not digging."<<std::endl;
2500 is_valid_dig = false;
2502 m_script->on_cheat(playersao, "finished_unknown_dig");
2504 // Get player's wielded item
2505 ItemStack playeritem;
2506 InventoryList *mlist = playersao->getInventory()->getList("main");
2508 playeritem = mlist->getItem(playersao->getWieldIndex());
2509 ToolCapabilities playeritem_toolcap =
2510 playeritem.getToolCapabilities(m_itemdef);
2511 // Get diggability and expected digging time
2512 DigParams params = getDigParams(m_nodedef->get(n).groups,
2513 &playeritem_toolcap);
2514 // If can't dig, try hand
2515 if(!params.diggable){
2516 const ItemDefinition &hand = m_itemdef->get("");
2517 const ToolCapabilities *tp = hand.tool_capabilities;
2519 params = getDigParams(m_nodedef->get(n).groups, tp);
2521 // If can't dig, ignore dig
2522 if(!params.diggable){
2523 infostream<<"Server: NoCheat: "<<player->getName()
2524 <<" completed digging "<<PP(p_under)
2525 <<", which is not diggable with tool. not digging."
2527 is_valid_dig = false;
2529 m_script->on_cheat(playersao, "dug_unbreakable");
2531 // Check digging time
2532 // If already invalidated, we don't have to
2534 // Well not our problem then
2536 // Clean and long dig
2537 else if(params.time > 2.0 && nocheat_t * 1.2 > params.time){
2538 // All is good, but grab time from pool; don't care if
2539 // it's actually available
2540 playersao->getDigPool().grab(params.time);
2542 // Short or laggy dig
2543 // Try getting the time from pool
2544 else if(playersao->getDigPool().grab(params.time)){
2549 infostream<<"Server: NoCheat: "<<player->getName()
2550 <<" completed digging "<<PP(p_under)
2551 <<"too fast; not digging."<<std::endl;
2552 is_valid_dig = false;
2554 m_script->on_cheat(playersao, "dug_too_fast");
2558 /* Actually dig node */
2560 if(is_valid_dig && n.getContent() != CONTENT_IGNORE)
2561 m_script->node_on_dig(p_under, n, playersao);
2563 v3s16 blockpos = getNodeBlockPos(floatToInt(pointed_pos_under, BS));
2564 RemoteClient *client = getClient(peer_id);
2565 // Send unusual result (that is, node not being removed)
2566 if(m_env->getMap().getNodeNoEx(p_under).getContent() != CONTENT_AIR)
2568 // Re-send block to revert change on client-side
2569 client->SetBlockNotSent(blockpos);
2572 client->ResendBlockIfOnWire(blockpos);
2578 3: place block or right-click object
2580 else if(action == 3)
2582 ItemStack item = playersao->getWieldedItem();
2584 // Reset build time counter
2585 if(pointed.type == POINTEDTHING_NODE &&
2586 item.getDefinition(m_itemdef).type == ITEM_NODE)
2587 getClient(peer_id)->m_time_from_building = 0.0;
2589 if(pointed.type == POINTEDTHING_OBJECT)
2591 // Right click object
2593 // Skip if object has been removed
2594 if(pointed_object->m_removed)
2597 actionstream<<player->getName()<<" right-clicks object "
2598 <<pointed.object_id<<": "
2599 <<pointed_object->getDescription()<<std::endl;
2602 pointed_object->rightClick(playersao);
2604 else if(m_script->item_OnPlace(
2605 item, playersao, pointed))
2607 // Placement was handled in lua
2609 // Apply returned ItemStack
2610 playersao->setWieldedItem(item);
2613 // If item has node placement prediction, always send the
2614 // blocks to make sure the client knows what exactly happened
2615 RemoteClient *client = getClient(peer_id);
2616 v3s16 blockpos = getNodeBlockPos(floatToInt(pointed_pos_above, BS));
2617 v3s16 blockpos2 = getNodeBlockPos(floatToInt(pointed_pos_under, BS));
2618 if(item.getDefinition(m_itemdef).node_placement_prediction != "") {
2619 client->SetBlockNotSent(blockpos);
2620 if(blockpos2 != blockpos) {
2621 client->SetBlockNotSent(blockpos2);
2625 client->ResendBlockIfOnWire(blockpos);
2626 if(blockpos2 != blockpos) {
2627 client->ResendBlockIfOnWire(blockpos2);
2635 else if(action == 4)
2637 ItemStack item = playersao->getWieldedItem();
2639 actionstream<<player->getName()<<" uses "<<item.name
2640 <<", pointing at "<<pointed.dump()<<std::endl;
2642 if(m_script->item_OnUse(
2643 item, playersao, pointed))
2645 // Apply returned ItemStack
2646 playersao->setWieldedItem(item);
2653 Catch invalid actions
2657 infostream<<"WARNING: Server: Invalid action "
2658 <<action<<std::endl;
2661 else if(command == TOSERVER_REMOVED_SOUNDS)
2663 std::string datastring((char*)&data[2], datasize-2);
2664 std::istringstream is(datastring, std::ios_base::binary);
2666 int num = readU16(is);
2667 for(int k=0; k<num; k++){
2668 s32 id = readS32(is);
2669 std::map<s32, ServerPlayingSound>::iterator i =
2670 m_playing_sounds.find(id);
2671 if(i == m_playing_sounds.end())
2673 ServerPlayingSound &psound = i->second;
2674 psound.clients.erase(peer_id);
2675 if(psound.clients.size() == 0)
2676 m_playing_sounds.erase(i++);
2679 else if(command == TOSERVER_NODEMETA_FIELDS)
2681 std::string datastring((char*)&data[2], datasize-2);
2682 std::istringstream is(datastring, std::ios_base::binary);
2684 v3s16 p = readV3S16(is);
2685 std::string formname = deSerializeString(is);
2686 int num = readU16(is);
2687 std::map<std::string, std::string> fields;
2688 for(int k=0; k<num; k++){
2689 std::string fieldname = deSerializeString(is);
2690 std::string fieldvalue = deSerializeLongString(is);
2691 fields[fieldname] = fieldvalue;
2694 // If something goes wrong, this player is to blame
2695 RollbackScopeActor rollback_scope(m_rollback,
2696 std::string("player:")+player->getName());
2698 // Check the target node for rollback data; leave others unnoticed
2699 RollbackNode rn_old(&m_env->getMap(), p, this);
2701 m_script->node_on_receive_fields(p, formname, fields,playersao);
2703 // Report rollback data
2704 RollbackNode rn_new(&m_env->getMap(), p, this);
2705 if(rollback() && rn_new != rn_old){
2706 RollbackAction action;
2707 action.setSetNode(p, rn_old, rn_new);
2708 rollback()->reportAction(action);
2711 else if(command == TOSERVER_INVENTORY_FIELDS)
2713 std::string datastring((char*)&data[2], datasize-2);
2714 std::istringstream is(datastring, std::ios_base::binary);
2716 std::string formname = deSerializeString(is);
2717 int num = readU16(is);
2718 std::map<std::string, std::string> fields;
2719 for(int k=0; k<num; k++){
2720 std::string fieldname = deSerializeString(is);
2721 std::string fieldvalue = deSerializeLongString(is);
2722 fields[fieldname] = fieldvalue;
2725 m_script->on_playerReceiveFields(playersao, formname, fields);
2729 infostream<<"Server::ProcessData(): Ignoring "
2730 "unknown command "<<command<<std::endl;
2734 catch(SendFailedException &e)
2736 errorstream<<"Server::ProcessData(): SendFailedException: "
2742 void Server::setTimeOfDay(u32 time)
2744 m_env->setTimeOfDay(time);
2745 m_time_of_day_send_timer = 0;
2748 void Server::onMapEditEvent(MapEditEvent *event)
2750 //infostream<<"Server::onMapEditEvent()"<<std::endl;
2751 if(m_ignore_map_edit_events)
2753 if(m_ignore_map_edit_events_area.contains(event->getArea()))
2755 MapEditEvent *e = event->clone();
2756 m_unsent_map_edit_queue.push_back(e);
2759 Inventory* Server::getInventory(const InventoryLocation &loc)
2762 case InventoryLocation::UNDEFINED:
2765 case InventoryLocation::CURRENT_PLAYER:
2768 case InventoryLocation::PLAYER:
2770 Player *player = m_env->getPlayer(loc.name.c_str());
2773 PlayerSAO *playersao = player->getPlayerSAO();
2776 return playersao->getInventory();
2779 case InventoryLocation::NODEMETA:
2781 NodeMetadata *meta = m_env->getMap().getNodeMetadata(loc.p);
2784 return meta->getInventory();
2787 case InventoryLocation::DETACHED:
2789 if(m_detached_inventories.count(loc.name) == 0)
2791 return m_detached_inventories[loc.name];
2799 void Server::setInventoryModified(const InventoryLocation &loc)
2802 case InventoryLocation::UNDEFINED:
2805 case InventoryLocation::PLAYER:
2807 Player *player = m_env->getPlayer(loc.name.c_str());
2810 PlayerSAO *playersao = player->getPlayerSAO();
2813 playersao->m_inventory_not_sent = true;
2814 playersao->m_wielded_item_not_sent = true;
2817 case InventoryLocation::NODEMETA:
2819 v3s16 blockpos = getNodeBlockPos(loc.p);
2821 MapBlock *block = m_env->getMap().getBlockNoCreateNoEx(blockpos);
2823 block->raiseModified(MOD_STATE_WRITE_NEEDED);
2825 setBlockNotSent(blockpos);
2828 case InventoryLocation::DETACHED:
2830 sendDetachedInventory(loc.name,PEER_ID_INEXISTENT);
2838 void Server::SetBlocksNotSent(std::map<v3s16, MapBlock *>& block)
2840 std::list<u16> clients = m_clients.getClientIDs();
2842 // Set the modified blocks unsent for all the clients
2843 for (std::list<u16>::iterator
2844 i = clients.begin();
2845 i != clients.end(); ++i) {
2846 RemoteClient *client = m_clients.lockedGetClientNoEx(*i);
2848 client->SetBlocksNotSent(block);
2853 void Server::peerAdded(con::Peer *peer)
2855 DSTACK(__FUNCTION_NAME);
2856 verbosestream<<"Server::peerAdded(): peer->id="
2857 <<peer->id<<std::endl;
2860 c.type = con::PEER_ADDED;
2861 c.peer_id = peer->id;
2863 m_peer_change_queue.push_back(c);
2866 void Server::deletingPeer(con::Peer *peer, bool timeout)
2868 DSTACK(__FUNCTION_NAME);
2869 verbosestream<<"Server::deletingPeer(): peer->id="
2870 <<peer->id<<", timeout="<<timeout<<std::endl;
2872 m_clients.event(peer->id, CSE_Disconnect);
2874 c.type = con::PEER_REMOVED;
2875 c.peer_id = peer->id;
2876 c.timeout = timeout;
2877 m_peer_change_queue.push_back(c);
2880 bool Server::getClientConInfo(u16 peer_id, con::rtt_stat_type type, float* retval)
2882 *retval = m_con.getPeerStat(peer_id,type);
2883 if (*retval == -1) return false;
2887 bool Server::getClientInfo(
2896 std::string* vers_string
2899 *state = m_clients.getClientState(peer_id);
2901 RemoteClient* client = m_clients.lockedGetClientNoEx(peer_id, CS_Invalid);
2903 if (client == NULL) {
2908 *uptime = client->uptime();
2909 *ser_vers = client->serialization_version;
2910 *prot_vers = client->net_proto_version;
2912 *major = client->getMajor();
2913 *minor = client->getMinor();
2914 *patch = client->getPatch();
2915 *vers_string = client->getPatch();
2922 void Server::handlePeerChanges()
2924 while(m_peer_change_queue.size() > 0)
2926 con::PeerChange c = m_peer_change_queue.pop_front();
2928 verbosestream<<"Server: Handling peer change: "
2929 <<"id="<<c.peer_id<<", timeout="<<c.timeout
2934 case con::PEER_ADDED:
2935 m_clients.CreateClient(c.peer_id);
2938 case con::PEER_REMOVED:
2939 DeleteClient(c.peer_id, c.timeout?CDR_TIMEOUT:CDR_LEAVE);
2943 assert("Invalid peer change event received!" == 0);
2949 void Server::SendMovement(u16 peer_id)
2951 DSTACK(__FUNCTION_NAME);
2952 std::ostringstream os(std::ios_base::binary);
2954 writeU16(os, TOCLIENT_MOVEMENT);
2955 writeF1000(os, g_settings->getFloat("movement_acceleration_default"));
2956 writeF1000(os, g_settings->getFloat("movement_acceleration_air"));
2957 writeF1000(os, g_settings->getFloat("movement_acceleration_fast"));
2958 writeF1000(os, g_settings->getFloat("movement_speed_walk"));
2959 writeF1000(os, g_settings->getFloat("movement_speed_crouch"));
2960 writeF1000(os, g_settings->getFloat("movement_speed_fast"));
2961 writeF1000(os, g_settings->getFloat("movement_speed_climb"));
2962 writeF1000(os, g_settings->getFloat("movement_speed_jump"));
2963 writeF1000(os, g_settings->getFloat("movement_liquid_fluidity"));
2964 writeF1000(os, g_settings->getFloat("movement_liquid_fluidity_smooth"));
2965 writeF1000(os, g_settings->getFloat("movement_liquid_sink"));
2966 writeF1000(os, g_settings->getFloat("movement_gravity"));
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::SendHP(u16 peer_id, u8 hp)
2977 DSTACK(__FUNCTION_NAME);
2978 std::ostringstream os(std::ios_base::binary);
2980 writeU16(os, TOCLIENT_HP);
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::SendBreath(u16 peer_id, u16 breath)
2992 DSTACK(__FUNCTION_NAME);
2993 std::ostringstream os(std::ios_base::binary);
2995 writeU16(os, TOCLIENT_BREATH);
2996 writeU16(os, breath);
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::SendAccessDenied(u16 peer_id,const std::wstring &reason)
3007 DSTACK(__FUNCTION_NAME);
3008 std::ostringstream os(std::ios_base::binary);
3010 writeU16(os, TOCLIENT_ACCESS_DENIED);
3011 os<<serializeWideString(reason);
3014 std::string s = os.str();
3015 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3017 m_clients.send(peer_id, 0, data, true);
3020 void Server::SendDeathscreen(u16 peer_id,bool set_camera_point_target,
3021 v3f camera_point_target)
3023 DSTACK(__FUNCTION_NAME);
3024 std::ostringstream os(std::ios_base::binary);
3026 writeU16(os, TOCLIENT_DEATHSCREEN);
3027 writeU8(os, set_camera_point_target);
3028 writeV3F1000(os, camera_point_target);
3031 std::string s = os.str();
3032 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3034 m_clients.send(peer_id, 0, data, true);
3037 void Server::SendItemDef(u16 peer_id,
3038 IItemDefManager *itemdef, u16 protocol_version)
3040 DSTACK(__FUNCTION_NAME);
3041 std::ostringstream os(std::ios_base::binary);
3045 u32 length of the next item
3046 zlib-compressed serialized ItemDefManager
3048 writeU16(os, TOCLIENT_ITEMDEF);
3049 std::ostringstream tmp_os(std::ios::binary);
3050 itemdef->serialize(tmp_os, protocol_version);
3051 std::ostringstream tmp_os2(std::ios::binary);
3052 compressZlib(tmp_os.str(), tmp_os2);
3053 os<<serializeLongString(tmp_os2.str());
3056 std::string s = os.str();
3057 verbosestream<<"Server: Sending item definitions to id("<<peer_id
3058 <<"): size="<<s.size()<<std::endl;
3059 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3061 m_clients.send(peer_id, 0, data, true);
3064 void Server::SendNodeDef(u16 peer_id,
3065 INodeDefManager *nodedef, u16 protocol_version)
3067 DSTACK(__FUNCTION_NAME);
3068 std::ostringstream os(std::ios_base::binary);
3072 u32 length of the next item
3073 zlib-compressed serialized NodeDefManager
3075 writeU16(os, TOCLIENT_NODEDEF);
3076 std::ostringstream tmp_os(std::ios::binary);
3077 nodedef->serialize(tmp_os, protocol_version);
3078 std::ostringstream tmp_os2(std::ios::binary);
3079 compressZlib(tmp_os.str(), tmp_os2);
3080 os<<serializeLongString(tmp_os2.str());
3083 std::string s = os.str();
3084 verbosestream<<"Server: Sending node definitions to id("<<peer_id
3085 <<"): size="<<s.size()<<std::endl;
3086 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3088 m_clients.send(peer_id, 0, data, true);
3092 Non-static send methods
3095 void Server::SendInventory(u16 peer_id)
3097 DSTACK(__FUNCTION_NAME);
3099 PlayerSAO *playersao = getPlayerSAO(peer_id);
3102 playersao->m_inventory_not_sent = false;
3108 std::ostringstream os;
3109 playersao->getInventory()->serialize(os);
3111 std::string s = os.str();
3113 SharedBuffer<u8> data(s.size()+2);
3114 writeU16(&data[0], TOCLIENT_INVENTORY);
3115 memcpy(&data[2], s.c_str(), s.size());
3118 m_clients.send(peer_id, 0, data, true);
3121 void Server::SendChatMessage(u16 peer_id, const std::wstring &message)
3123 DSTACK(__FUNCTION_NAME);
3125 std::ostringstream os(std::ios_base::binary);
3129 writeU16(buf, TOCLIENT_CHAT_MESSAGE);
3130 os.write((char*)buf, 2);
3133 writeU16(buf, message.size());
3134 os.write((char*)buf, 2);
3137 for(u32 i=0; i<message.size(); i++)
3141 os.write((char*)buf, 2);
3145 std::string s = os.str();
3146 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3148 if (peer_id != PEER_ID_INEXISTENT)
3151 m_clients.send(peer_id, 0, data, true);
3155 m_clients.sendToAll(0,data,true);
3159 void Server::SendShowFormspecMessage(u16 peer_id, const std::string &formspec,
3160 const std::string &formname)
3162 DSTACK(__FUNCTION_NAME);
3164 std::ostringstream os(std::ios_base::binary);
3169 writeU16(buf, TOCLIENT_SHOW_FORMSPEC);
3170 os.write((char*)buf, 2);
3171 os<<serializeLongString(FORMSPEC_VERSION_STRING + formspec);
3172 os<<serializeString(formname);
3175 std::string s = os.str();
3176 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3178 m_clients.send(peer_id, 0, data, true);
3181 // Spawns a particle on peer with peer_id
3182 void Server::SendSpawnParticle(u16 peer_id, v3f pos, v3f velocity, v3f acceleration,
3183 float expirationtime, float size, bool collisiondetection,
3184 bool vertical, std::string texture)
3186 DSTACK(__FUNCTION_NAME);
3188 std::ostringstream os(std::ios_base::binary);
3189 writeU16(os, TOCLIENT_SPAWN_PARTICLE);
3190 writeV3F1000(os, pos);
3191 writeV3F1000(os, velocity);
3192 writeV3F1000(os, acceleration);
3193 writeF1000(os, expirationtime);
3194 writeF1000(os, size);
3195 writeU8(os, collisiondetection);
3196 os<<serializeLongString(texture);
3197 writeU8(os, vertical);
3200 std::string s = os.str();
3201 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3203 if (peer_id != PEER_ID_INEXISTENT)
3206 m_clients.send(peer_id, 0, data, true);
3210 m_clients.sendToAll(0,data,true);
3214 // Adds a ParticleSpawner on peer with peer_id
3215 void Server::SendAddParticleSpawner(u16 peer_id, u16 amount, float spawntime, v3f minpos, v3f maxpos,
3216 v3f minvel, v3f maxvel, v3f minacc, v3f maxacc, float minexptime, float maxexptime,
3217 float minsize, float maxsize, bool collisiondetection, bool vertical, std::string texture, u32 id)
3219 DSTACK(__FUNCTION_NAME);
3221 std::ostringstream os(std::ios_base::binary);
3222 writeU16(os, TOCLIENT_ADD_PARTICLESPAWNER);
3224 writeU16(os, amount);
3225 writeF1000(os, spawntime);
3226 writeV3F1000(os, minpos);
3227 writeV3F1000(os, maxpos);
3228 writeV3F1000(os, minvel);
3229 writeV3F1000(os, maxvel);
3230 writeV3F1000(os, minacc);
3231 writeV3F1000(os, maxacc);
3232 writeF1000(os, minexptime);
3233 writeF1000(os, maxexptime);
3234 writeF1000(os, minsize);
3235 writeF1000(os, maxsize);
3236 writeU8(os, collisiondetection);
3237 os<<serializeLongString(texture);
3239 writeU8(os, vertical);
3242 std::string s = os.str();
3243 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3245 if (peer_id != PEER_ID_INEXISTENT)
3248 m_clients.send(peer_id, 0, data, true);
3251 m_clients.sendToAll(0,data,true);
3255 void Server::SendDeleteParticleSpawner(u16 peer_id, u32 id)
3257 DSTACK(__FUNCTION_NAME);
3259 std::ostringstream os(std::ios_base::binary);
3260 writeU16(os, TOCLIENT_DELETE_PARTICLESPAWNER);
3265 std::string s = os.str();
3266 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3268 if (peer_id != PEER_ID_INEXISTENT) {
3270 m_clients.send(peer_id, 0, data, true);
3273 m_clients.sendToAll(0,data,true);
3278 void Server::SendHUDAdd(u16 peer_id, u32 id, HudElement *form)
3280 std::ostringstream os(std::ios_base::binary);
3283 writeU16(os, TOCLIENT_HUDADD);
3285 writeU8(os, (u8)form->type);
3286 writeV2F1000(os, form->pos);
3287 os << serializeString(form->name);
3288 writeV2F1000(os, form->scale);
3289 os << serializeString(form->text);
3290 writeU32(os, form->number);
3291 writeU32(os, form->item);
3292 writeU32(os, form->dir);
3293 writeV2F1000(os, form->align);
3294 writeV2F1000(os, form->offset);
3295 writeV3F1000(os, form->world_pos);
3296 writeV2S32(os,form->size);
3299 std::string s = os.str();
3300 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3302 m_clients.send(peer_id, 1, data, true);
3305 void Server::SendHUDRemove(u16 peer_id, u32 id)
3307 std::ostringstream os(std::ios_base::binary);
3310 writeU16(os, TOCLIENT_HUDRM);
3314 std::string s = os.str();
3315 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3318 m_clients.send(peer_id, 1, data, true);
3321 void Server::SendHUDChange(u16 peer_id, u32 id, HudElementStat stat, void *value)
3323 std::ostringstream os(std::ios_base::binary);
3326 writeU16(os, TOCLIENT_HUDCHANGE);
3328 writeU8(os, (u8)stat);
3331 case HUD_STAT_SCALE:
3332 case HUD_STAT_ALIGN:
3333 case HUD_STAT_OFFSET:
3334 writeV2F1000(os, *(v2f *)value);
3338 os << serializeString(*(std::string *)value);
3340 case HUD_STAT_WORLD_POS:
3341 writeV3F1000(os, *(v3f *)value);
3344 writeV2S32(os,*(v2s32 *)value);
3346 case HUD_STAT_NUMBER:
3350 writeU32(os, *(u32 *)value);
3355 std::string s = os.str();
3356 SharedBuffer<u8> data((u8 *)s.c_str(), s.size());
3358 m_clients.send(peer_id, 0, data, true);
3361 void Server::SendHUDSetFlags(u16 peer_id, u32 flags, u32 mask)
3363 std::ostringstream os(std::ios_base::binary);
3366 writeU16(os, TOCLIENT_HUD_SET_FLAGS);
3368 //////////////////////////// compatibility code to be removed //////////////
3369 flags &= ~(HUD_FLAG_HEALTHBAR_VISIBLE | HUD_FLAG_BREATHBAR_VISIBLE);
3370 ////////////////////////////////////////////////////////////////////////////
3371 writeU32(os, flags);
3375 std::string s = os.str();
3376 SharedBuffer<u8> data((u8 *)s.c_str(), s.size());
3378 m_clients.send(peer_id, 0, data, true);
3381 void Server::SendHUDSetParam(u16 peer_id, u16 param, const std::string &value)
3383 std::ostringstream os(std::ios_base::binary);
3386 writeU16(os, TOCLIENT_HUD_SET_PARAM);
3387 writeU16(os, param);
3388 os<<serializeString(value);
3391 std::string s = os.str();
3392 SharedBuffer<u8> data((u8 *)s.c_str(), s.size());
3394 m_clients.send(peer_id, 0, data, true);
3397 void Server::SendSetSky(u16 peer_id, const video::SColor &bgcolor,
3398 const std::string &type, const std::vector<std::string> ¶ms)
3400 std::ostringstream os(std::ios_base::binary);
3403 writeU16(os, TOCLIENT_SET_SKY);
3404 writeARGB8(os, bgcolor);
3405 os<<serializeString(type);
3406 writeU16(os, params.size());
3407 for(size_t i=0; i<params.size(); i++)
3408 os<<serializeString(params[i]);
3411 std::string s = os.str();
3412 SharedBuffer<u8> data((u8 *)s.c_str(), s.size());
3414 m_clients.send(peer_id, 0, data, true);
3417 void Server::SendOverrideDayNightRatio(u16 peer_id, bool do_override,
3420 std::ostringstream os(std::ios_base::binary);
3423 writeU16(os, TOCLIENT_OVERRIDE_DAY_NIGHT_RATIO);
3424 writeU8(os, do_override);
3425 writeU16(os, ratio*65535);
3428 std::string s = os.str();
3429 SharedBuffer<u8> data((u8 *)s.c_str(), s.size());
3431 m_clients.send(peer_id, 0, data, true);
3434 void Server::SendTimeOfDay(u16 peer_id, u16 time, f32 time_speed)
3436 DSTACK(__FUNCTION_NAME);
3439 SharedBuffer<u8> data(2+2+4);
3440 writeU16(&data[0], TOCLIENT_TIME_OF_DAY);
3441 writeU16(&data[2], time);
3442 writeF1000(&data[4], time_speed);
3444 if (peer_id == PEER_ID_INEXISTENT) {
3445 m_clients.sendToAll(0,data,true);
3449 m_clients.send(peer_id, 0, data, true);
3453 void Server::SendPlayerHP(u16 peer_id)
3455 DSTACK(__FUNCTION_NAME);
3456 PlayerSAO *playersao = getPlayerSAO(peer_id);
3458 playersao->m_hp_not_sent = false;
3459 SendHP(peer_id, playersao->getHP());
3460 m_script->player_event(playersao,"health_changed");
3462 // Send to other clients
3463 std::string str = gob_cmd_punched(playersao->readDamage(), playersao->getHP());
3464 ActiveObjectMessage aom(playersao->getId(), true, str);
3465 playersao->m_messages_out.push_back(aom);
3468 void Server::SendPlayerBreath(u16 peer_id)
3470 DSTACK(__FUNCTION_NAME);
3471 PlayerSAO *playersao = getPlayerSAO(peer_id);
3473 playersao->m_breath_not_sent = false;
3474 m_script->player_event(playersao,"breath_changed");
3475 SendBreath(peer_id, playersao->getBreath());
3478 void Server::SendMovePlayer(u16 peer_id)
3480 DSTACK(__FUNCTION_NAME);
3481 Player *player = m_env->getPlayer(peer_id);
3484 std::ostringstream os(std::ios_base::binary);
3485 writeU16(os, TOCLIENT_MOVE_PLAYER);
3486 writeV3F1000(os, player->getPosition());
3487 writeF1000(os, player->getPitch());
3488 writeF1000(os, player->getYaw());
3491 v3f pos = player->getPosition();
3492 f32 pitch = player->getPitch();
3493 f32 yaw = player->getYaw();
3494 verbosestream<<"Server: Sending TOCLIENT_MOVE_PLAYER"
3495 <<" pos=("<<pos.X<<","<<pos.Y<<","<<pos.Z<<")"
3502 std::string s = os.str();
3503 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3505 m_clients.send(peer_id, 0, data, true);
3508 void Server::SendLocalPlayerAnimations(u16 peer_id, v2s32 animation_frames[4], f32 animation_speed)
3510 std::ostringstream os(std::ios_base::binary);
3512 writeU16(os, TOCLIENT_LOCAL_PLAYER_ANIMATIONS);
3513 writeV2S32(os, animation_frames[0]);
3514 writeV2S32(os, animation_frames[1]);
3515 writeV2S32(os, animation_frames[2]);
3516 writeV2S32(os, animation_frames[3]);
3517 writeF1000(os, animation_speed);
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);
3526 void Server::SendEyeOffset(u16 peer_id, v3f first, v3f third)
3528 std::ostringstream os(std::ios_base::binary);
3530 writeU16(os, TOCLIENT_EYE_OFFSET);
3531 writeV3F1000(os, first);
3532 writeV3F1000(os, third);
3535 std::string s = os.str();
3536 SharedBuffer<u8> data((u8 *)s.c_str(), s.size());
3538 m_clients.send(peer_id, 0, data, true);
3540 void Server::SendPlayerPrivileges(u16 peer_id)
3542 Player *player = m_env->getPlayer(peer_id);
3544 if(player->peer_id == PEER_ID_INEXISTENT)
3547 std::set<std::string> privs;
3548 m_script->getAuth(player->getName(), NULL, &privs);
3550 std::ostringstream os(std::ios_base::binary);
3551 writeU16(os, TOCLIENT_PRIVILEGES);
3552 writeU16(os, privs.size());
3553 for(std::set<std::string>::const_iterator i = privs.begin();
3554 i != privs.end(); i++){
3555 os<<serializeString(*i);
3559 std::string s = os.str();
3560 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3562 m_clients.send(peer_id, 0, data, true);
3565 void Server::SendPlayerInventoryFormspec(u16 peer_id)
3567 Player *player = m_env->getPlayer(peer_id);
3569 if(player->peer_id == PEER_ID_INEXISTENT)
3572 std::ostringstream os(std::ios_base::binary);
3573 writeU16(os, TOCLIENT_INVENTORY_FORMSPEC);
3574 os<<serializeLongString(FORMSPEC_VERSION_STRING + player->inventory_formspec);
3577 std::string s = os.str();
3578 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3580 m_clients.send(peer_id, 0, data, true);
3583 s32 Server::playSound(const SimpleSoundSpec &spec,
3584 const ServerSoundParams ¶ms)
3586 // Find out initial position of sound
3587 bool pos_exists = false;
3588 v3f pos = params.getPos(m_env, &pos_exists);
3589 // If position is not found while it should be, cancel sound
3590 if(pos_exists != (params.type != ServerSoundParams::SSP_LOCAL))
3593 // Filter destination clients
3594 std::list<u16> dst_clients;
3595 if(params.to_player != "")
3597 Player *player = m_env->getPlayer(params.to_player.c_str());
3599 infostream<<"Server::playSound: Player \""<<params.to_player
3600 <<"\" not found"<<std::endl;
3603 if(player->peer_id == PEER_ID_INEXISTENT){
3604 infostream<<"Server::playSound: Player \""<<params.to_player
3605 <<"\" not connected"<<std::endl;
3608 dst_clients.push_back(player->peer_id);
3612 std::list<u16> clients = m_clients.getClientIDs();
3614 for(std::list<u16>::iterator
3615 i = clients.begin(); i != clients.end(); ++i)
3617 Player *player = m_env->getPlayer(*i);
3621 if(player->getPosition().getDistanceFrom(pos) >
3622 params.max_hear_distance)
3625 dst_clients.push_back(*i);
3628 if(dst_clients.size() == 0)
3632 s32 id = m_next_sound_id++;
3633 // The sound will exist as a reference in m_playing_sounds
3634 m_playing_sounds[id] = ServerPlayingSound();
3635 ServerPlayingSound &psound = m_playing_sounds[id];
3636 psound.params = params;
3637 for(std::list<u16>::iterator i = dst_clients.begin();
3638 i != dst_clients.end(); i++)
3639 psound.clients.insert(*i);
3641 std::ostringstream os(std::ios_base::binary);
3642 writeU16(os, TOCLIENT_PLAY_SOUND);
3644 os<<serializeString(spec.name);
3645 writeF1000(os, spec.gain * params.gain);
3646 writeU8(os, params.type);
3647 writeV3F1000(os, pos);
3648 writeU16(os, params.object);
3649 writeU8(os, params.loop);
3651 std::string s = os.str();
3652 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3654 for(std::list<u16>::iterator i = dst_clients.begin();
3655 i != dst_clients.end(); i++){
3657 m_clients.send(*i, 0, data, true);
3661 void Server::stopSound(s32 handle)
3663 // Get sound reference
3664 std::map<s32, ServerPlayingSound>::iterator i =
3665 m_playing_sounds.find(handle);
3666 if(i == m_playing_sounds.end())
3668 ServerPlayingSound &psound = i->second;
3670 std::ostringstream os(std::ios_base::binary);
3671 writeU16(os, TOCLIENT_STOP_SOUND);
3672 writeS32(os, handle);
3674 std::string s = os.str();
3675 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3677 for(std::set<u16>::iterator i = psound.clients.begin();
3678 i != psound.clients.end(); i++){
3680 m_clients.send(*i, 0, data, true);
3682 // Remove sound reference
3683 m_playing_sounds.erase(i);
3686 void Server::sendRemoveNode(v3s16 p, u16 ignore_id,
3687 std::list<u16> *far_players, float far_d_nodes)
3689 float maxd = far_d_nodes*BS;
3690 v3f p_f = intToFloat(p, BS);
3694 SharedBuffer<u8> reply(replysize);
3695 writeU16(&reply[0], TOCLIENT_REMOVENODE);
3696 writeS16(&reply[2], p.X);
3697 writeS16(&reply[4], p.Y);
3698 writeS16(&reply[6], p.Z);
3700 std::list<u16> clients = m_clients.getClientIDs();
3701 for(std::list<u16>::iterator
3702 i = clients.begin();
3703 i != clients.end(); ++i)
3708 Player *player = m_env->getPlayer(*i);
3711 // If player is far away, only set modified blocks not sent
3712 v3f player_pos = player->getPosition();
3713 if(player_pos.getDistanceFrom(p_f) > maxd)
3715 far_players->push_back(*i);
3722 m_clients.send(*i, 0, reply, true);
3726 void Server::sendAddNode(v3s16 p, MapNode n, u16 ignore_id,
3727 std::list<u16> *far_players, float far_d_nodes,
3728 bool remove_metadata)
3730 float maxd = far_d_nodes*BS;
3731 v3f p_f = intToFloat(p, BS);
3733 std::list<u16> clients = m_clients.getClientIDs();
3734 for(std::list<u16>::iterator
3735 i = clients.begin();
3736 i != clients.end(); ++i)
3742 Player *player = m_env->getPlayer(*i);
3745 // If player is far away, only set modified blocks not sent
3746 v3f player_pos = player->getPosition();
3747 if(player_pos.getDistanceFrom(p_f) > maxd)
3749 far_players->push_back(*i);
3754 SharedBuffer<u8> reply(0);
3756 RemoteClient* client = m_clients.lockedGetClientNoEx(*i);
3760 u32 replysize = 9 + MapNode::serializedLength(client->serialization_version);
3761 reply = SharedBuffer<u8>(replysize);
3762 writeU16(&reply[0], TOCLIENT_ADDNODE);
3763 writeS16(&reply[2], p.X);
3764 writeS16(&reply[4], p.Y);
3765 writeS16(&reply[6], p.Z);
3766 n.serialize(&reply[8], client->serialization_version);
3767 u32 index = 8 + MapNode::serializedLength(client->serialization_version);
3768 writeU8(&reply[index], remove_metadata ? 0 : 1);
3770 if (!remove_metadata) {
3771 if (client->net_proto_version <= 21) {
3772 // Old clients always clear metadata; fix it
3773 // by sending the full block again.
3774 client->SetBlockNotSent(p);
3781 if (reply.getSize() > 0)
3782 m_clients.send(*i, 0, reply, true);
3786 void Server::setBlockNotSent(v3s16 p)
3788 std::list<u16> clients = m_clients.getClientIDs();
3790 for(std::list<u16>::iterator
3791 i = clients.begin();
3792 i != clients.end(); ++i)
3794 RemoteClient *client = m_clients.lockedGetClientNoEx(*i);
3795 client->SetBlockNotSent(p);
3800 void Server::SendBlockNoLock(u16 peer_id, MapBlock *block, u8 ver, u16 net_proto_version)
3802 DSTACK(__FUNCTION_NAME);
3804 v3s16 p = block->getPos();
3808 bool completely_air = true;
3809 for(s16 z0=0; z0<MAP_BLOCKSIZE; z0++)
3810 for(s16 x0=0; x0<MAP_BLOCKSIZE; x0++)
3811 for(s16 y0=0; y0<MAP_BLOCKSIZE; y0++)
3813 if(block->getNodeNoEx(v3s16(x0,y0,z0)).d != CONTENT_AIR)
3815 completely_air = false;
3816 x0 = y0 = z0 = MAP_BLOCKSIZE; // Break out
3821 infostream<<"Server: Sending block ("<<p.X<<","<<p.Y<<","<<p.Z<<"): ";
3823 infostream<<"[completely air] ";
3824 infostream<<std::endl;
3828 Create a packet with the block in the right format
3831 std::ostringstream os(std::ios_base::binary);
3832 block->serialize(os, ver, false);
3833 block->serializeNetworkSpecific(os, net_proto_version);
3834 std::string s = os.str();
3835 SharedBuffer<u8> blockdata((u8*)s.c_str(), s.size());
3837 u32 replysize = 8 + blockdata.getSize();
3838 SharedBuffer<u8> reply(replysize);
3839 writeU16(&reply[0], TOCLIENT_BLOCKDATA);
3840 writeS16(&reply[2], p.X);
3841 writeS16(&reply[4], p.Y);
3842 writeS16(&reply[6], p.Z);
3843 memcpy(&reply[8], *blockdata, blockdata.getSize());
3845 /*infostream<<"Server: Sending block ("<<p.X<<","<<p.Y<<","<<p.Z<<")"
3846 <<": \tpacket size: "<<replysize<<std::endl;*/
3851 m_clients.send(peer_id, 2, reply, true);
3854 void Server::SendBlocks(float dtime)
3856 DSTACK(__FUNCTION_NAME);
3858 JMutexAutoLock envlock(m_env_mutex);
3859 //TODO check if one big lock could be faster then multiple small ones
3861 ScopeProfiler sp(g_profiler, "Server: sel and send blocks to clients");
3863 std::vector<PrioritySortedBlockTransfer> queue;
3865 s32 total_sending = 0;
3868 ScopeProfiler sp(g_profiler, "Server: selecting blocks for sending");
3870 std::list<u16> clients = m_clients.getClientIDs();
3873 for(std::list<u16>::iterator
3874 i = clients.begin();
3875 i != clients.end(); ++i)
3877 RemoteClient *client = m_clients.lockedGetClientNoEx(*i, CS_Active);
3882 total_sending += client->SendingCount();
3883 client->GetNextBlocks(m_env,m_emerge, dtime, queue);
3889 // Lowest priority number comes first.
3890 // Lowest is most important.
3891 std::sort(queue.begin(), queue.end());
3894 for(u32 i=0; i<queue.size(); i++)
3896 //TODO: Calculate limit dynamically
3897 if(total_sending >= g_settings->getS32
3898 ("max_simultaneous_block_sends_server_total"))
3901 PrioritySortedBlockTransfer q = queue[i];
3903 MapBlock *block = NULL;
3906 block = m_env->getMap().getBlockNoCreate(q.pos);
3908 catch(InvalidPositionException &e)
3913 RemoteClient *client = m_clients.lockedGetClientNoEx(q.peer_id, CS_Active);
3918 SendBlockNoLock(q.peer_id, block, client->serialization_version, client->net_proto_version);
3920 client->SentBlock(q.pos);
3926 void Server::fillMediaCache()
3928 DSTACK(__FUNCTION_NAME);
3930 infostream<<"Server: Calculating media file checksums"<<std::endl;
3932 // Collect all media file paths
3933 std::list<std::string> paths;
3934 for(std::vector<ModSpec>::iterator i = m_mods.begin();
3935 i != m_mods.end(); i++){
3936 const ModSpec &mod = *i;
3937 paths.push_back(mod.path + DIR_DELIM + "textures");
3938 paths.push_back(mod.path + DIR_DELIM + "sounds");
3939 paths.push_back(mod.path + DIR_DELIM + "media");
3940 paths.push_back(mod.path + DIR_DELIM + "models");
3942 paths.push_back(porting::path_user + DIR_DELIM + "textures" + DIR_DELIM + "server");
3944 // Collect media file information from paths into cache
3945 for(std::list<std::string>::iterator i = paths.begin();
3946 i != paths.end(); i++)
3948 std::string mediapath = *i;
3949 std::vector<fs::DirListNode> dirlist = fs::GetDirListing(mediapath);
3950 for(u32 j=0; j<dirlist.size(); j++){
3951 if(dirlist[j].dir) // Ignode dirs
3953 std::string filename = dirlist[j].name;
3954 // If name contains illegal characters, ignore the file
3955 if(!string_allowed(filename, TEXTURENAME_ALLOWED_CHARS)){
3956 infostream<<"Server: ignoring illegal file name: \""
3957 <<filename<<"\""<<std::endl;
3960 // If name is not in a supported format, ignore it
3961 const char *supported_ext[] = {
3962 ".png", ".jpg", ".bmp", ".tga",
3963 ".pcx", ".ppm", ".psd", ".wal", ".rgb",
3965 ".x", ".b3d", ".md2", ".obj",
3968 if(removeStringEnd(filename, supported_ext) == ""){
3969 infostream<<"Server: ignoring unsupported file extension: \""
3970 <<filename<<"\""<<std::endl;
3973 // Ok, attempt to load the file and add to cache
3974 std::string filepath = mediapath + DIR_DELIM + filename;
3976 std::ifstream fis(filepath.c_str(), std::ios_base::binary);
3977 if(fis.good() == false){
3978 errorstream<<"Server::fillMediaCache(): Could not open \""
3979 <<filename<<"\" for reading"<<std::endl;
3982 std::ostringstream tmp_os(std::ios_base::binary);
3986 fis.read(buf, 1024);
3987 std::streamsize len = fis.gcount();
3988 tmp_os.write(buf, len);
3997 errorstream<<"Server::fillMediaCache(): Failed to read \""
3998 <<filename<<"\""<<std::endl;
4001 if(tmp_os.str().length() == 0){
4002 errorstream<<"Server::fillMediaCache(): Empty file \""
4003 <<filepath<<"\""<<std::endl;
4008 sha1.addBytes(tmp_os.str().c_str(), tmp_os.str().length());
4010 unsigned char *digest = sha1.getDigest();
4011 std::string sha1_base64 = base64_encode(digest, 20);
4012 std::string sha1_hex = hex_encode((char*)digest, 20);
4016 this->m_media[filename] = MediaInfo(filepath, sha1_base64);
4017 verbosestream<<"Server: "<<sha1_hex<<" is "<<filename<<std::endl;
4022 struct SendableMediaAnnouncement
4025 std::string sha1_digest;
4027 SendableMediaAnnouncement(const std::string &name_="",
4028 const std::string &sha1_digest_=""):
4030 sha1_digest(sha1_digest_)
4034 void Server::sendMediaAnnouncement(u16 peer_id)
4036 DSTACK(__FUNCTION_NAME);
4038 verbosestream<<"Server: Announcing files to id("<<peer_id<<")"
4041 std::list<SendableMediaAnnouncement> file_announcements;
4043 for(std::map<std::string, MediaInfo>::iterator i = m_media.begin();
4044 i != m_media.end(); i++){
4046 file_announcements.push_back(
4047 SendableMediaAnnouncement(i->first, i->second.sha1_digest));
4051 std::ostringstream os(std::ios_base::binary);
4059 u16 length of sha1_digest
4064 writeU16(os, TOCLIENT_ANNOUNCE_MEDIA);
4065 writeU16(os, file_announcements.size());
4067 for(std::list<SendableMediaAnnouncement>::iterator
4068 j = file_announcements.begin();
4069 j != file_announcements.end(); ++j){
4070 os<<serializeString(j->name);
4071 os<<serializeString(j->sha1_digest);
4073 os<<serializeString(g_settings->get("remote_media"));
4076 std::string s = os.str();
4077 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
4080 m_clients.send(peer_id, 0, data, true);
4083 struct SendableMedia
4089 SendableMedia(const std::string &name_="", const std::string &path_="",
4090 const std::string &data_=""):
4097 void Server::sendRequestedMedia(u16 peer_id,
4098 const std::list<std::string> &tosend)
4100 DSTACK(__FUNCTION_NAME);
4102 verbosestream<<"Server::sendRequestedMedia(): "
4103 <<"Sending files to client"<<std::endl;
4107 // Put 5kB in one bunch (this is not accurate)
4108 u32 bytes_per_bunch = 5000;
4110 std::vector< std::list<SendableMedia> > file_bunches;
4111 file_bunches.push_back(std::list<SendableMedia>());
4113 u32 file_size_bunch_total = 0;
4115 for(std::list<std::string>::const_iterator i = tosend.begin();
4116 i != tosend.end(); ++i)
4118 const std::string &name = *i;
4120 if(m_media.find(name) == m_media.end()){
4121 errorstream<<"Server::sendRequestedMedia(): Client asked for "
4122 <<"unknown file \""<<(name)<<"\""<<std::endl;
4126 //TODO get path + name
4127 std::string tpath = m_media[name].path;
4130 std::ifstream fis(tpath.c_str(), std::ios_base::binary);
4131 if(fis.good() == false){
4132 errorstream<<"Server::sendRequestedMedia(): Could not open \""
4133 <<tpath<<"\" for reading"<<std::endl;
4136 std::ostringstream tmp_os(std::ios_base::binary);
4140 fis.read(buf, 1024);
4141 std::streamsize len = fis.gcount();
4142 tmp_os.write(buf, len);
4143 file_size_bunch_total += len;
4152 errorstream<<"Server::sendRequestedMedia(): Failed to read \""
4153 <<name<<"\""<<std::endl;
4156 /*infostream<<"Server::sendRequestedMedia(): Loaded \""
4157 <<tname<<"\""<<std::endl;*/
4159 file_bunches[file_bunches.size()-1].push_back(
4160 SendableMedia(name, tpath, tmp_os.str()));
4162 // Start next bunch if got enough data
4163 if(file_size_bunch_total >= bytes_per_bunch){
4164 file_bunches.push_back(std::list<SendableMedia>());
4165 file_size_bunch_total = 0;
4170 /* Create and send packets */
4172 u32 num_bunches = file_bunches.size();
4173 for(u32 i=0; i<num_bunches; i++)
4175 std::ostringstream os(std::ios_base::binary);
4179 u16 total number of texture bunches
4180 u16 index of this bunch
4181 u32 number of files in this bunch
4190 writeU16(os, TOCLIENT_MEDIA);
4191 writeU16(os, num_bunches);
4193 writeU32(os, file_bunches[i].size());
4195 for(std::list<SendableMedia>::iterator
4196 j = file_bunches[i].begin();
4197 j != file_bunches[i].end(); ++j){
4198 os<<serializeString(j->name);
4199 os<<serializeLongString(j->data);
4203 std::string s = os.str();
4204 verbosestream<<"Server::sendRequestedMedia(): bunch "
4205 <<i<<"/"<<num_bunches
4206 <<" files="<<file_bunches[i].size()
4207 <<" size=" <<s.size()<<std::endl;
4208 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
4210 m_clients.send(peer_id, 2, data, true);
4214 void Server::sendDetachedInventory(const std::string &name, u16 peer_id)
4216 if(m_detached_inventories.count(name) == 0){
4217 errorstream<<__FUNCTION_NAME<<": \""<<name<<"\" not found"<<std::endl;
4220 Inventory *inv = m_detached_inventories[name];
4222 std::ostringstream os(std::ios_base::binary);
4223 writeU16(os, TOCLIENT_DETACHED_INVENTORY);
4224 os<<serializeString(name);
4228 std::string s = os.str();
4229 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
4231 if (peer_id != PEER_ID_INEXISTENT)
4234 m_clients.send(peer_id, 0, data, true);
4238 m_clients.sendToAll(0,data,true);
4242 void Server::sendDetachedInventories(u16 peer_id)
4244 DSTACK(__FUNCTION_NAME);
4246 for(std::map<std::string, Inventory*>::iterator
4247 i = m_detached_inventories.begin();
4248 i != m_detached_inventories.end(); i++){
4249 const std::string &name = i->first;
4250 //Inventory *inv = i->second;
4251 sendDetachedInventory(name, peer_id);
4259 void Server::DiePlayer(u16 peer_id)
4261 DSTACK(__FUNCTION_NAME);
4263 PlayerSAO *playersao = getPlayerSAO(peer_id);
4266 infostream<<"Server::DiePlayer(): Player "
4267 <<playersao->getPlayer()->getName()
4268 <<" dies"<<std::endl;
4270 playersao->setHP(0);
4272 // Trigger scripted stuff
4273 m_script->on_dieplayer(playersao);
4275 SendPlayerHP(peer_id);
4276 SendDeathscreen(peer_id, false, v3f(0,0,0));
4279 void Server::RespawnPlayer(u16 peer_id)
4281 DSTACK(__FUNCTION_NAME);
4283 PlayerSAO *playersao = getPlayerSAO(peer_id);
4286 infostream<<"Server::RespawnPlayer(): Player "
4287 <<playersao->getPlayer()->getName()
4288 <<" respawns"<<std::endl;
4290 playersao->setHP(PLAYER_MAX_HP);
4292 bool repositioned = m_script->on_respawnplayer(playersao);
4294 v3f pos = findSpawnPos(m_env->getServerMap());
4295 playersao->setPos(pos);
4299 void Server::DenyAccess(u16 peer_id, const std::wstring &reason)
4301 DSTACK(__FUNCTION_NAME);
4303 SendAccessDenied(peer_id, reason);
4304 m_clients.event(peer_id, CSE_SetDenied);
4305 m_con.DisconnectPeer(peer_id);
4308 void Server::DeleteClient(u16 peer_id, ClientDeletionReason reason)
4310 DSTACK(__FUNCTION_NAME);
4311 std::wstring message;
4314 Clear references to playing sounds
4316 for(std::map<s32, ServerPlayingSound>::iterator
4317 i = m_playing_sounds.begin();
4318 i != m_playing_sounds.end();)
4320 ServerPlayingSound &psound = i->second;
4321 psound.clients.erase(peer_id);
4322 if(psound.clients.size() == 0)
4323 m_playing_sounds.erase(i++);
4328 Player *player = m_env->getPlayer(peer_id);
4330 // Collect information about leaving in chat
4332 if(player != NULL && reason != CDR_DENY)
4334 std::wstring name = narrow_to_wide(player->getName());
4337 message += L" left the game.";
4338 if(reason == CDR_TIMEOUT)
4339 message += L" (timed out)";
4343 /* Run scripts and remove from environment */
4347 PlayerSAO *playersao = player->getPlayerSAO();
4350 m_script->on_leaveplayer(playersao);
4352 playersao->disconnected();
4360 if(player != NULL && reason != CDR_DENY)
4362 std::ostringstream os(std::ios_base::binary);
4363 std::list<u16> clients = m_clients.getClientIDs();
4365 for(std::list<u16>::iterator
4366 i = clients.begin();
4367 i != clients.end(); ++i)
4370 Player *player = m_env->getPlayer(*i);
4373 // Get name of player
4374 os<<player->getName()<<" ";
4377 actionstream<<player->getName()<<" "
4378 <<(reason==CDR_TIMEOUT?"times out.":"leaves game.")
4379 <<" List of players: "<<os.str()<<std::endl;
4383 JMutexAutoLock env_lock(m_env_mutex);
4384 m_clients.DeleteClient(peer_id);
4388 // Send leave chat message to all remaining clients
4389 if(message.length() != 0)
4390 SendChatMessage(PEER_ID_INEXISTENT,message);
4393 void Server::UpdateCrafting(u16 peer_id)
4395 DSTACK(__FUNCTION_NAME);
4397 Player* player = m_env->getPlayer(peer_id);
4400 // Get a preview for crafting
4402 InventoryLocation loc;
4403 loc.setPlayer(player->getName());
4404 getCraftingResult(&player->inventory, preview, false, this);
4405 m_env->getScriptIface()->item_CraftPredict(preview, player->getPlayerSAO(), (&player->inventory)->getList("craft"), loc);
4407 // Put the new preview in
4408 InventoryList *plist = player->inventory.getList("craftpreview");
4410 assert(plist->getSize() >= 1);
4411 plist->changeItem(0, preview);
4414 RemoteClient* Server::getClient(u16 peer_id, ClientState state_min)
4416 RemoteClient *client = getClientNoEx(peer_id,state_min);
4418 throw ClientNotFoundException("Client not found");
4422 RemoteClient* Server::getClientNoEx(u16 peer_id, ClientState state_min)
4424 return m_clients.getClientNoEx(peer_id, state_min);
4427 std::string Server::getPlayerName(u16 peer_id)
4429 Player *player = m_env->getPlayer(peer_id);
4431 return "[id="+itos(peer_id)+"]";
4432 return player->getName();
4435 PlayerSAO* Server::getPlayerSAO(u16 peer_id)
4437 Player *player = m_env->getPlayer(peer_id);
4440 return player->getPlayerSAO();
4443 std::wstring Server::getStatusString()
4445 std::wostringstream os(std::ios_base::binary);
4448 os<<L"version="<<narrow_to_wide(minetest_version_simple);
4450 os<<L", uptime="<<m_uptime.get();
4452 os<<L", max_lag="<<m_env->getMaxLagEstimate();
4453 // Information about clients
4456 std::list<u16> clients = m_clients.getClientIDs();
4457 for(std::list<u16>::iterator i = clients.begin();
4458 i != clients.end(); ++i)
4461 Player *player = m_env->getPlayer(*i);
4462 // Get name of player
4463 std::wstring name = L"unknown";
4465 name = narrow_to_wide(player->getName());
4466 // Add name to information string
4474 if(((ServerMap*)(&m_env->getMap()))->isSavingEnabled() == false)
4475 os<<std::endl<<L"# Server: "<<" WARNING: Map saving is disabled.";
4476 if(g_settings->get("motd") != "")
4477 os<<std::endl<<L"# Server: "<<narrow_to_wide(g_settings->get("motd"));
4481 std::set<std::string> Server::getPlayerEffectivePrivs(const std::string &name)
4483 std::set<std::string> privs;
4484 m_script->getAuth(name, NULL, &privs);
4488 bool Server::checkPriv(const std::string &name, const std::string &priv)
4490 std::set<std::string> privs = getPlayerEffectivePrivs(name);
4491 return (privs.count(priv) != 0);
4494 void Server::reportPrivsModified(const std::string &name)
4497 std::list<u16> clients = m_clients.getClientIDs();
4498 for(std::list<u16>::iterator
4499 i = clients.begin();
4500 i != clients.end(); ++i){
4501 Player *player = m_env->getPlayer(*i);
4502 reportPrivsModified(player->getName());
4505 Player *player = m_env->getPlayer(name.c_str());
4508 SendPlayerPrivileges(player->peer_id);
4509 PlayerSAO *sao = player->getPlayerSAO();
4512 sao->updatePrivileges(
4513 getPlayerEffectivePrivs(name),
4518 void Server::reportInventoryFormspecModified(const std::string &name)
4520 Player *player = m_env->getPlayer(name.c_str());
4523 SendPlayerInventoryFormspec(player->peer_id);
4526 void Server::setIpBanned(const std::string &ip, const std::string &name)
4528 m_banmanager->add(ip, name);
4531 void Server::unsetIpBanned(const std::string &ip_or_name)
4533 m_banmanager->remove(ip_or_name);
4536 std::string Server::getBanDescription(const std::string &ip_or_name)
4538 return m_banmanager->getBanDescription(ip_or_name);
4541 void Server::notifyPlayer(const char *name, const std::wstring &msg)
4543 Player *player = m_env->getPlayer(name);
4547 if (player->peer_id == PEER_ID_INEXISTENT)
4550 SendChatMessage(player->peer_id, msg);
4553 bool Server::showFormspec(const char *playername, const std::string &formspec, const std::string &formname)
4555 Player *player = m_env->getPlayer(playername);
4559 infostream<<"showFormspec: couldn't find player:"<<playername<<std::endl;
4563 SendShowFormspecMessage(player->peer_id, formspec, formname);
4567 u32 Server::hudAdd(Player *player, HudElement *form) {
4571 u32 id = player->addHud(form);
4573 SendHUDAdd(player->peer_id, id, form);
4578 bool Server::hudRemove(Player *player, u32 id) {
4582 HudElement* todel = player->removeHud(id);
4589 SendHUDRemove(player->peer_id, id);
4593 bool Server::hudChange(Player *player, u32 id, HudElementStat stat, void *data) {
4597 SendHUDChange(player->peer_id, id, stat, data);
4601 bool Server::hudSetFlags(Player *player, u32 flags, u32 mask) {
4605 SendHUDSetFlags(player->peer_id, flags, mask);
4606 player->hud_flags = flags;
4608 PlayerSAO* playersao = player->getPlayerSAO();
4610 if (playersao == NULL)
4613 m_script->player_event(playersao, "hud_changed");
4617 bool Server::hudSetHotbarItemcount(Player *player, s32 hotbar_itemcount) {
4620 if (hotbar_itemcount <= 0 || hotbar_itemcount > HUD_HOTBAR_ITEMCOUNT_MAX)
4623 std::ostringstream os(std::ios::binary);
4624 writeS32(os, hotbar_itemcount);
4625 SendHUDSetParam(player->peer_id, HUD_PARAM_HOTBAR_ITEMCOUNT, os.str());
4629 void Server::hudSetHotbarImage(Player *player, std::string name) {
4633 SendHUDSetParam(player->peer_id, HUD_PARAM_HOTBAR_IMAGE, name);
4636 void Server::hudSetHotbarSelectedImage(Player *player, std::string name) {
4640 SendHUDSetParam(player->peer_id, HUD_PARAM_HOTBAR_SELECTED_IMAGE, name);
4643 bool Server::setLocalPlayerAnimations(Player *player, v2s32 animation_frames[4], f32 frame_speed)
4648 SendLocalPlayerAnimations(player->peer_id, animation_frames, frame_speed);
4652 bool Server::setPlayerEyeOffset(Player *player, v3f first, v3f third)
4657 SendEyeOffset(player->peer_id, first, third);
4661 bool Server::setSky(Player *player, const video::SColor &bgcolor,
4662 const std::string &type, const std::vector<std::string> ¶ms)
4667 SendSetSky(player->peer_id, bgcolor, type, params);
4671 bool Server::overrideDayNightRatio(Player *player, bool do_override,
4677 SendOverrideDayNightRatio(player->peer_id, do_override, ratio);
4681 void Server::notifyPlayers(const std::wstring &msg)
4683 SendChatMessage(PEER_ID_INEXISTENT,msg);
4686 void Server::spawnParticle(const char *playername, v3f pos,
4687 v3f velocity, v3f acceleration,
4688 float expirationtime, float size, bool
4689 collisiondetection, bool vertical, std::string texture)
4691 Player *player = m_env->getPlayer(playername);
4694 SendSpawnParticle(player->peer_id, pos, velocity, acceleration,
4695 expirationtime, size, collisiondetection, vertical, texture);
4698 void Server::spawnParticleAll(v3f pos, v3f velocity, v3f acceleration,
4699 float expirationtime, float size,
4700 bool collisiondetection, bool vertical, std::string texture)
4702 SendSpawnParticle(PEER_ID_INEXISTENT,pos, velocity, acceleration,
4703 expirationtime, size, collisiondetection, vertical, texture);
4706 u32 Server::addParticleSpawner(const char *playername,
4707 u16 amount, float spawntime,
4708 v3f minpos, v3f maxpos,
4709 v3f minvel, v3f maxvel,
4710 v3f minacc, v3f maxacc,
4711 float minexptime, float maxexptime,
4712 float minsize, float maxsize,
4713 bool collisiondetection, bool vertical, std::string texture)
4715 Player *player = m_env->getPlayer(playername);
4720 for(;;) // look for unused particlespawner id
4723 if (std::find(m_particlespawner_ids.begin(),
4724 m_particlespawner_ids.end(), id)
4725 == m_particlespawner_ids.end())
4727 m_particlespawner_ids.push_back(id);
4732 SendAddParticleSpawner(player->peer_id, amount, spawntime,
4733 minpos, maxpos, minvel, maxvel, minacc, maxacc,
4734 minexptime, maxexptime, minsize, maxsize,
4735 collisiondetection, vertical, texture, id);
4740 u32 Server::addParticleSpawnerAll(u16 amount, float spawntime,
4741 v3f minpos, v3f maxpos,
4742 v3f minvel, v3f maxvel,
4743 v3f minacc, v3f maxacc,
4744 float minexptime, float maxexptime,
4745 float minsize, float maxsize,
4746 bool collisiondetection, bool vertical, std::string texture)
4749 for(;;) // look for unused particlespawner id
4752 if (std::find(m_particlespawner_ids.begin(),
4753 m_particlespawner_ids.end(), id)
4754 == m_particlespawner_ids.end())
4756 m_particlespawner_ids.push_back(id);
4761 SendAddParticleSpawner(PEER_ID_INEXISTENT, amount, spawntime,
4762 minpos, maxpos, minvel, maxvel, minacc, maxacc,
4763 minexptime, maxexptime, minsize, maxsize,
4764 collisiondetection, vertical, texture, id);
4769 void Server::deleteParticleSpawner(const char *playername, u32 id)
4771 Player *player = m_env->getPlayer(playername);
4775 m_particlespawner_ids.erase(
4776 std::remove(m_particlespawner_ids.begin(),
4777 m_particlespawner_ids.end(), id),
4778 m_particlespawner_ids.end());
4779 SendDeleteParticleSpawner(player->peer_id, id);
4782 void Server::deleteParticleSpawnerAll(u32 id)
4784 m_particlespawner_ids.erase(
4785 std::remove(m_particlespawner_ids.begin(),
4786 m_particlespawner_ids.end(), id),
4787 m_particlespawner_ids.end());
4788 SendDeleteParticleSpawner(PEER_ID_INEXISTENT, id);
4791 Inventory* Server::createDetachedInventory(const std::string &name)
4793 if(m_detached_inventories.count(name) > 0){
4794 infostream<<"Server clearing detached inventory \""<<name<<"\""<<std::endl;
4795 delete m_detached_inventories[name];
4797 infostream<<"Server creating detached inventory \""<<name<<"\""<<std::endl;
4799 Inventory *inv = new Inventory(m_itemdef);
4801 m_detached_inventories[name] = inv;
4802 //TODO find a better way to do this
4803 sendDetachedInventory(name,PEER_ID_INEXISTENT);
4810 BoolScopeSet(bool *dst, bool val):
4813 m_orig_state = *m_dst;
4818 *m_dst = m_orig_state;
4825 // actions: time-reversed list
4826 // Return value: success/failure
4827 bool Server::rollbackRevertActions(const std::list<RollbackAction> &actions,
4828 std::list<std::string> *log)
4830 infostream<<"Server::rollbackRevertActions(len="<<actions.size()<<")"<<std::endl;
4831 ServerMap *map = (ServerMap*)(&m_env->getMap());
4832 // Disable rollback report sink while reverting
4833 BoolScopeSet rollback_scope_disable(&m_rollback_sink_enabled, false);
4835 // Fail if no actions to handle
4836 if(actions.empty()){
4837 log->push_back("Nothing to do.");
4844 for(std::list<RollbackAction>::const_iterator
4845 i = actions.begin();
4846 i != actions.end(); i++)
4848 const RollbackAction &action = *i;
4850 bool success = action.applyRevert(map, this, this);
4853 std::ostringstream os;
4854 os<<"Revert of step ("<<num_tried<<") "<<action.toString()<<" failed";
4855 infostream<<"Map::rollbackRevertActions(): "<<os.str()<<std::endl;
4857 log->push_back(os.str());
4859 std::ostringstream os;
4860 os<<"Successfully reverted step ("<<num_tried<<") "<<action.toString();
4861 infostream<<"Map::rollbackRevertActions(): "<<os.str()<<std::endl;
4863 log->push_back(os.str());
4867 infostream<<"Map::rollbackRevertActions(): "<<num_failed<<"/"<<num_tried
4868 <<" failed"<<std::endl;
4870 // Call it done if less than half failed
4871 return num_failed <= num_tried/2;
4874 // IGameDef interface
4876 IItemDefManager* Server::getItemDefManager()
4880 INodeDefManager* Server::getNodeDefManager()
4884 ICraftDefManager* Server::getCraftDefManager()
4888 ITextureSource* Server::getTextureSource()
4892 IShaderSource* Server::getShaderSource()
4896 scene::ISceneManager* Server::getSceneManager()
4901 u16 Server::allocateUnknownNodeId(const std::string &name)
4903 return m_nodedef->allocateDummy(name);
4905 ISoundManager* Server::getSoundManager()
4907 return &dummySoundManager;
4909 MtEventManager* Server::getEventManager()
4913 IRollbackReportSink* Server::getRollbackReportSink()
4915 if(!m_enable_rollback_recording)
4917 if(!m_rollback_sink_enabled)
4922 IWritableItemDefManager* Server::getWritableItemDefManager()
4926 IWritableNodeDefManager* Server::getWritableNodeDefManager()
4930 IWritableCraftDefManager* Server::getWritableCraftDefManager()
4935 const ModSpec* Server::getModSpec(const std::string &modname)
4937 for(std::vector<ModSpec>::iterator i = m_mods.begin();
4938 i != m_mods.end(); i++){
4939 const ModSpec &mod = *i;
4940 if(mod.name == modname)
4945 void Server::getModNames(std::list<std::string> &modlist)
4947 for(std::vector<ModSpec>::iterator i = m_mods.begin(); i != m_mods.end(); i++)
4949 modlist.push_back(i->name);
4952 std::string Server::getBuiltinLuaPath()
4954 return porting::path_share + DIR_DELIM + "builtin";
4957 v3f findSpawnPos(ServerMap &map)
4959 //return v3f(50,50,50)*BS;
4964 nodepos = v2s16(0,0);
4969 s16 water_level = map.getWaterLevel();
4971 // Try to find a good place a few times
4972 for(s32 i=0; i<1000; i++)
4975 // We're going to try to throw the player to this position
4976 v2s16 nodepos2d = v2s16(
4977 -range + (myrand() % (range * 2)),
4978 -range + (myrand() % (range * 2)));
4980 // Get ground height at point
4981 s16 groundheight = map.findGroundLevel(nodepos2d);
4982 if (groundheight <= water_level) // Don't go underwater
4984 if (groundheight > water_level + 6) // Don't go to high places
4987 nodepos = v3s16(nodepos2d.X, groundheight, nodepos2d.Y);
4988 bool is_good = false;
4990 for (s32 i = 0; i < 10; i++) {
4991 v3s16 blockpos = getNodeBlockPos(nodepos);
4992 map.emergeBlock(blockpos, true);
4993 content_t c = map.getNodeNoEx(nodepos).getContent();
4994 if (c == CONTENT_AIR || c == CONTENT_IGNORE) {
4996 if (air_count >= 2){
5004 // Found a good place
5005 //infostream<<"Searched through "<<i<<" places."<<std::endl;
5011 return intToFloat(nodepos, BS);
5014 PlayerSAO* Server::emergePlayer(const char *name, u16 peer_id)
5016 RemotePlayer *player = NULL;
5017 bool newplayer = false;
5020 Try to get an existing player
5022 player = static_cast<RemotePlayer*>(m_env->getPlayer(name));
5024 // If player is already connected, cancel
5025 if(player != NULL && player->peer_id != 0)
5027 infostream<<"emergePlayer(): Player already connected"<<std::endl;
5032 If player with the wanted peer_id already exists, cancel.
5034 if(m_env->getPlayer(peer_id) != NULL)
5036 infostream<<"emergePlayer(): Player with wrong name but same"
5037 " peer_id already exists"<<std::endl;
5041 // Load player if it isn't already loaded
5043 player = static_cast<RemotePlayer*>(m_env->loadPlayer(name));
5046 // Create player if it doesn't exist
5049 player = new RemotePlayer(this, name);
5050 // Set player position
5051 infostream<<"Server: Finding spawn place for player \""
5052 <<name<<"\""<<std::endl;
5053 v3f pos = findSpawnPos(m_env->getServerMap());
5054 player->setPosition(pos);
5056 // Make sure the player is saved
5057 player->setModified(true);
5059 // Add player to environment
5060 m_env->addPlayer(player);
5063 // Create a new player active object
5064 PlayerSAO *playersao = new PlayerSAO(m_env, player, peer_id,
5065 getPlayerEffectivePrivs(player->getName()),
5068 /* Clean up old HUD elements from previous sessions */
5071 /* Add object to environment */
5072 m_env->addActiveObject(playersao);
5076 m_script->on_newplayer(playersao);
5082 void dedicated_server_loop(Server &server, bool &kill)
5084 DSTACK(__FUNCTION_NAME);
5086 verbosestream<<"dedicated_server_loop()"<<std::endl;
5088 IntervalLimiter m_profiler_interval;
5092 float steplen = g_settings->getFloat("dedicated_server_step");
5093 // This is kind of a hack but can be done like this
5094 // because server.step() is very light
5096 ScopeProfiler sp(g_profiler, "dedicated server sleep");
5097 sleep_ms((int)(steplen*1000.0));
5099 server.step(steplen);
5101 if(server.getShutdownRequested() || kill)
5103 infostream<<"Dedicated server quitting"<<std::endl;
5105 if(g_settings->getBool("server_announce") == true)
5106 ServerList::sendAnnounce("delete");
5114 float profiler_print_interval =
5115 g_settings->getFloat("profiler_print_interval");
5116 if(profiler_print_interval != 0)
5118 if(m_profiler_interval.step(steplen, profiler_print_interval))
5120 infostream<<"Profiler:"<<std::endl;
5121 g_profiler->print(infostream);
5122 g_profiler->clear();