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(),
690 m_emerge->params.mg_name,
699 Check added and deleted active objects
702 //infostream<<"Server: Checking added and deleted active objects"<<std::endl;
703 JMutexAutoLock envlock(m_env_mutex);
706 std::map<u16, RemoteClient*> clients = m_clients.getClientList();
707 ScopeProfiler sp(g_profiler, "Server: checking added and deleted objs");
709 // Radius inside which objects are active
710 s16 radius = g_settings->getS16("active_object_send_range_blocks");
711 s16 player_radius = g_settings->getS16("player_transfer_distance");
713 if (player_radius == 0 && g_settings->exists("unlimited_player_transfer_distance") &&
714 !g_settings->getBool("unlimited_player_transfer_distance"))
715 player_radius = radius;
717 radius *= MAP_BLOCKSIZE;
718 player_radius *= MAP_BLOCKSIZE;
720 for(std::map<u16, RemoteClient*>::iterator
722 i != clients.end(); ++i)
724 RemoteClient *client = i->second;
726 // If definitions and textures have not been sent, don't
727 // send objects either
728 if (client->getState() < CS_DefinitionsSent)
731 Player *player = m_env->getPlayer(client->peer_id);
734 // This can happen if the client timeouts somehow
735 /*infostream<<"WARNING: "<<__FUNCTION_NAME<<": Client "
737 <<" has no associated player"<<std::endl;*/
740 v3s16 pos = floatToInt(player->getPosition(), BS);
742 std::set<u16> removed_objects;
743 std::set<u16> added_objects;
744 m_env->getRemovedActiveObjects(pos, radius, player_radius,
745 client->m_known_objects, removed_objects);
746 m_env->getAddedActiveObjects(pos, radius, player_radius,
747 client->m_known_objects, added_objects);
749 // Ignore if nothing happened
750 if(removed_objects.size() == 0 && added_objects.size() == 0)
752 //infostream<<"active objects: none changed"<<std::endl;
756 std::string data_buffer;
760 // Handle removed objects
761 writeU16((u8*)buf, removed_objects.size());
762 data_buffer.append(buf, 2);
763 for(std::set<u16>::iterator
764 i = removed_objects.begin();
765 i != removed_objects.end(); ++i)
769 ServerActiveObject* obj = m_env->getActiveObject(id);
771 // Add to data buffer for sending
772 writeU16((u8*)buf, id);
773 data_buffer.append(buf, 2);
775 // Remove from known objects
776 client->m_known_objects.erase(id);
778 if(obj && obj->m_known_by_count > 0)
779 obj->m_known_by_count--;
782 // Handle added objects
783 writeU16((u8*)buf, added_objects.size());
784 data_buffer.append(buf, 2);
785 for(std::set<u16>::iterator
786 i = added_objects.begin();
787 i != added_objects.end(); ++i)
791 ServerActiveObject* obj = m_env->getActiveObject(id);
794 u8 type = ACTIVEOBJECT_TYPE_INVALID;
796 infostream<<"WARNING: "<<__FUNCTION_NAME
797 <<": NULL object"<<std::endl;
799 type = obj->getSendType();
801 // Add to data buffer for sending
802 writeU16((u8*)buf, id);
803 data_buffer.append(buf, 2);
804 writeU8((u8*)buf, type);
805 data_buffer.append(buf, 1);
808 data_buffer.append(serializeLongString(
809 obj->getClientInitializationData(client->net_proto_version)));
811 data_buffer.append(serializeLongString(""));
813 // Add to known objects
814 client->m_known_objects.insert(id);
817 obj->m_known_by_count++;
821 SharedBuffer<u8> reply(2 + data_buffer.size());
822 writeU16(&reply[0], TOCLIENT_ACTIVE_OBJECT_REMOVE_ADD);
823 memcpy((char*)&reply[2], data_buffer.c_str(),
826 m_clients.send(client->peer_id, 0, reply, true);
828 verbosestream<<"Server: Sent object remove/add: "
829 <<removed_objects.size()<<" removed, "
830 <<added_objects.size()<<" added, "
831 <<"packet size is "<<reply.getSize()<<std::endl;
836 Collect a list of all the objects known by the clients
837 and report it back to the environment.
840 core::map<u16, bool> all_known_objects;
842 for(core::map<u16, RemoteClient*>::Iterator
843 i = m_clients.getIterator();
844 i.atEnd() == false; i++)
846 RemoteClient *client = i.getNode()->getValue();
847 // Go through all known objects of client
848 for(core::map<u16, bool>::Iterator
849 i = client->m_known_objects.getIterator();
850 i.atEnd()==false; i++)
852 u16 id = i.getNode()->getKey();
853 all_known_objects[id] = true;
857 m_env->setKnownActiveObjects(whatever);
866 JMutexAutoLock envlock(m_env_mutex);
867 ScopeProfiler sp(g_profiler, "Server: sending object messages");
870 // Value = data sent by object
871 std::map<u16, std::list<ActiveObjectMessage>* > buffered_messages;
873 // Get active object messages from environment
876 ActiveObjectMessage aom = m_env->getActiveObjectMessage();
880 std::list<ActiveObjectMessage>* message_list = NULL;
881 std::map<u16, std::list<ActiveObjectMessage>* >::iterator n;
882 n = buffered_messages.find(aom.id);
883 if(n == buffered_messages.end())
885 message_list = new std::list<ActiveObjectMessage>;
886 buffered_messages[aom.id] = message_list;
890 message_list = n->second;
892 message_list->push_back(aom);
896 std::map<u16, RemoteClient*> clients = m_clients.getClientList();
897 // Route data to every client
898 for(std::map<u16, RemoteClient*>::iterator
900 i != clients.end(); ++i)
902 RemoteClient *client = i->second;
903 std::string reliable_data;
904 std::string unreliable_data;
905 // Go through all objects in message buffer
906 for(std::map<u16, std::list<ActiveObjectMessage>* >::iterator
907 j = buffered_messages.begin();
908 j != buffered_messages.end(); ++j)
910 // If object is not known by client, skip it
912 if(client->m_known_objects.find(id) == client->m_known_objects.end())
914 // Get message list of object
915 std::list<ActiveObjectMessage>* list = j->second;
916 // Go through every message
917 for(std::list<ActiveObjectMessage>::iterator
918 k = list->begin(); k != list->end(); ++k)
920 // Compose the full new data with header
921 ActiveObjectMessage aom = *k;
922 std::string new_data;
925 writeU16((u8*)&buf[0], aom.id);
926 new_data.append(buf, 2);
928 new_data += serializeString(aom.datastring);
929 // Add data to buffer
931 reliable_data += new_data;
933 unreliable_data += new_data;
937 reliable_data and unreliable_data are now ready.
940 if(reliable_data.size() > 0)
942 SharedBuffer<u8> reply(2 + reliable_data.size());
943 writeU16(&reply[0], TOCLIENT_ACTIVE_OBJECT_MESSAGES);
944 memcpy((char*)&reply[2], reliable_data.c_str(),
945 reliable_data.size());
947 m_clients.send(client->peer_id, 0, reply, true);
949 if(unreliable_data.size() > 0)
951 SharedBuffer<u8> reply(2 + unreliable_data.size());
952 writeU16(&reply[0], TOCLIENT_ACTIVE_OBJECT_MESSAGES);
953 memcpy((char*)&reply[2], unreliable_data.c_str(),
954 unreliable_data.size());
955 // Send as unreliable
956 m_clients.send(client->peer_id, 1, reply, false);
959 /*if(reliable_data.size() > 0 || unreliable_data.size() > 0)
961 infostream<<"Server: Size of object message data: "
962 <<"reliable: "<<reliable_data.size()
963 <<", unreliable: "<<unreliable_data.size()
969 // Clear buffered_messages
970 for(std::map<u16, std::list<ActiveObjectMessage>* >::iterator
971 i = buffered_messages.begin();
972 i != buffered_messages.end(); ++i)
979 Send queued-for-sending map edit events.
982 // We will be accessing the environment
983 JMutexAutoLock lock(m_env_mutex);
985 // Don't send too many at a time
988 // Single change sending is disabled if queue size is not small
989 bool disable_single_change_sending = false;
990 if(m_unsent_map_edit_queue.size() >= 4)
991 disable_single_change_sending = true;
993 int event_count = m_unsent_map_edit_queue.size();
995 // We'll log the amount of each
998 while(m_unsent_map_edit_queue.size() != 0)
1000 MapEditEvent* event = m_unsent_map_edit_queue.pop_front();
1002 // Players far away from the change are stored here.
1003 // Instead of sending the changes, MapBlocks are set not sent
1005 std::list<u16> far_players;
1007 if(event->type == MEET_ADDNODE || event->type == MEET_SWAPNODE)
1009 //infostream<<"Server: MEET_ADDNODE"<<std::endl;
1010 prof.add("MEET_ADDNODE", 1);
1011 if(disable_single_change_sending)
1012 sendAddNode(event->p, event->n, event->already_known_by_peer,
1013 &far_players, 5, event->type == MEET_ADDNODE);
1015 sendAddNode(event->p, event->n, event->already_known_by_peer,
1016 &far_players, 30, event->type == MEET_ADDNODE);
1018 else if(event->type == MEET_REMOVENODE)
1020 //infostream<<"Server: MEET_REMOVENODE"<<std::endl;
1021 prof.add("MEET_REMOVENODE", 1);
1022 if(disable_single_change_sending)
1023 sendRemoveNode(event->p, event->already_known_by_peer,
1026 sendRemoveNode(event->p, event->already_known_by_peer,
1029 else if(event->type == MEET_BLOCK_NODE_METADATA_CHANGED)
1031 infostream<<"Server: MEET_BLOCK_NODE_METADATA_CHANGED"<<std::endl;
1032 prof.add("MEET_BLOCK_NODE_METADATA_CHANGED", 1);
1033 setBlockNotSent(event->p);
1035 else if(event->type == MEET_OTHER)
1037 infostream<<"Server: MEET_OTHER"<<std::endl;
1038 prof.add("MEET_OTHER", 1);
1039 for(std::set<v3s16>::iterator
1040 i = event->modified_blocks.begin();
1041 i != event->modified_blocks.end(); ++i)
1043 setBlockNotSent(*i);
1048 prof.add("unknown", 1);
1049 infostream<<"WARNING: Server: Unknown MapEditEvent "
1050 <<((u32)event->type)<<std::endl;
1054 Set blocks not sent to far players
1056 if(far_players.size() > 0)
1058 // Convert list format to that wanted by SetBlocksNotSent
1059 std::map<v3s16, MapBlock*> modified_blocks2;
1060 for(std::set<v3s16>::iterator
1061 i = event->modified_blocks.begin();
1062 i != event->modified_blocks.end(); ++i)
1064 modified_blocks2[*i] =
1065 m_env->getMap().getBlockNoCreateNoEx(*i);
1067 // Set blocks not sent
1068 for(std::list<u16>::iterator
1069 i = far_players.begin();
1070 i != far_players.end(); ++i)
1073 RemoteClient *client = getClient(peer_id);
1076 client->SetBlocksNotSent(modified_blocks2);
1082 /*// Don't send too many at a time
1084 if(count >= 1 && m_unsent_map_edit_queue.size() < 100)
1088 if(event_count >= 5){
1089 infostream<<"Server: MapEditEvents:"<<std::endl;
1090 prof.print(infostream);
1091 } else if(event_count != 0){
1092 verbosestream<<"Server: MapEditEvents:"<<std::endl;
1093 prof.print(verbosestream);
1099 Trigger emergethread (it somehow gets to a non-triggered but
1100 bysy state sometimes)
1103 float &counter = m_emergethread_trigger_timer;
1109 m_emerge->startThreads();
1111 // Update m_enable_rollback_recording here too
1112 m_enable_rollback_recording =
1113 g_settings->getBool("enable_rollback_recording");
1117 // Save map, players and auth stuff
1119 float &counter = m_savemap_timer;
1121 if(counter >= g_settings->getFloat("server_map_save_interval"))
1124 JMutexAutoLock lock(m_env_mutex);
1126 ScopeProfiler sp(g_profiler, "Server: saving stuff");
1129 if (m_banmanager->isModified()) {
1130 m_banmanager->save();
1133 // Save changed parts of map
1134 m_env->getMap().save(MOD_STATE_WRITE_NEEDED);
1137 m_env->saveLoadedPlayers();
1139 // Save environment metadata
1145 void Server::Receive()
1147 DSTACK(__FUNCTION_NAME);
1148 SharedBuffer<u8> data;
1152 datasize = m_con.Receive(peer_id,data);
1153 ProcessData(*data, datasize, peer_id);
1155 catch(con::InvalidIncomingDataException &e)
1157 infostream<<"Server::Receive(): "
1158 "InvalidIncomingDataException: what()="
1159 <<e.what()<<std::endl;
1161 catch(SerializationError &e) {
1162 infostream<<"Server::Receive(): "
1163 "SerializationError: what()="
1164 <<e.what()<<std::endl;
1166 catch(ClientStateError &e)
1168 errorstream << "ProcessData: peer=" << peer_id << e.what() << std::endl;
1169 DenyAccess(peer_id, L"Your client sent something server didn't expect."
1170 L"Try reconnecting or updating your client");
1172 catch(con::PeerNotFoundException &e)
1178 PlayerSAO* Server::StageTwoClientInit(u16 peer_id)
1180 std::string playername = "";
1181 PlayerSAO *playersao = NULL;
1184 RemoteClient* client = m_clients.lockedGetClientNoEx(peer_id, CS_InitDone);
1185 if (client != NULL) {
1186 playername = client->getName();
1187 playersao = emergePlayer(playername.c_str(), peer_id);
1189 } catch (std::exception &e) {
1195 RemotePlayer *player =
1196 static_cast<RemotePlayer*>(m_env->getPlayer(playername.c_str()));
1198 // If failed, cancel
1199 if((playersao == NULL) || (player == NULL))
1201 if(player && player->peer_id != 0){
1202 errorstream<<"Server: "<<playername<<": Failed to emerge player"
1203 <<" (player allocated to an another client)"<<std::endl;
1204 DenyAccess(peer_id, L"Another client is connected with this "
1205 L"name. If your client closed unexpectedly, try again in "
1208 errorstream<<"Server: "<<playername<<": Failed to emerge player"
1210 DenyAccess(peer_id, L"Could not allocate player.");
1216 Send complete position information
1218 SendMovePlayer(peer_id);
1221 SendPlayerPrivileges(peer_id);
1223 // Send inventory formspec
1224 SendPlayerInventoryFormspec(peer_id);
1227 UpdateCrafting(peer_id);
1228 SendInventory(peer_id);
1231 if(g_settings->getBool("enable_damage"))
1232 SendPlayerHP(peer_id);
1235 SendPlayerBreath(peer_id);
1237 // Show death screen if necessary
1239 SendDeathscreen(peer_id, false, v3f(0,0,0));
1241 // Note things in chat if not in simple singleplayer mode
1242 if(!m_simple_singleplayer_mode)
1244 // Send information about server to player in chat
1245 SendChatMessage(peer_id, getStatusString());
1247 // Send information about joining in chat
1249 std::wstring name = L"unknown";
1250 Player *player = m_env->getPlayer(peer_id);
1252 name = narrow_to_wide(player->getName());
1254 std::wstring message;
1257 message += L" joined the game.";
1258 SendChatMessage(PEER_ID_INEXISTENT,message);
1261 Address addr = getPeerAddress(player->peer_id);
1262 std::string ip_str = addr.serializeString();
1263 actionstream<<player->getName() <<" [" << ip_str << "] joins game. " << std::endl;
1268 std::vector<std::string> names = m_clients.getPlayerNames();
1270 actionstream<<player->getName() <<" joins game. List of players: ";
1272 for (std::vector<std::string>::iterator i = names.begin();
1273 i != names.end(); i++)
1275 actionstream << *i << " ";
1278 actionstream << player->getName() <<std::endl;
1283 void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
1285 DSTACK(__FUNCTION_NAME);
1286 // Environment is locked first.
1287 JMutexAutoLock envlock(m_env_mutex);
1289 ScopeProfiler sp(g_profiler, "Server::ProcessData");
1293 Address address = getPeerAddress(peer_id);
1294 addr_s = address.serializeString();
1296 // drop player if is ip is banned
1297 if(m_banmanager->isIpBanned(addr_s)){
1298 std::string ban_name = m_banmanager->getBanName(addr_s);
1299 infostream<<"Server: A banned client tried to connect from "
1300 <<addr_s<<"; banned name was "
1301 <<ban_name<<std::endl;
1302 // This actually doesn't seem to transfer to the client
1303 DenyAccess(peer_id, L"Your ip is banned. Banned name was "
1304 +narrow_to_wide(ban_name));
1308 catch(con::PeerNotFoundException &e)
1311 * no peer for this packet found
1312 * most common reason is peer timeout, e.g. peer didn't
1313 * respond for some time, your server was overloaded or
1316 infostream<<"Server::ProcessData(): Cancelling: peer "
1317 <<peer_id<<" not found"<<std::endl;
1327 ToServerCommand command = (ToServerCommand)readU16(&data[0]);
1329 if(command == TOSERVER_INIT)
1331 // [0] u16 TOSERVER_INIT
1332 // [2] u8 SER_FMT_VER_HIGHEST_READ
1333 // [3] u8[20] player_name
1334 // [23] u8[28] password <--- can be sent without this, from old versions
1336 if(datasize < 2+1+PLAYERNAME_SIZE)
1339 RemoteClient* client = getClient(peer_id, CS_Created);
1341 // If net_proto_version is set, this client has already been handled
1342 if(client->getState() > CS_Created)
1344 verbosestream<<"Server: Ignoring multiple TOSERVER_INITs from "
1345 <<addr_s<<" (peer_id="<<peer_id<<")"<<std::endl;
1349 verbosestream<<"Server: Got TOSERVER_INIT from "<<addr_s<<" (peer_id="
1350 <<peer_id<<")"<<std::endl;
1352 // Do not allow multiple players in simple singleplayer mode.
1353 // This isn't a perfect way to do it, but will suffice for now
1354 if(m_simple_singleplayer_mode && m_clients.getClientIDs().size() > 1){
1355 infostream<<"Server: Not allowing another client ("<<addr_s
1356 <<") to connect in simple singleplayer mode"<<std::endl;
1357 DenyAccess(peer_id, L"Running in simple singleplayer mode.");
1361 // First byte after command is maximum supported
1362 // serialization version
1363 u8 client_max = data[2];
1364 u8 our_max = SER_FMT_VER_HIGHEST_READ;
1365 // Use the highest version supported by both
1366 u8 deployed = std::min(client_max, our_max);
1367 // If it's lower than the lowest supported, give up.
1368 if(deployed < SER_FMT_VER_LOWEST)
1369 deployed = SER_FMT_VER_INVALID;
1371 if(deployed == SER_FMT_VER_INVALID)
1373 actionstream<<"Server: A mismatched client tried to connect from "
1374 <<addr_s<<std::endl;
1375 infostream<<"Server: Cannot negotiate serialization version with "
1376 <<addr_s<<std::endl;
1377 DenyAccess(peer_id, std::wstring(
1378 L"Your client's version is not supported.\n"
1379 L"Server version is ")
1380 + narrow_to_wide(minetest_version_simple) + L"."
1385 client->setPendingSerializationVersion(deployed);
1388 Read and check network protocol version
1391 u16 min_net_proto_version = 0;
1392 if(datasize >= 2+1+PLAYERNAME_SIZE+PASSWORD_SIZE+2)
1393 min_net_proto_version = readU16(&data[2+1+PLAYERNAME_SIZE+PASSWORD_SIZE]);
1395 // Use same version as minimum and maximum if maximum version field
1396 // doesn't exist (backwards compatibility)
1397 u16 max_net_proto_version = min_net_proto_version;
1398 if(datasize >= 2+1+PLAYERNAME_SIZE+PASSWORD_SIZE+2+2)
1399 max_net_proto_version = readU16(&data[2+1+PLAYERNAME_SIZE+PASSWORD_SIZE+2]);
1401 // Start with client's maximum version
1402 u16 net_proto_version = max_net_proto_version;
1404 // Figure out a working version if it is possible at all
1405 if(max_net_proto_version >= SERVER_PROTOCOL_VERSION_MIN ||
1406 min_net_proto_version <= SERVER_PROTOCOL_VERSION_MAX)
1408 // If maximum is larger than our maximum, go with our maximum
1409 if(max_net_proto_version > SERVER_PROTOCOL_VERSION_MAX)
1410 net_proto_version = SERVER_PROTOCOL_VERSION_MAX;
1411 // Else go with client's maximum
1413 net_proto_version = max_net_proto_version;
1416 verbosestream<<"Server: "<<addr_s<<": Protocol version: min: "
1417 <<min_net_proto_version<<", max: "<<max_net_proto_version
1418 <<", chosen: "<<net_proto_version<<std::endl;
1420 client->net_proto_version = net_proto_version;
1422 if(net_proto_version < SERVER_PROTOCOL_VERSION_MIN ||
1423 net_proto_version > SERVER_PROTOCOL_VERSION_MAX)
1425 actionstream<<"Server: A mismatched client tried to connect from "
1426 <<addr_s<<std::endl;
1427 DenyAccess(peer_id, std::wstring(
1428 L"Your client's version is not supported.\n"
1429 L"Server version is ")
1430 + narrow_to_wide(minetest_version_simple) + L",\n"
1431 + L"server's PROTOCOL_VERSION is "
1432 + narrow_to_wide(itos(SERVER_PROTOCOL_VERSION_MIN))
1434 + narrow_to_wide(itos(SERVER_PROTOCOL_VERSION_MAX))
1435 + L", client's PROTOCOL_VERSION is "
1436 + narrow_to_wide(itos(min_net_proto_version))
1438 + narrow_to_wide(itos(max_net_proto_version))
1443 if(g_settings->getBool("strict_protocol_version_checking"))
1445 if(net_proto_version != LATEST_PROTOCOL_VERSION)
1447 actionstream<<"Server: A mismatched (strict) client tried to "
1448 <<"connect from "<<addr_s<<std::endl;
1449 DenyAccess(peer_id, std::wstring(
1450 L"Your client's version is not supported.\n"
1451 L"Server version is ")
1452 + narrow_to_wide(minetest_version_simple) + L",\n"
1453 + L"server's PROTOCOL_VERSION (strict) is "
1454 + narrow_to_wide(itos(LATEST_PROTOCOL_VERSION))
1455 + L", client's PROTOCOL_VERSION is "
1456 + narrow_to_wide(itos(min_net_proto_version))
1458 + narrow_to_wide(itos(max_net_proto_version))
1467 char playername[PLAYERNAME_SIZE];
1468 unsigned int playername_length = 0;
1469 for (; playername_length < PLAYERNAME_SIZE; playername_length++ ) {
1470 playername[playername_length] = data[3+playername_length];
1471 if (data[3+playername_length] == 0)
1475 if (playername_length == PLAYERNAME_SIZE) {
1476 actionstream<<"Server: Player with name exceeding max length "
1477 <<"tried to connect from "<<addr_s<<std::endl;
1478 DenyAccess(peer_id, L"Name too long");
1483 if(playername[0]=='\0')
1485 actionstream<<"Server: Player with an empty name "
1486 <<"tried to connect from "<<addr_s<<std::endl;
1487 DenyAccess(peer_id, L"Empty name");
1491 if(string_allowed(playername, PLAYERNAME_ALLOWED_CHARS)==false)
1493 actionstream<<"Server: Player with an invalid name "
1494 <<"tried to connect from "<<addr_s<<std::endl;
1495 DenyAccess(peer_id, L"Name contains unallowed characters");
1499 if(!isSingleplayer() && strcasecmp(playername, "singleplayer") == 0)
1501 actionstream<<"Server: Player with the name \"singleplayer\" "
1502 <<"tried to connect from "<<addr_s<<std::endl;
1503 DenyAccess(peer_id, L"Name is not allowed");
1509 if(m_script->on_prejoinplayer(playername, addr_s, reason))
1511 actionstream<<"Server: Player with the name \""<<playername<<"\" "
1512 <<"tried to connect from "<<addr_s<<" "
1513 <<"but it was disallowed for the following reason: "
1514 <<reason<<std::endl;
1515 DenyAccess(peer_id, narrow_to_wide(reason.c_str()));
1520 infostream<<"Server: New connection: \""<<playername<<"\" from "
1521 <<addr_s<<" (peer_id="<<peer_id<<")"<<std::endl;
1524 char given_password[PASSWORD_SIZE];
1525 if(datasize < 2+1+PLAYERNAME_SIZE+PASSWORD_SIZE)
1527 // old version - assume blank password
1528 given_password[0] = 0;
1532 for(u32 i=0; i<PASSWORD_SIZE-1; i++)
1534 given_password[i] = data[23+i];
1536 given_password[PASSWORD_SIZE-1] = 0;
1539 if(!base64_is_valid(given_password)){
1540 actionstream<<"Server: "<<playername
1541 <<" supplied invalid password hash"<<std::endl;
1542 DenyAccess(peer_id, L"Invalid password hash");
1546 // Enforce user limit.
1547 // Don't enforce for users that have some admin right
1548 if(m_clients.getClientIDs(CS_Created).size() >= g_settings->getU16("max_users") &&
1549 !checkPriv(playername, "server") &&
1550 !checkPriv(playername, "ban") &&
1551 !checkPriv(playername, "privs") &&
1552 !checkPriv(playername, "password") &&
1553 playername != g_settings->get("name"))
1555 actionstream<<"Server: "<<playername<<" tried to join, but there"
1556 <<" are already max_users="
1557 <<g_settings->getU16("max_users")<<" players."<<std::endl;
1558 DenyAccess(peer_id, L"Too many users.");
1562 std::string checkpwd; // Password hash to check against
1563 bool has_auth = m_script->getAuth(playername, &checkpwd, NULL);
1565 // If no authentication info exists for user, create it
1567 if(!isSingleplayer() &&
1568 g_settings->getBool("disallow_empty_password") &&
1569 std::string(given_password) == ""){
1570 actionstream<<"Server: "<<playername
1571 <<" supplied empty password"<<std::endl;
1572 DenyAccess(peer_id, L"Empty passwords are "
1573 L"disallowed. Set a password and try again.");
1576 std::wstring raw_default_password =
1577 narrow_to_wide(g_settings->get("default_password"));
1578 std::string initial_password =
1579 translatePassword(playername, raw_default_password);
1581 // If default_password is empty, allow any initial password
1582 if (raw_default_password.length() == 0)
1583 initial_password = given_password;
1585 m_script->createAuth(playername, initial_password);
1588 has_auth = m_script->getAuth(playername, &checkpwd, NULL);
1591 actionstream<<"Server: "<<playername<<" cannot be authenticated"
1592 <<" (auth handler does not work?)"<<std::endl;
1593 DenyAccess(peer_id, L"Not allowed to login");
1597 if(given_password != checkpwd){
1598 actionstream<<"Server: "<<playername<<" supplied wrong password"
1600 DenyAccess(peer_id, L"Wrong password");
1604 RemotePlayer *player =
1605 static_cast<RemotePlayer*>(m_env->getPlayer(playername));
1607 if(player && player->peer_id != 0){
1608 errorstream<<"Server: "<<playername<<": Failed to emerge player"
1609 <<" (player allocated to an another client)"<<std::endl;
1610 DenyAccess(peer_id, L"Another client is connected with this "
1611 L"name. If your client closed unexpectedly, try again in "
1615 m_clients.setPlayerName(peer_id,playername);
1618 Answer with a TOCLIENT_INIT
1621 SharedBuffer<u8> reply(2+1+6+8+4);
1622 writeU16(&reply[0], TOCLIENT_INIT);
1623 writeU8(&reply[2], deployed);
1624 //send dummy pos for legacy reasons only
1625 writeV3S16(&reply[2+1], floatToInt(v3f(0,0,0), BS));
1626 writeU64(&reply[2+1+6], m_env->getServerMap().getSeed());
1627 writeF1000(&reply[2+1+6+8], g_settings->getFloat("dedicated_server_step"));
1630 m_clients.send(peer_id, 0, reply, true);
1631 m_clients.event(peer_id, CSE_Init);
1637 if(command == TOSERVER_INIT2)
1640 verbosestream<<"Server: Got TOSERVER_INIT2 from "
1641 <<peer_id<<std::endl;
1643 m_clients.event(peer_id, CSE_GotInit2);
1644 u16 protocol_version = m_clients.getProtocolVersion(peer_id);
1647 ///// begin compatibility code
1648 PlayerSAO* playersao = NULL;
1649 if (protocol_version <= 22) {
1650 playersao = StageTwoClientInit(peer_id);
1652 if (playersao == NULL) {
1654 << "TOSERVER_INIT2 stage 2 client init failed for peer "
1655 << peer_id << std::endl;
1659 ///// end compatibility code
1662 Send some initialization data
1665 infostream<<"Server: Sending content to "
1666 <<getPlayerName(peer_id)<<std::endl;
1668 // Send player movement settings
1669 SendMovement(peer_id);
1671 // Send item definitions
1672 SendItemDef(peer_id, m_itemdef, protocol_version);
1674 // Send node definitions
1675 SendNodeDef(peer_id, m_nodedef, protocol_version);
1677 m_clients.event(peer_id, CSE_SetDefinitionsSent);
1679 // Send media announcement
1680 sendMediaAnnouncement(peer_id);
1682 // Send detached inventories
1683 sendDetachedInventories(peer_id);
1686 u16 time = m_env->getTimeOfDay();
1687 float time_speed = g_settings->getFloat("time_speed");
1688 SendTimeOfDay(peer_id, time, time_speed);
1690 ///// begin compatibility code
1691 if (protocol_version <= 22) {
1692 m_clients.event(peer_id, CSE_SetClientReady);
1693 m_script->on_joinplayer(playersao);
1695 ///// end compatibility code
1697 // Warnings about protocol version can be issued here
1698 if(getClient(peer_id)->net_proto_version < LATEST_PROTOCOL_VERSION)
1700 SendChatMessage(peer_id, L"# Server: WARNING: YOUR CLIENT'S "
1701 L"VERSION MAY NOT BE FULLY COMPATIBLE WITH THIS SERVER!");
1707 u8 peer_ser_ver = getClient(peer_id, CS_InitDone)->serialization_version;
1708 u16 peer_proto_ver = getClient(peer_id, CS_InitDone)->net_proto_version;
1710 if(peer_ser_ver == SER_FMT_VER_INVALID)
1712 errorstream<<"Server::ProcessData(): Cancelling: Peer"
1713 " serialization format invalid or not initialized."
1714 " Skipping incoming command="<<command<<std::endl;
1718 /* Handle commands relate to client startup */
1719 if(command == TOSERVER_REQUEST_MEDIA) {
1720 std::string datastring((char*)&data[2], datasize-2);
1721 std::istringstream is(datastring, std::ios_base::binary);
1723 std::list<std::string> tosend;
1724 u16 numfiles = readU16(is);
1726 infostream<<"Sending "<<numfiles<<" files to "
1727 <<getPlayerName(peer_id)<<std::endl;
1728 verbosestream<<"TOSERVER_REQUEST_MEDIA: "<<std::endl;
1730 for(int i = 0; i < numfiles; i++) {
1731 std::string name = deSerializeString(is);
1732 tosend.push_back(name);
1733 verbosestream<<"TOSERVER_REQUEST_MEDIA: requested file "
1737 sendRequestedMedia(peer_id, tosend);
1740 else if(command == TOSERVER_RECEIVED_MEDIA) {
1743 else if(command == TOSERVER_CLIENT_READY) {
1744 // clients <= protocol version 22 did not send ready message,
1745 // they're already initialized
1746 if (peer_proto_ver <= 22) {
1747 infostream << "Client sent message not expected by a "
1748 << "client using protocol version <= 22,"
1749 << "disconnecing peer_id: " << peer_id << std::endl;
1750 m_con.DisconnectPeer(peer_id);
1754 PlayerSAO* playersao = StageTwoClientInit(peer_id);
1756 if (playersao == NULL) {
1758 << "TOSERVER_CLIENT_READY stage 2 client init failed for peer_id: "
1759 << peer_id << std::endl;
1760 m_con.DisconnectPeer(peer_id);
1765 if(datasize < 2+8) {
1767 << "TOSERVER_CLIENT_READY client sent inconsistent data, disconnecting peer_id: "
1768 << peer_id << std::endl;
1769 m_con.DisconnectPeer(peer_id);
1773 m_clients.setClientVersion(
1775 data[2], data[3], data[4],
1776 std::string((char*) &data[8],(u16) data[6]));
1778 m_clients.event(peer_id, CSE_SetClientReady);
1779 m_script->on_joinplayer(playersao);
1782 else if(command == TOSERVER_GOTBLOCKS)
1795 u16 count = data[2];
1796 for(u16 i=0; i<count; i++)
1798 if((s16)datasize < 2+1+(i+1)*6)
1799 throw con::InvalidIncomingDataException
1800 ("GOTBLOCKS length is too short");
1801 v3s16 p = readV3S16(&data[2+1+i*6]);
1802 /*infostream<<"Server: GOTBLOCKS ("
1803 <<p.X<<","<<p.Y<<","<<p.Z<<")"<<std::endl;*/
1804 RemoteClient *client = getClient(peer_id);
1805 client->GotBlock(p);
1810 if (m_clients.getClientState(peer_id) < CS_Active)
1812 if (command == TOSERVER_PLAYERPOS) return;
1814 errorstream<<"Got packet command: " << command << " for peer id "
1815 << peer_id << " but client isn't active yet. Dropping packet "
1820 Player *player = m_env->getPlayer(peer_id);
1821 if(player == NULL) {
1822 errorstream<<"Server::ProcessData(): Cancelling: "
1823 "No player for peer_id="<<peer_id
1824 << " disconnecting peer!" <<std::endl;
1825 m_con.DisconnectPeer(peer_id);
1829 PlayerSAO *playersao = player->getPlayerSAO();
1830 if(playersao == NULL) {
1831 errorstream<<"Server::ProcessData(): Cancelling: "
1832 "No player object for peer_id="<<peer_id
1833 << " disconnecting peer!" <<std::endl;
1834 m_con.DisconnectPeer(peer_id);
1838 if(command == TOSERVER_PLAYERPOS)
1840 if(datasize < 2+12+12+4+4)
1844 v3s32 ps = readV3S32(&data[start+2]);
1845 v3s32 ss = readV3S32(&data[start+2+12]);
1846 f32 pitch = (f32)readS32(&data[2+12+12]) / 100.0;
1847 f32 yaw = (f32)readS32(&data[2+12+12+4]) / 100.0;
1849 if(datasize >= 2+12+12+4+4+4)
1850 keyPressed = (u32)readU32(&data[2+12+12+4+4]);
1851 v3f position((f32)ps.X/100., (f32)ps.Y/100., (f32)ps.Z/100.);
1852 v3f speed((f32)ss.X/100., (f32)ss.Y/100., (f32)ss.Z/100.);
1853 pitch = wrapDegrees(pitch);
1854 yaw = wrapDegrees(yaw);
1856 player->setPosition(position);
1857 player->setSpeed(speed);
1858 player->setPitch(pitch);
1859 player->setYaw(yaw);
1860 player->keyPressed=keyPressed;
1861 player->control.up = (bool)(keyPressed&1);
1862 player->control.down = (bool)(keyPressed&2);
1863 player->control.left = (bool)(keyPressed&4);
1864 player->control.right = (bool)(keyPressed&8);
1865 player->control.jump = (bool)(keyPressed&16);
1866 player->control.aux1 = (bool)(keyPressed&32);
1867 player->control.sneak = (bool)(keyPressed&64);
1868 player->control.LMB = (bool)(keyPressed&128);
1869 player->control.RMB = (bool)(keyPressed&256);
1871 bool cheated = playersao->checkMovementCheat();
1874 m_script->on_cheat(playersao, "moved_too_fast");
1877 /*infostream<<"Server::ProcessData(): Moved player "<<peer_id<<" to "
1878 <<"("<<position.X<<","<<position.Y<<","<<position.Z<<")"
1879 <<" pitch="<<pitch<<" yaw="<<yaw<<std::endl;*/
1881 else if(command == TOSERVER_DELETEDBLOCKS)
1894 u16 count = data[2];
1895 for(u16 i=0; i<count; i++)
1897 if((s16)datasize < 2+1+(i+1)*6)
1898 throw con::InvalidIncomingDataException
1899 ("DELETEDBLOCKS length is too short");
1900 v3s16 p = readV3S16(&data[2+1+i*6]);
1901 /*infostream<<"Server: DELETEDBLOCKS ("
1902 <<p.X<<","<<p.Y<<","<<p.Z<<")"<<std::endl;*/
1903 RemoteClient *client = getClient(peer_id);
1904 client->SetBlockNotSent(p);
1907 else if(command == TOSERVER_CLICK_OBJECT)
1909 infostream<<"Server: CLICK_OBJECT not supported anymore"<<std::endl;
1912 else if(command == TOSERVER_CLICK_ACTIVEOBJECT)
1914 infostream<<"Server: CLICK_ACTIVEOBJECT not supported anymore"<<std::endl;
1917 else if(command == TOSERVER_GROUND_ACTION)
1919 infostream<<"Server: GROUND_ACTION not supported anymore"<<std::endl;
1923 else if(command == TOSERVER_RELEASE)
1925 infostream<<"Server: RELEASE not supported anymore"<<std::endl;
1928 else if(command == TOSERVER_SIGNTEXT)
1930 infostream<<"Server: SIGNTEXT not supported anymore"
1934 else if(command == TOSERVER_SIGNNODETEXT)
1936 infostream<<"Server: SIGNNODETEXT not supported anymore"
1940 else if(command == TOSERVER_INVENTORY_ACTION)
1942 // Strip command and create a stream
1943 std::string datastring((char*)&data[2], datasize-2);
1944 verbosestream<<"TOSERVER_INVENTORY_ACTION: data="<<datastring<<std::endl;
1945 std::istringstream is(datastring, std::ios_base::binary);
1947 InventoryAction *a = InventoryAction::deSerialize(is);
1950 infostream<<"TOSERVER_INVENTORY_ACTION: "
1951 <<"InventoryAction::deSerialize() returned NULL"
1956 // If something goes wrong, this player is to blame
1957 RollbackScopeActor rollback_scope(m_rollback,
1958 std::string("player:")+player->getName());
1961 Note: Always set inventory not sent, to repair cases
1962 where the client made a bad prediction.
1966 Handle restrictions and special cases of the move action
1968 if(a->getType() == IACTION_MOVE)
1970 IMoveAction *ma = (IMoveAction*)a;
1972 ma->from_inv.applyCurrentPlayer(player->getName());
1973 ma->to_inv.applyCurrentPlayer(player->getName());
1975 setInventoryModified(ma->from_inv);
1976 setInventoryModified(ma->to_inv);
1978 bool from_inv_is_current_player =
1979 (ma->from_inv.type == InventoryLocation::PLAYER) &&
1980 (ma->from_inv.name == player->getName());
1982 bool to_inv_is_current_player =
1983 (ma->to_inv.type == InventoryLocation::PLAYER) &&
1984 (ma->to_inv.name == player->getName());
1987 Disable moving items out of craftpreview
1989 if(ma->from_list == "craftpreview")
1991 infostream<<"Ignoring IMoveAction from "
1992 <<(ma->from_inv.dump())<<":"<<ma->from_list
1993 <<" to "<<(ma->to_inv.dump())<<":"<<ma->to_list
1994 <<" because src is "<<ma->from_list<<std::endl;
2000 Disable moving items into craftresult and craftpreview
2002 if(ma->to_list == "craftpreview" || ma->to_list == "craftresult")
2004 infostream<<"Ignoring IMoveAction from "
2005 <<(ma->from_inv.dump())<<":"<<ma->from_list
2006 <<" to "<<(ma->to_inv.dump())<<":"<<ma->to_list
2007 <<" because dst is "<<ma->to_list<<std::endl;
2012 // Disallow moving items in elsewhere than player's inventory
2013 // if not allowed to interact
2014 if(!checkPriv(player->getName(), "interact") &&
2015 (!from_inv_is_current_player ||
2016 !to_inv_is_current_player))
2018 infostream<<"Cannot move outside of player's inventory: "
2019 <<"No interact privilege"<<std::endl;
2025 Handle restrictions and special cases of the drop action
2027 else if(a->getType() == IACTION_DROP)
2029 IDropAction *da = (IDropAction*)a;
2031 da->from_inv.applyCurrentPlayer(player->getName());
2033 setInventoryModified(da->from_inv);
2036 Disable dropping items out of craftpreview
2038 if(da->from_list == "craftpreview")
2040 infostream<<"Ignoring IDropAction from "
2041 <<(da->from_inv.dump())<<":"<<da->from_list
2042 <<" because src is "<<da->from_list<<std::endl;
2047 // Disallow dropping items if not allowed to interact
2048 if(!checkPriv(player->getName(), "interact"))
2055 Handle restrictions and special cases of the craft action
2057 else if(a->getType() == IACTION_CRAFT)
2059 ICraftAction *ca = (ICraftAction*)a;
2061 ca->craft_inv.applyCurrentPlayer(player->getName());
2063 setInventoryModified(ca->craft_inv);
2065 //bool craft_inv_is_current_player =
2066 // (ca->craft_inv.type == InventoryLocation::PLAYER) &&
2067 // (ca->craft_inv.name == player->getName());
2069 // Disallow crafting if not allowed to interact
2070 if(!checkPriv(player->getName(), "interact"))
2072 infostream<<"Cannot craft: "
2073 <<"No interact privilege"<<std::endl;
2080 a->apply(this, playersao, this);
2084 else if(command == TOSERVER_CHAT_MESSAGE)
2092 std::string datastring((char*)&data[2], datasize-2);
2093 std::istringstream is(datastring, std::ios_base::binary);
2096 is.read((char*)buf, 2);
2097 u16 len = readU16(buf);
2099 std::wstring message;
2100 for(u16 i=0; i<len; i++)
2102 is.read((char*)buf, 2);
2103 message += (wchar_t)readU16(buf);
2106 // If something goes wrong, this player is to blame
2107 RollbackScopeActor rollback_scope(m_rollback,
2108 std::string("player:")+player->getName());
2110 // Get player name of this client
2111 std::wstring name = narrow_to_wide(player->getName());
2114 bool ate = m_script->on_chat_message(player->getName(),
2115 wide_to_narrow(message));
2116 // If script ate the message, don't proceed
2120 // Line to send to players
2122 // Whether to send to the player that sent the line
2123 bool send_to_sender_only = false;
2125 // Commands are implemented in Lua, so only catch invalid
2126 // commands that were not "eaten" and send an error back
2127 if(message[0] == L'/')
2129 message = message.substr(1);
2130 send_to_sender_only = true;
2131 if(message.length() == 0)
2132 line += L"-!- Empty command";
2134 line += L"-!- Invalid command: " + str_split(message, L' ')[0];
2138 if(checkPriv(player->getName(), "shout")){
2144 line += L"-!- You don't have permission to shout.";
2145 send_to_sender_only = true;
2152 Send the message to sender
2154 if (send_to_sender_only)
2156 SendChatMessage(peer_id, line);
2159 Send the message to others
2163 actionstream<<"CHAT: "<<wide_to_narrow(line)<<std::endl;
2165 std::list<u16> clients = m_clients.getClientIDs();
2167 for(std::list<u16>::iterator
2168 i = clients.begin();
2169 i != clients.end(); ++i)
2172 SendChatMessage(*i, line);
2177 else if(command == TOSERVER_DAMAGE)
2179 std::string datastring((char*)&data[2], datasize-2);
2180 std::istringstream is(datastring, std::ios_base::binary);
2181 u8 damage = readU8(is);
2183 if(g_settings->getBool("enable_damage"))
2185 actionstream<<player->getName()<<" damaged by "
2186 <<(int)damage<<" hp at "<<PP(player->getPosition()/BS)
2189 playersao->setHP(playersao->getHP() - damage);
2191 if(playersao->getHP() == 0 && playersao->m_hp_not_sent)
2194 if(playersao->m_hp_not_sent)
2195 SendPlayerHP(peer_id);
2198 else if(command == TOSERVER_BREATH)
2200 std::string datastring((char*)&data[2], datasize-2);
2201 std::istringstream is(datastring, std::ios_base::binary);
2202 u16 breath = readU16(is);
2203 playersao->setBreath(breath);
2204 m_script->player_event(playersao,"breath_changed");
2206 else if(command == TOSERVER_PASSWORD)
2209 [0] u16 TOSERVER_PASSWORD
2210 [2] u8[28] old password
2211 [30] u8[28] new password
2214 if(datasize != 2+PASSWORD_SIZE*2)
2216 /*char password[PASSWORD_SIZE];
2217 for(u32 i=0; i<PASSWORD_SIZE-1; i++)
2218 password[i] = data[2+i];
2219 password[PASSWORD_SIZE-1] = 0;*/
2221 for(u32 i=0; i<PASSWORD_SIZE-1; i++)
2229 for(u32 i=0; i<PASSWORD_SIZE-1; i++)
2231 char c = data[2+PASSWORD_SIZE+i];
2237 if(!base64_is_valid(newpwd)){
2238 infostream<<"Server: "<<player->getName()<<" supplied invalid password hash"<<std::endl;
2239 // Wrong old password supplied!!
2240 SendChatMessage(peer_id, L"Invalid new password hash supplied. Password NOT changed.");
2244 infostream<<"Server: Client requests a password change from "
2245 <<"'"<<oldpwd<<"' to '"<<newpwd<<"'"<<std::endl;
2247 std::string playername = player->getName();
2249 std::string checkpwd;
2250 m_script->getAuth(playername, &checkpwd, NULL);
2252 if(oldpwd != checkpwd)
2254 infostream<<"Server: invalid old password"<<std::endl;
2255 // Wrong old password supplied!!
2256 SendChatMessage(peer_id, L"Invalid old password supplied. Password NOT changed.");
2260 bool success = m_script->setPassword(playername, newpwd);
2262 actionstream<<player->getName()<<" changes password"<<std::endl;
2263 SendChatMessage(peer_id, L"Password change successful.");
2265 actionstream<<player->getName()<<" tries to change password but "
2266 <<"it fails"<<std::endl;
2267 SendChatMessage(peer_id, L"Password change failed or inavailable.");
2270 else if(command == TOSERVER_PLAYERITEM)
2275 u16 item = readU16(&data[2]);
2276 playersao->setWieldIndex(item);
2278 else if(command == TOSERVER_RESPAWN)
2280 if(player->hp != 0 || !g_settings->getBool("enable_damage"))
2283 RespawnPlayer(peer_id);
2285 actionstream<<player->getName()<<" respawns at "
2286 <<PP(player->getPosition()/BS)<<std::endl;
2288 // ActiveObject is added to environment in AsyncRunStep after
2289 // the previous addition has been succesfully removed
2291 else if(command == TOSERVER_INTERACT)
2293 std::string datastring((char*)&data[2], datasize-2);
2294 std::istringstream is(datastring, std::ios_base::binary);
2300 [5] u32 length of the next item
2301 [9] serialized PointedThing
2303 0: start digging (from undersurface) or use
2304 1: stop digging (all parameters ignored)
2305 2: digging completed
2306 3: place block or item (to abovesurface)
2309 u8 action = readU8(is);
2310 u16 item_i = readU16(is);
2311 std::istringstream tmp_is(deSerializeLongString(is), std::ios::binary);
2312 PointedThing pointed;
2313 pointed.deSerialize(tmp_is);
2315 verbosestream<<"TOSERVER_INTERACT: action="<<(int)action<<", item="
2316 <<item_i<<", pointed="<<pointed.dump()<<std::endl;
2320 verbosestream<<"TOSERVER_INTERACT: "<<player->getName()
2321 <<" tried to interact, but is dead!"<<std::endl;
2325 v3f player_pos = playersao->getLastGoodPosition();
2327 // Update wielded item
2328 playersao->setWieldIndex(item_i);
2330 // Get pointed to node (undefined if not POINTEDTYPE_NODE)
2331 v3s16 p_under = pointed.node_undersurface;
2332 v3s16 p_above = pointed.node_abovesurface;
2334 // Get pointed to object (NULL if not POINTEDTYPE_OBJECT)
2335 ServerActiveObject *pointed_object = NULL;
2336 if(pointed.type == POINTEDTHING_OBJECT)
2338 pointed_object = m_env->getActiveObject(pointed.object_id);
2339 if(pointed_object == NULL)
2341 verbosestream<<"TOSERVER_INTERACT: "
2342 "pointed object is NULL"<<std::endl;
2348 v3f pointed_pos_under = player_pos;
2349 v3f pointed_pos_above = player_pos;
2350 if(pointed.type == POINTEDTHING_NODE)
2352 pointed_pos_under = intToFloat(p_under, BS);
2353 pointed_pos_above = intToFloat(p_above, BS);
2355 else if(pointed.type == POINTEDTHING_OBJECT)
2357 pointed_pos_under = pointed_object->getBasePosition();
2358 pointed_pos_above = pointed_pos_under;
2362 Check that target is reasonably close
2363 (only when digging or placing things)
2365 if(action == 0 || action == 2 || action == 3)
2367 float d = player_pos.getDistanceFrom(pointed_pos_under);
2368 float max_d = BS * 14; // Just some large enough value
2370 actionstream<<"Player "<<player->getName()
2371 <<" tried to access "<<pointed.dump()
2373 <<"d="<<d<<", max_d="<<max_d
2374 <<". ignoring."<<std::endl;
2375 // Re-send block to revert change on client-side
2376 RemoteClient *client = getClient(peer_id);
2377 v3s16 blockpos = getNodeBlockPos(floatToInt(pointed_pos_under, BS));
2378 client->SetBlockNotSent(blockpos);
2380 m_script->on_cheat(playersao, "interacted_too_far");
2387 Make sure the player is allowed to do it
2389 if(!checkPriv(player->getName(), "interact"))
2391 actionstream<<player->getName()<<" attempted to interact with "
2392 <<pointed.dump()<<" without 'interact' privilege"
2394 // Re-send block to revert change on client-side
2395 RemoteClient *client = getClient(peer_id);
2396 // Digging completed -> under
2398 v3s16 blockpos = getNodeBlockPos(floatToInt(pointed_pos_under, BS));
2399 client->SetBlockNotSent(blockpos);
2401 // Placement -> above
2403 v3s16 blockpos = getNodeBlockPos(floatToInt(pointed_pos_above, BS));
2404 client->SetBlockNotSent(blockpos);
2410 If something goes wrong, this player is to blame
2412 RollbackScopeActor rollback_scope(m_rollback,
2413 std::string("player:")+player->getName());
2416 0: start digging or punch object
2420 if(pointed.type == POINTEDTHING_NODE)
2423 NOTE: This can be used in the future to check if
2424 somebody is cheating, by checking the timing.
2426 MapNode n(CONTENT_IGNORE);
2429 n = m_env->getMap().getNode(p_under);
2431 catch(InvalidPositionException &e)
2433 infostream<<"Server: Not punching: Node not found."
2434 <<" Adding block to emerge queue."
2436 m_emerge->enqueueBlockEmerge(peer_id, getNodeBlockPos(p_above), false);
2438 if(n.getContent() != CONTENT_IGNORE)
2439 m_script->node_on_punch(p_under, n, playersao, pointed);
2441 playersao->noCheatDigStart(p_under);
2443 else if(pointed.type == POINTEDTHING_OBJECT)
2445 // Skip if object has been removed
2446 if(pointed_object->m_removed)
2449 actionstream<<player->getName()<<" punches object "
2450 <<pointed.object_id<<": "
2451 <<pointed_object->getDescription()<<std::endl;
2453 ItemStack punchitem = playersao->getWieldedItem();
2454 ToolCapabilities toolcap =
2455 punchitem.getToolCapabilities(m_itemdef);
2456 v3f dir = (pointed_object->getBasePosition() -
2457 (player->getPosition() + player->getEyeOffset())
2459 float time_from_last_punch =
2460 playersao->resetTimeFromLastPunch();
2461 pointed_object->punch(dir, &toolcap, playersao,
2462 time_from_last_punch);
2470 else if(action == 1)
2475 2: Digging completed
2477 else if(action == 2)
2479 // Only digging of nodes
2480 if(pointed.type == POINTEDTHING_NODE)
2482 MapNode n(CONTENT_IGNORE);
2485 n = m_env->getMap().getNode(p_under);
2487 catch(InvalidPositionException &e)
2489 infostream<<"Server: Not finishing digging: Node not found."
2490 <<" Adding block to emerge queue."
2492 m_emerge->enqueueBlockEmerge(peer_id, getNodeBlockPos(p_above), false);
2495 /* Cheat prevention */
2496 bool is_valid_dig = true;
2497 if(!isSingleplayer() && !g_settings->getBool("disable_anticheat"))
2499 v3s16 nocheat_p = playersao->getNoCheatDigPos();
2500 float nocheat_t = playersao->getNoCheatDigTime();
2501 playersao->noCheatDigEnd();
2502 // If player didn't start digging this, ignore dig
2503 if(nocheat_p != p_under){
2504 infostream<<"Server: NoCheat: "<<player->getName()
2505 <<" started digging "
2506 <<PP(nocheat_p)<<" and completed digging "
2507 <<PP(p_under)<<"; not digging."<<std::endl;
2508 is_valid_dig = false;
2510 m_script->on_cheat(playersao, "finished_unknown_dig");
2512 // Get player's wielded item
2513 ItemStack playeritem;
2514 InventoryList *mlist = playersao->getInventory()->getList("main");
2516 playeritem = mlist->getItem(playersao->getWieldIndex());
2517 ToolCapabilities playeritem_toolcap =
2518 playeritem.getToolCapabilities(m_itemdef);
2519 // Get diggability and expected digging time
2520 DigParams params = getDigParams(m_nodedef->get(n).groups,
2521 &playeritem_toolcap);
2522 // If can't dig, try hand
2523 if(!params.diggable){
2524 const ItemDefinition &hand = m_itemdef->get("");
2525 const ToolCapabilities *tp = hand.tool_capabilities;
2527 params = getDigParams(m_nodedef->get(n).groups, tp);
2529 // If can't dig, ignore dig
2530 if(!params.diggable){
2531 infostream<<"Server: NoCheat: "<<player->getName()
2532 <<" completed digging "<<PP(p_under)
2533 <<", which is not diggable with tool. not digging."
2535 is_valid_dig = false;
2537 m_script->on_cheat(playersao, "dug_unbreakable");
2539 // Check digging time
2540 // If already invalidated, we don't have to
2542 // Well not our problem then
2544 // Clean and long dig
2545 else if(params.time > 2.0 && nocheat_t * 1.2 > params.time){
2546 // All is good, but grab time from pool; don't care if
2547 // it's actually available
2548 playersao->getDigPool().grab(params.time);
2550 // Short or laggy dig
2551 // Try getting the time from pool
2552 else if(playersao->getDigPool().grab(params.time)){
2557 infostream<<"Server: NoCheat: "<<player->getName()
2558 <<" completed digging "<<PP(p_under)
2559 <<"too fast; not digging."<<std::endl;
2560 is_valid_dig = false;
2562 m_script->on_cheat(playersao, "dug_too_fast");
2566 /* Actually dig node */
2568 if(is_valid_dig && n.getContent() != CONTENT_IGNORE)
2569 m_script->node_on_dig(p_under, n, playersao);
2571 v3s16 blockpos = getNodeBlockPos(floatToInt(pointed_pos_under, BS));
2572 RemoteClient *client = getClient(peer_id);
2573 // Send unusual result (that is, node not being removed)
2574 if(m_env->getMap().getNodeNoEx(p_under).getContent() != CONTENT_AIR)
2576 // Re-send block to revert change on client-side
2577 client->SetBlockNotSent(blockpos);
2580 client->ResendBlockIfOnWire(blockpos);
2586 3: place block or right-click object
2588 else if(action == 3)
2590 ItemStack item = playersao->getWieldedItem();
2592 // Reset build time counter
2593 if(pointed.type == POINTEDTHING_NODE &&
2594 item.getDefinition(m_itemdef).type == ITEM_NODE)
2595 getClient(peer_id)->m_time_from_building = 0.0;
2597 if(pointed.type == POINTEDTHING_OBJECT)
2599 // Right click object
2601 // Skip if object has been removed
2602 if(pointed_object->m_removed)
2605 actionstream<<player->getName()<<" right-clicks object "
2606 <<pointed.object_id<<": "
2607 <<pointed_object->getDescription()<<std::endl;
2610 pointed_object->rightClick(playersao);
2612 else if(m_script->item_OnPlace(
2613 item, playersao, pointed))
2615 // Placement was handled in lua
2617 // Apply returned ItemStack
2618 playersao->setWieldedItem(item);
2621 // If item has node placement prediction, always send the
2622 // blocks to make sure the client knows what exactly happened
2623 RemoteClient *client = getClient(peer_id);
2624 v3s16 blockpos = getNodeBlockPos(floatToInt(pointed_pos_above, BS));
2625 v3s16 blockpos2 = getNodeBlockPos(floatToInt(pointed_pos_under, BS));
2626 if(item.getDefinition(m_itemdef).node_placement_prediction != "") {
2627 client->SetBlockNotSent(blockpos);
2628 if(blockpos2 != blockpos) {
2629 client->SetBlockNotSent(blockpos2);
2633 client->ResendBlockIfOnWire(blockpos);
2634 if(blockpos2 != blockpos) {
2635 client->ResendBlockIfOnWire(blockpos2);
2643 else if(action == 4)
2645 ItemStack item = playersao->getWieldedItem();
2647 actionstream<<player->getName()<<" uses "<<item.name
2648 <<", pointing at "<<pointed.dump()<<std::endl;
2650 if(m_script->item_OnUse(
2651 item, playersao, pointed))
2653 // Apply returned ItemStack
2654 playersao->setWieldedItem(item);
2661 Catch invalid actions
2665 infostream<<"WARNING: Server: Invalid action "
2666 <<action<<std::endl;
2669 else if(command == TOSERVER_REMOVED_SOUNDS)
2671 std::string datastring((char*)&data[2], datasize-2);
2672 std::istringstream is(datastring, std::ios_base::binary);
2674 int num = readU16(is);
2675 for(int k=0; k<num; k++){
2676 s32 id = readS32(is);
2677 std::map<s32, ServerPlayingSound>::iterator i =
2678 m_playing_sounds.find(id);
2679 if(i == m_playing_sounds.end())
2681 ServerPlayingSound &psound = i->second;
2682 psound.clients.erase(peer_id);
2683 if(psound.clients.size() == 0)
2684 m_playing_sounds.erase(i++);
2687 else if(command == TOSERVER_NODEMETA_FIELDS)
2689 std::string datastring((char*)&data[2], datasize-2);
2690 std::istringstream is(datastring, std::ios_base::binary);
2692 v3s16 p = readV3S16(is);
2693 std::string formname = deSerializeString(is);
2694 int num = readU16(is);
2695 std::map<std::string, std::string> fields;
2696 for(int k=0; k<num; k++){
2697 std::string fieldname = deSerializeString(is);
2698 std::string fieldvalue = deSerializeLongString(is);
2699 fields[fieldname] = fieldvalue;
2702 // If something goes wrong, this player is to blame
2703 RollbackScopeActor rollback_scope(m_rollback,
2704 std::string("player:")+player->getName());
2706 // Check the target node for rollback data; leave others unnoticed
2707 RollbackNode rn_old(&m_env->getMap(), p, this);
2709 m_script->node_on_receive_fields(p, formname, fields,playersao);
2711 // Report rollback data
2712 RollbackNode rn_new(&m_env->getMap(), p, this);
2713 if(rollback() && rn_new != rn_old){
2714 RollbackAction action;
2715 action.setSetNode(p, rn_old, rn_new);
2716 rollback()->reportAction(action);
2719 else if(command == TOSERVER_INVENTORY_FIELDS)
2721 std::string datastring((char*)&data[2], datasize-2);
2722 std::istringstream is(datastring, std::ios_base::binary);
2724 std::string formname = deSerializeString(is);
2725 int num = readU16(is);
2726 std::map<std::string, std::string> fields;
2727 for(int k=0; k<num; k++){
2728 std::string fieldname = deSerializeString(is);
2729 std::string fieldvalue = deSerializeLongString(is);
2730 fields[fieldname] = fieldvalue;
2733 m_script->on_playerReceiveFields(playersao, formname, fields);
2737 infostream<<"Server::ProcessData(): Ignoring "
2738 "unknown command "<<command<<std::endl;
2742 catch(SendFailedException &e)
2744 errorstream<<"Server::ProcessData(): SendFailedException: "
2750 void Server::setTimeOfDay(u32 time)
2752 m_env->setTimeOfDay(time);
2753 m_time_of_day_send_timer = 0;
2756 void Server::onMapEditEvent(MapEditEvent *event)
2758 //infostream<<"Server::onMapEditEvent()"<<std::endl;
2759 if(m_ignore_map_edit_events)
2761 if(m_ignore_map_edit_events_area.contains(event->getArea()))
2763 MapEditEvent *e = event->clone();
2764 m_unsent_map_edit_queue.push_back(e);
2767 Inventory* Server::getInventory(const InventoryLocation &loc)
2770 case InventoryLocation::UNDEFINED:
2773 case InventoryLocation::CURRENT_PLAYER:
2776 case InventoryLocation::PLAYER:
2778 Player *player = m_env->getPlayer(loc.name.c_str());
2781 PlayerSAO *playersao = player->getPlayerSAO();
2784 return playersao->getInventory();
2787 case InventoryLocation::NODEMETA:
2789 NodeMetadata *meta = m_env->getMap().getNodeMetadata(loc.p);
2792 return meta->getInventory();
2795 case InventoryLocation::DETACHED:
2797 if(m_detached_inventories.count(loc.name) == 0)
2799 return m_detached_inventories[loc.name];
2807 void Server::setInventoryModified(const InventoryLocation &loc)
2810 case InventoryLocation::UNDEFINED:
2813 case InventoryLocation::PLAYER:
2815 Player *player = m_env->getPlayer(loc.name.c_str());
2818 PlayerSAO *playersao = player->getPlayerSAO();
2821 playersao->m_inventory_not_sent = true;
2822 playersao->m_wielded_item_not_sent = true;
2825 case InventoryLocation::NODEMETA:
2827 v3s16 blockpos = getNodeBlockPos(loc.p);
2829 MapBlock *block = m_env->getMap().getBlockNoCreateNoEx(blockpos);
2831 block->raiseModified(MOD_STATE_WRITE_NEEDED);
2833 setBlockNotSent(blockpos);
2836 case InventoryLocation::DETACHED:
2838 sendDetachedInventory(loc.name,PEER_ID_INEXISTENT);
2846 void Server::SetBlocksNotSent(std::map<v3s16, MapBlock *>& block)
2848 std::list<u16> clients = m_clients.getClientIDs();
2850 // Set the modified blocks unsent for all the clients
2851 for (std::list<u16>::iterator
2852 i = clients.begin();
2853 i != clients.end(); ++i) {
2854 RemoteClient *client = m_clients.lockedGetClientNoEx(*i);
2856 client->SetBlocksNotSent(block);
2861 void Server::peerAdded(con::Peer *peer)
2863 DSTACK(__FUNCTION_NAME);
2864 verbosestream<<"Server::peerAdded(): peer->id="
2865 <<peer->id<<std::endl;
2868 c.type = con::PEER_ADDED;
2869 c.peer_id = peer->id;
2871 m_peer_change_queue.push_back(c);
2874 void Server::deletingPeer(con::Peer *peer, bool timeout)
2876 DSTACK(__FUNCTION_NAME);
2877 verbosestream<<"Server::deletingPeer(): peer->id="
2878 <<peer->id<<", timeout="<<timeout<<std::endl;
2880 m_clients.event(peer->id, CSE_Disconnect);
2882 c.type = con::PEER_REMOVED;
2883 c.peer_id = peer->id;
2884 c.timeout = timeout;
2885 m_peer_change_queue.push_back(c);
2888 bool Server::getClientConInfo(u16 peer_id, con::rtt_stat_type type, float* retval)
2890 *retval = m_con.getPeerStat(peer_id,type);
2891 if (*retval == -1) return false;
2895 bool Server::getClientInfo(
2904 std::string* vers_string
2907 *state = m_clients.getClientState(peer_id);
2909 RemoteClient* client = m_clients.lockedGetClientNoEx(peer_id, CS_Invalid);
2911 if (client == NULL) {
2916 *uptime = client->uptime();
2917 *ser_vers = client->serialization_version;
2918 *prot_vers = client->net_proto_version;
2920 *major = client->getMajor();
2921 *minor = client->getMinor();
2922 *patch = client->getPatch();
2923 *vers_string = client->getPatch();
2930 void Server::handlePeerChanges()
2932 while(m_peer_change_queue.size() > 0)
2934 con::PeerChange c = m_peer_change_queue.pop_front();
2936 verbosestream<<"Server: Handling peer change: "
2937 <<"id="<<c.peer_id<<", timeout="<<c.timeout
2942 case con::PEER_ADDED:
2943 m_clients.CreateClient(c.peer_id);
2946 case con::PEER_REMOVED:
2947 DeleteClient(c.peer_id, c.timeout?CDR_TIMEOUT:CDR_LEAVE);
2951 assert("Invalid peer change event received!" == 0);
2957 void Server::SendMovement(u16 peer_id)
2959 DSTACK(__FUNCTION_NAME);
2960 std::ostringstream os(std::ios_base::binary);
2962 writeU16(os, TOCLIENT_MOVEMENT);
2963 writeF1000(os, g_settings->getFloat("movement_acceleration_default"));
2964 writeF1000(os, g_settings->getFloat("movement_acceleration_air"));
2965 writeF1000(os, g_settings->getFloat("movement_acceleration_fast"));
2966 writeF1000(os, g_settings->getFloat("movement_speed_walk"));
2967 writeF1000(os, g_settings->getFloat("movement_speed_crouch"));
2968 writeF1000(os, g_settings->getFloat("movement_speed_fast"));
2969 writeF1000(os, g_settings->getFloat("movement_speed_climb"));
2970 writeF1000(os, g_settings->getFloat("movement_speed_jump"));
2971 writeF1000(os, g_settings->getFloat("movement_liquid_fluidity"));
2972 writeF1000(os, g_settings->getFloat("movement_liquid_fluidity_smooth"));
2973 writeF1000(os, g_settings->getFloat("movement_liquid_sink"));
2974 writeF1000(os, g_settings->getFloat("movement_gravity"));
2977 std::string s = os.str();
2978 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
2980 m_clients.send(peer_id, 0, data, true);
2983 void Server::SendHP(u16 peer_id, u8 hp)
2985 DSTACK(__FUNCTION_NAME);
2986 std::ostringstream os(std::ios_base::binary);
2988 writeU16(os, TOCLIENT_HP);
2992 std::string s = os.str();
2993 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
2995 m_clients.send(peer_id, 0, data, true);
2998 void Server::SendBreath(u16 peer_id, u16 breath)
3000 DSTACK(__FUNCTION_NAME);
3001 std::ostringstream os(std::ios_base::binary);
3003 writeU16(os, TOCLIENT_BREATH);
3004 writeU16(os, breath);
3007 std::string s = os.str();
3008 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3010 m_clients.send(peer_id, 0, data, true);
3013 void Server::SendAccessDenied(u16 peer_id,const std::wstring &reason)
3015 DSTACK(__FUNCTION_NAME);
3016 std::ostringstream os(std::ios_base::binary);
3018 writeU16(os, TOCLIENT_ACCESS_DENIED);
3019 os<<serializeWideString(reason);
3022 std::string s = os.str();
3023 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3025 m_clients.send(peer_id, 0, data, true);
3028 void Server::SendDeathscreen(u16 peer_id,bool set_camera_point_target,
3029 v3f camera_point_target)
3031 DSTACK(__FUNCTION_NAME);
3032 std::ostringstream os(std::ios_base::binary);
3034 writeU16(os, TOCLIENT_DEATHSCREEN);
3035 writeU8(os, set_camera_point_target);
3036 writeV3F1000(os, camera_point_target);
3039 std::string s = os.str();
3040 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3042 m_clients.send(peer_id, 0, data, true);
3045 void Server::SendItemDef(u16 peer_id,
3046 IItemDefManager *itemdef, u16 protocol_version)
3048 DSTACK(__FUNCTION_NAME);
3049 std::ostringstream os(std::ios_base::binary);
3053 u32 length of the next item
3054 zlib-compressed serialized ItemDefManager
3056 writeU16(os, TOCLIENT_ITEMDEF);
3057 std::ostringstream tmp_os(std::ios::binary);
3058 itemdef->serialize(tmp_os, protocol_version);
3059 std::ostringstream tmp_os2(std::ios::binary);
3060 compressZlib(tmp_os.str(), tmp_os2);
3061 os<<serializeLongString(tmp_os2.str());
3064 std::string s = os.str();
3065 verbosestream<<"Server: Sending item definitions to id("<<peer_id
3066 <<"): size="<<s.size()<<std::endl;
3067 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3069 m_clients.send(peer_id, 0, data, true);
3072 void Server::SendNodeDef(u16 peer_id,
3073 INodeDefManager *nodedef, u16 protocol_version)
3075 DSTACK(__FUNCTION_NAME);
3076 std::ostringstream os(std::ios_base::binary);
3080 u32 length of the next item
3081 zlib-compressed serialized NodeDefManager
3083 writeU16(os, TOCLIENT_NODEDEF);
3084 std::ostringstream tmp_os(std::ios::binary);
3085 nodedef->serialize(tmp_os, protocol_version);
3086 std::ostringstream tmp_os2(std::ios::binary);
3087 compressZlib(tmp_os.str(), tmp_os2);
3088 os<<serializeLongString(tmp_os2.str());
3091 std::string s = os.str();
3092 verbosestream<<"Server: Sending node definitions to id("<<peer_id
3093 <<"): size="<<s.size()<<std::endl;
3094 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3096 m_clients.send(peer_id, 0, data, true);
3100 Non-static send methods
3103 void Server::SendInventory(u16 peer_id)
3105 DSTACK(__FUNCTION_NAME);
3107 PlayerSAO *playersao = getPlayerSAO(peer_id);
3110 playersao->m_inventory_not_sent = false;
3116 std::ostringstream os;
3117 playersao->getInventory()->serialize(os);
3119 std::string s = os.str();
3121 SharedBuffer<u8> data(s.size()+2);
3122 writeU16(&data[0], TOCLIENT_INVENTORY);
3123 memcpy(&data[2], s.c_str(), s.size());
3126 m_clients.send(peer_id, 0, data, true);
3129 void Server::SendChatMessage(u16 peer_id, const std::wstring &message)
3131 DSTACK(__FUNCTION_NAME);
3133 std::ostringstream os(std::ios_base::binary);
3137 writeU16(buf, TOCLIENT_CHAT_MESSAGE);
3138 os.write((char*)buf, 2);
3141 writeU16(buf, message.size());
3142 os.write((char*)buf, 2);
3145 for(u32 i=0; i<message.size(); i++)
3149 os.write((char*)buf, 2);
3153 std::string s = os.str();
3154 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3156 if (peer_id != PEER_ID_INEXISTENT)
3159 m_clients.send(peer_id, 0, data, true);
3163 m_clients.sendToAll(0,data,true);
3167 void Server::SendShowFormspecMessage(u16 peer_id, const std::string &formspec,
3168 const std::string &formname)
3170 DSTACK(__FUNCTION_NAME);
3172 std::ostringstream os(std::ios_base::binary);
3177 writeU16(buf, TOCLIENT_SHOW_FORMSPEC);
3178 os.write((char*)buf, 2);
3179 os<<serializeLongString(FORMSPEC_VERSION_STRING + formspec);
3180 os<<serializeString(formname);
3183 std::string s = os.str();
3184 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3186 m_clients.send(peer_id, 0, data, true);
3189 // Spawns a particle on peer with peer_id
3190 void Server::SendSpawnParticle(u16 peer_id, v3f pos, v3f velocity, v3f acceleration,
3191 float expirationtime, float size, bool collisiondetection,
3192 bool vertical, std::string texture)
3194 DSTACK(__FUNCTION_NAME);
3196 std::ostringstream os(std::ios_base::binary);
3197 writeU16(os, TOCLIENT_SPAWN_PARTICLE);
3198 writeV3F1000(os, pos);
3199 writeV3F1000(os, velocity);
3200 writeV3F1000(os, acceleration);
3201 writeF1000(os, expirationtime);
3202 writeF1000(os, size);
3203 writeU8(os, collisiondetection);
3204 os<<serializeLongString(texture);
3205 writeU8(os, vertical);
3208 std::string s = os.str();
3209 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3211 if (peer_id != PEER_ID_INEXISTENT)
3214 m_clients.send(peer_id, 0, data, true);
3218 m_clients.sendToAll(0,data,true);
3222 // Adds a ParticleSpawner on peer with peer_id
3223 void Server::SendAddParticleSpawner(u16 peer_id, u16 amount, float spawntime, v3f minpos, v3f maxpos,
3224 v3f minvel, v3f maxvel, v3f minacc, v3f maxacc, float minexptime, float maxexptime,
3225 float minsize, float maxsize, bool collisiondetection, bool vertical, std::string texture, u32 id)
3227 DSTACK(__FUNCTION_NAME);
3229 std::ostringstream os(std::ios_base::binary);
3230 writeU16(os, TOCLIENT_ADD_PARTICLESPAWNER);
3232 writeU16(os, amount);
3233 writeF1000(os, spawntime);
3234 writeV3F1000(os, minpos);
3235 writeV3F1000(os, maxpos);
3236 writeV3F1000(os, minvel);
3237 writeV3F1000(os, maxvel);
3238 writeV3F1000(os, minacc);
3239 writeV3F1000(os, maxacc);
3240 writeF1000(os, minexptime);
3241 writeF1000(os, maxexptime);
3242 writeF1000(os, minsize);
3243 writeF1000(os, maxsize);
3244 writeU8(os, collisiondetection);
3245 os<<serializeLongString(texture);
3247 writeU8(os, vertical);
3250 std::string s = os.str();
3251 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3253 if (peer_id != PEER_ID_INEXISTENT)
3256 m_clients.send(peer_id, 0, data, true);
3259 m_clients.sendToAll(0,data,true);
3263 void Server::SendDeleteParticleSpawner(u16 peer_id, u32 id)
3265 DSTACK(__FUNCTION_NAME);
3267 std::ostringstream os(std::ios_base::binary);
3268 writeU16(os, TOCLIENT_DELETE_PARTICLESPAWNER);
3273 std::string s = os.str();
3274 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3276 if (peer_id != PEER_ID_INEXISTENT) {
3278 m_clients.send(peer_id, 0, data, true);
3281 m_clients.sendToAll(0,data,true);
3286 void Server::SendHUDAdd(u16 peer_id, u32 id, HudElement *form)
3288 std::ostringstream os(std::ios_base::binary);
3291 writeU16(os, TOCLIENT_HUDADD);
3293 writeU8(os, (u8)form->type);
3294 writeV2F1000(os, form->pos);
3295 os << serializeString(form->name);
3296 writeV2F1000(os, form->scale);
3297 os << serializeString(form->text);
3298 writeU32(os, form->number);
3299 writeU32(os, form->item);
3300 writeU32(os, form->dir);
3301 writeV2F1000(os, form->align);
3302 writeV2F1000(os, form->offset);
3303 writeV3F1000(os, form->world_pos);
3304 writeV2S32(os,form->size);
3307 std::string s = os.str();
3308 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3310 m_clients.send(peer_id, 1, data, true);
3313 void Server::SendHUDRemove(u16 peer_id, u32 id)
3315 std::ostringstream os(std::ios_base::binary);
3318 writeU16(os, TOCLIENT_HUDRM);
3322 std::string s = os.str();
3323 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3326 m_clients.send(peer_id, 1, data, true);
3329 void Server::SendHUDChange(u16 peer_id, u32 id, HudElementStat stat, void *value)
3331 std::ostringstream os(std::ios_base::binary);
3334 writeU16(os, TOCLIENT_HUDCHANGE);
3336 writeU8(os, (u8)stat);
3339 case HUD_STAT_SCALE:
3340 case HUD_STAT_ALIGN:
3341 case HUD_STAT_OFFSET:
3342 writeV2F1000(os, *(v2f *)value);
3346 os << serializeString(*(std::string *)value);
3348 case HUD_STAT_WORLD_POS:
3349 writeV3F1000(os, *(v3f *)value);
3352 writeV2S32(os,*(v2s32 *)value);
3354 case HUD_STAT_NUMBER:
3358 writeU32(os, *(u32 *)value);
3363 std::string s = os.str();
3364 SharedBuffer<u8> data((u8 *)s.c_str(), s.size());
3366 m_clients.send(peer_id, 0, data, true);
3369 void Server::SendHUDSetFlags(u16 peer_id, u32 flags, u32 mask)
3371 std::ostringstream os(std::ios_base::binary);
3374 writeU16(os, TOCLIENT_HUD_SET_FLAGS);
3376 //////////////////////////// compatibility code to be removed //////////////
3377 flags &= ~(HUD_FLAG_HEALTHBAR_VISIBLE | HUD_FLAG_BREATHBAR_VISIBLE);
3378 ////////////////////////////////////////////////////////////////////////////
3379 writeU32(os, flags);
3383 std::string s = os.str();
3384 SharedBuffer<u8> data((u8 *)s.c_str(), s.size());
3386 m_clients.send(peer_id, 0, data, true);
3389 void Server::SendHUDSetParam(u16 peer_id, u16 param, const std::string &value)
3391 std::ostringstream os(std::ios_base::binary);
3394 writeU16(os, TOCLIENT_HUD_SET_PARAM);
3395 writeU16(os, param);
3396 os<<serializeString(value);
3399 std::string s = os.str();
3400 SharedBuffer<u8> data((u8 *)s.c_str(), s.size());
3402 m_clients.send(peer_id, 0, data, true);
3405 void Server::SendSetSky(u16 peer_id, const video::SColor &bgcolor,
3406 const std::string &type, const std::vector<std::string> ¶ms)
3408 std::ostringstream os(std::ios_base::binary);
3411 writeU16(os, TOCLIENT_SET_SKY);
3412 writeARGB8(os, bgcolor);
3413 os<<serializeString(type);
3414 writeU16(os, params.size());
3415 for(size_t i=0; i<params.size(); i++)
3416 os<<serializeString(params[i]);
3419 std::string s = os.str();
3420 SharedBuffer<u8> data((u8 *)s.c_str(), s.size());
3422 m_clients.send(peer_id, 0, data, true);
3425 void Server::SendOverrideDayNightRatio(u16 peer_id, bool do_override,
3428 std::ostringstream os(std::ios_base::binary);
3431 writeU16(os, TOCLIENT_OVERRIDE_DAY_NIGHT_RATIO);
3432 writeU8(os, do_override);
3433 writeU16(os, ratio*65535);
3436 std::string s = os.str();
3437 SharedBuffer<u8> data((u8 *)s.c_str(), s.size());
3439 m_clients.send(peer_id, 0, data, true);
3442 void Server::SendTimeOfDay(u16 peer_id, u16 time, f32 time_speed)
3444 DSTACK(__FUNCTION_NAME);
3447 SharedBuffer<u8> data(2+2+4);
3448 writeU16(&data[0], TOCLIENT_TIME_OF_DAY);
3449 writeU16(&data[2], time);
3450 writeF1000(&data[4], time_speed);
3452 if (peer_id == PEER_ID_INEXISTENT) {
3453 m_clients.sendToAll(0,data,true);
3457 m_clients.send(peer_id, 0, data, true);
3461 void Server::SendPlayerHP(u16 peer_id)
3463 DSTACK(__FUNCTION_NAME);
3464 PlayerSAO *playersao = getPlayerSAO(peer_id);
3466 playersao->m_hp_not_sent = false;
3467 SendHP(peer_id, playersao->getHP());
3468 m_script->player_event(playersao,"health_changed");
3470 // Send to other clients
3471 std::string str = gob_cmd_punched(playersao->readDamage(), playersao->getHP());
3472 ActiveObjectMessage aom(playersao->getId(), true, str);
3473 playersao->m_messages_out.push_back(aom);
3476 void Server::SendPlayerBreath(u16 peer_id)
3478 DSTACK(__FUNCTION_NAME);
3479 PlayerSAO *playersao = getPlayerSAO(peer_id);
3481 playersao->m_breath_not_sent = false;
3482 m_script->player_event(playersao,"breath_changed");
3483 SendBreath(peer_id, playersao->getBreath());
3486 void Server::SendMovePlayer(u16 peer_id)
3488 DSTACK(__FUNCTION_NAME);
3489 Player *player = m_env->getPlayer(peer_id);
3492 std::ostringstream os(std::ios_base::binary);
3493 writeU16(os, TOCLIENT_MOVE_PLAYER);
3494 writeV3F1000(os, player->getPosition());
3495 writeF1000(os, player->getPitch());
3496 writeF1000(os, player->getYaw());
3499 v3f pos = player->getPosition();
3500 f32 pitch = player->getPitch();
3501 f32 yaw = player->getYaw();
3502 verbosestream<<"Server: Sending TOCLIENT_MOVE_PLAYER"
3503 <<" pos=("<<pos.X<<","<<pos.Y<<","<<pos.Z<<")"
3510 std::string s = os.str();
3511 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3513 m_clients.send(peer_id, 0, data, true);
3516 void Server::SendLocalPlayerAnimations(u16 peer_id, v2s32 animation_frames[4], f32 animation_speed)
3518 std::ostringstream os(std::ios_base::binary);
3520 writeU16(os, TOCLIENT_LOCAL_PLAYER_ANIMATIONS);
3521 writeV2S32(os, animation_frames[0]);
3522 writeV2S32(os, animation_frames[1]);
3523 writeV2S32(os, animation_frames[2]);
3524 writeV2S32(os, animation_frames[3]);
3525 writeF1000(os, animation_speed);
3528 std::string s = os.str();
3529 SharedBuffer<u8> data((u8 *)s.c_str(), s.size());
3531 m_clients.send(peer_id, 0, data, true);
3534 void Server::SendEyeOffset(u16 peer_id, v3f first, v3f third)
3536 std::ostringstream os(std::ios_base::binary);
3538 writeU16(os, TOCLIENT_EYE_OFFSET);
3539 writeV3F1000(os, first);
3540 writeV3F1000(os, third);
3543 std::string s = os.str();
3544 SharedBuffer<u8> data((u8 *)s.c_str(), s.size());
3546 m_clients.send(peer_id, 0, data, true);
3548 void Server::SendPlayerPrivileges(u16 peer_id)
3550 Player *player = m_env->getPlayer(peer_id);
3552 if(player->peer_id == PEER_ID_INEXISTENT)
3555 std::set<std::string> privs;
3556 m_script->getAuth(player->getName(), NULL, &privs);
3558 std::ostringstream os(std::ios_base::binary);
3559 writeU16(os, TOCLIENT_PRIVILEGES);
3560 writeU16(os, privs.size());
3561 for(std::set<std::string>::const_iterator i = privs.begin();
3562 i != privs.end(); i++){
3563 os<<serializeString(*i);
3567 std::string s = os.str();
3568 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3570 m_clients.send(peer_id, 0, data, true);
3573 void Server::SendPlayerInventoryFormspec(u16 peer_id)
3575 Player *player = m_env->getPlayer(peer_id);
3577 if(player->peer_id == PEER_ID_INEXISTENT)
3580 std::ostringstream os(std::ios_base::binary);
3581 writeU16(os, TOCLIENT_INVENTORY_FORMSPEC);
3582 os<<serializeLongString(FORMSPEC_VERSION_STRING + player->inventory_formspec);
3585 std::string s = os.str();
3586 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3588 m_clients.send(peer_id, 0, data, true);
3591 s32 Server::playSound(const SimpleSoundSpec &spec,
3592 const ServerSoundParams ¶ms)
3594 // Find out initial position of sound
3595 bool pos_exists = false;
3596 v3f pos = params.getPos(m_env, &pos_exists);
3597 // If position is not found while it should be, cancel sound
3598 if(pos_exists != (params.type != ServerSoundParams::SSP_LOCAL))
3601 // Filter destination clients
3602 std::list<u16> dst_clients;
3603 if(params.to_player != "")
3605 Player *player = m_env->getPlayer(params.to_player.c_str());
3607 infostream<<"Server::playSound: Player \""<<params.to_player
3608 <<"\" not found"<<std::endl;
3611 if(player->peer_id == PEER_ID_INEXISTENT){
3612 infostream<<"Server::playSound: Player \""<<params.to_player
3613 <<"\" not connected"<<std::endl;
3616 dst_clients.push_back(player->peer_id);
3620 std::list<u16> clients = m_clients.getClientIDs();
3622 for(std::list<u16>::iterator
3623 i = clients.begin(); i != clients.end(); ++i)
3625 Player *player = m_env->getPlayer(*i);
3629 if(player->getPosition().getDistanceFrom(pos) >
3630 params.max_hear_distance)
3633 dst_clients.push_back(*i);
3636 if(dst_clients.size() == 0)
3640 s32 id = m_next_sound_id++;
3641 // The sound will exist as a reference in m_playing_sounds
3642 m_playing_sounds[id] = ServerPlayingSound();
3643 ServerPlayingSound &psound = m_playing_sounds[id];
3644 psound.params = params;
3645 for(std::list<u16>::iterator i = dst_clients.begin();
3646 i != dst_clients.end(); i++)
3647 psound.clients.insert(*i);
3649 std::ostringstream os(std::ios_base::binary);
3650 writeU16(os, TOCLIENT_PLAY_SOUND);
3652 os<<serializeString(spec.name);
3653 writeF1000(os, spec.gain * params.gain);
3654 writeU8(os, params.type);
3655 writeV3F1000(os, pos);
3656 writeU16(os, params.object);
3657 writeU8(os, params.loop);
3659 std::string s = os.str();
3660 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3662 for(std::list<u16>::iterator i = dst_clients.begin();
3663 i != dst_clients.end(); i++){
3665 m_clients.send(*i, 0, data, true);
3669 void Server::stopSound(s32 handle)
3671 // Get sound reference
3672 std::map<s32, ServerPlayingSound>::iterator i =
3673 m_playing_sounds.find(handle);
3674 if(i == m_playing_sounds.end())
3676 ServerPlayingSound &psound = i->second;
3678 std::ostringstream os(std::ios_base::binary);
3679 writeU16(os, TOCLIENT_STOP_SOUND);
3680 writeS32(os, handle);
3682 std::string s = os.str();
3683 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3685 for(std::set<u16>::iterator i = psound.clients.begin();
3686 i != psound.clients.end(); i++){
3688 m_clients.send(*i, 0, data, true);
3690 // Remove sound reference
3691 m_playing_sounds.erase(i);
3694 void Server::sendRemoveNode(v3s16 p, u16 ignore_id,
3695 std::list<u16> *far_players, float far_d_nodes)
3697 float maxd = far_d_nodes*BS;
3698 v3f p_f = intToFloat(p, BS);
3702 SharedBuffer<u8> reply(replysize);
3703 writeU16(&reply[0], TOCLIENT_REMOVENODE);
3704 writeS16(&reply[2], p.X);
3705 writeS16(&reply[4], p.Y);
3706 writeS16(&reply[6], p.Z);
3708 std::list<u16> clients = m_clients.getClientIDs();
3709 for(std::list<u16>::iterator
3710 i = clients.begin();
3711 i != clients.end(); ++i)
3716 Player *player = m_env->getPlayer(*i);
3719 // If player is far away, only set modified blocks not sent
3720 v3f player_pos = player->getPosition();
3721 if(player_pos.getDistanceFrom(p_f) > maxd)
3723 far_players->push_back(*i);
3730 m_clients.send(*i, 0, reply, true);
3734 void Server::sendAddNode(v3s16 p, MapNode n, u16 ignore_id,
3735 std::list<u16> *far_players, float far_d_nodes,
3736 bool remove_metadata)
3738 float maxd = far_d_nodes*BS;
3739 v3f p_f = intToFloat(p, BS);
3741 std::list<u16> clients = m_clients.getClientIDs();
3742 for(std::list<u16>::iterator
3743 i = clients.begin();
3744 i != clients.end(); ++i)
3750 Player *player = m_env->getPlayer(*i);
3753 // If player is far away, only set modified blocks not sent
3754 v3f player_pos = player->getPosition();
3755 if(player_pos.getDistanceFrom(p_f) > maxd)
3757 far_players->push_back(*i);
3762 SharedBuffer<u8> reply(0);
3764 RemoteClient* client = m_clients.lockedGetClientNoEx(*i);
3768 u32 replysize = 9 + MapNode::serializedLength(client->serialization_version);
3769 reply = SharedBuffer<u8>(replysize);
3770 writeU16(&reply[0], TOCLIENT_ADDNODE);
3771 writeS16(&reply[2], p.X);
3772 writeS16(&reply[4], p.Y);
3773 writeS16(&reply[6], p.Z);
3774 n.serialize(&reply[8], client->serialization_version);
3775 u32 index = 8 + MapNode::serializedLength(client->serialization_version);
3776 writeU8(&reply[index], remove_metadata ? 0 : 1);
3778 if (!remove_metadata) {
3779 if (client->net_proto_version <= 21) {
3780 // Old clients always clear metadata; fix it
3781 // by sending the full block again.
3782 client->SetBlockNotSent(p);
3789 if (reply.getSize() > 0)
3790 m_clients.send(*i, 0, reply, true);
3794 void Server::setBlockNotSent(v3s16 p)
3796 std::list<u16> clients = m_clients.getClientIDs();
3798 for(std::list<u16>::iterator
3799 i = clients.begin();
3800 i != clients.end(); ++i)
3802 RemoteClient *client = m_clients.lockedGetClientNoEx(*i);
3803 client->SetBlockNotSent(p);
3808 void Server::SendBlockNoLock(u16 peer_id, MapBlock *block, u8 ver, u16 net_proto_version)
3810 DSTACK(__FUNCTION_NAME);
3812 v3s16 p = block->getPos();
3816 bool completely_air = true;
3817 for(s16 z0=0; z0<MAP_BLOCKSIZE; z0++)
3818 for(s16 x0=0; x0<MAP_BLOCKSIZE; x0++)
3819 for(s16 y0=0; y0<MAP_BLOCKSIZE; y0++)
3821 if(block->getNodeNoEx(v3s16(x0,y0,z0)).d != CONTENT_AIR)
3823 completely_air = false;
3824 x0 = y0 = z0 = MAP_BLOCKSIZE; // Break out
3829 infostream<<"Server: Sending block ("<<p.X<<","<<p.Y<<","<<p.Z<<"): ";
3831 infostream<<"[completely air] ";
3832 infostream<<std::endl;
3836 Create a packet with the block in the right format
3839 std::ostringstream os(std::ios_base::binary);
3840 block->serialize(os, ver, false);
3841 block->serializeNetworkSpecific(os, net_proto_version);
3842 std::string s = os.str();
3843 SharedBuffer<u8> blockdata((u8*)s.c_str(), s.size());
3845 u32 replysize = 8 + blockdata.getSize();
3846 SharedBuffer<u8> reply(replysize);
3847 writeU16(&reply[0], TOCLIENT_BLOCKDATA);
3848 writeS16(&reply[2], p.X);
3849 writeS16(&reply[4], p.Y);
3850 writeS16(&reply[6], p.Z);
3851 memcpy(&reply[8], *blockdata, blockdata.getSize());
3853 /*infostream<<"Server: Sending block ("<<p.X<<","<<p.Y<<","<<p.Z<<")"
3854 <<": \tpacket size: "<<replysize<<std::endl;*/
3859 m_clients.send(peer_id, 2, reply, true);
3862 void Server::SendBlocks(float dtime)
3864 DSTACK(__FUNCTION_NAME);
3866 JMutexAutoLock envlock(m_env_mutex);
3867 //TODO check if one big lock could be faster then multiple small ones
3869 ScopeProfiler sp(g_profiler, "Server: sel and send blocks to clients");
3871 std::vector<PrioritySortedBlockTransfer> queue;
3873 s32 total_sending = 0;
3876 ScopeProfiler sp(g_profiler, "Server: selecting blocks for sending");
3878 std::list<u16> clients = m_clients.getClientIDs();
3881 for(std::list<u16>::iterator
3882 i = clients.begin();
3883 i != clients.end(); ++i)
3885 RemoteClient *client = m_clients.lockedGetClientNoEx(*i, CS_Active);
3890 total_sending += client->SendingCount();
3891 client->GetNextBlocks(m_env,m_emerge, dtime, queue);
3897 // Lowest priority number comes first.
3898 // Lowest is most important.
3899 std::sort(queue.begin(), queue.end());
3902 for(u32 i=0; i<queue.size(); i++)
3904 //TODO: Calculate limit dynamically
3905 if(total_sending >= g_settings->getS32
3906 ("max_simultaneous_block_sends_server_total"))
3909 PrioritySortedBlockTransfer q = queue[i];
3911 MapBlock *block = NULL;
3914 block = m_env->getMap().getBlockNoCreate(q.pos);
3916 catch(InvalidPositionException &e)
3921 RemoteClient *client = m_clients.lockedGetClientNoEx(q.peer_id, CS_Active);
3926 SendBlockNoLock(q.peer_id, block, client->serialization_version, client->net_proto_version);
3928 client->SentBlock(q.pos);
3934 void Server::fillMediaCache()
3936 DSTACK(__FUNCTION_NAME);
3938 infostream<<"Server: Calculating media file checksums"<<std::endl;
3940 // Collect all media file paths
3941 std::list<std::string> paths;
3942 for(std::vector<ModSpec>::iterator i = m_mods.begin();
3943 i != m_mods.end(); i++){
3944 const ModSpec &mod = *i;
3945 paths.push_back(mod.path + DIR_DELIM + "textures");
3946 paths.push_back(mod.path + DIR_DELIM + "sounds");
3947 paths.push_back(mod.path + DIR_DELIM + "media");
3948 paths.push_back(mod.path + DIR_DELIM + "models");
3950 paths.push_back(porting::path_user + DIR_DELIM + "textures" + DIR_DELIM + "server");
3952 // Collect media file information from paths into cache
3953 for(std::list<std::string>::iterator i = paths.begin();
3954 i != paths.end(); i++)
3956 std::string mediapath = *i;
3957 std::vector<fs::DirListNode> dirlist = fs::GetDirListing(mediapath);
3958 for(u32 j=0; j<dirlist.size(); j++){
3959 if(dirlist[j].dir) // Ignode dirs
3961 std::string filename = dirlist[j].name;
3962 // If name contains illegal characters, ignore the file
3963 if(!string_allowed(filename, TEXTURENAME_ALLOWED_CHARS)){
3964 infostream<<"Server: ignoring illegal file name: \""
3965 <<filename<<"\""<<std::endl;
3968 // If name is not in a supported format, ignore it
3969 const char *supported_ext[] = {
3970 ".png", ".jpg", ".bmp", ".tga",
3971 ".pcx", ".ppm", ".psd", ".wal", ".rgb",
3973 ".x", ".b3d", ".md2", ".obj",
3976 if(removeStringEnd(filename, supported_ext) == ""){
3977 infostream<<"Server: ignoring unsupported file extension: \""
3978 <<filename<<"\""<<std::endl;
3981 // Ok, attempt to load the file and add to cache
3982 std::string filepath = mediapath + DIR_DELIM + filename;
3984 std::ifstream fis(filepath.c_str(), std::ios_base::binary);
3985 if(fis.good() == false){
3986 errorstream<<"Server::fillMediaCache(): Could not open \""
3987 <<filename<<"\" for reading"<<std::endl;
3990 std::ostringstream tmp_os(std::ios_base::binary);
3994 fis.read(buf, 1024);
3995 std::streamsize len = fis.gcount();
3996 tmp_os.write(buf, len);
4005 errorstream<<"Server::fillMediaCache(): Failed to read \""
4006 <<filename<<"\""<<std::endl;
4009 if(tmp_os.str().length() == 0){
4010 errorstream<<"Server::fillMediaCache(): Empty file \""
4011 <<filepath<<"\""<<std::endl;
4016 sha1.addBytes(tmp_os.str().c_str(), tmp_os.str().length());
4018 unsigned char *digest = sha1.getDigest();
4019 std::string sha1_base64 = base64_encode(digest, 20);
4020 std::string sha1_hex = hex_encode((char*)digest, 20);
4024 this->m_media[filename] = MediaInfo(filepath, sha1_base64);
4025 verbosestream<<"Server: "<<sha1_hex<<" is "<<filename<<std::endl;
4030 struct SendableMediaAnnouncement
4033 std::string sha1_digest;
4035 SendableMediaAnnouncement(const std::string &name_="",
4036 const std::string &sha1_digest_=""):
4038 sha1_digest(sha1_digest_)
4042 void Server::sendMediaAnnouncement(u16 peer_id)
4044 DSTACK(__FUNCTION_NAME);
4046 verbosestream<<"Server: Announcing files to id("<<peer_id<<")"
4049 std::list<SendableMediaAnnouncement> file_announcements;
4051 for(std::map<std::string, MediaInfo>::iterator i = m_media.begin();
4052 i != m_media.end(); i++){
4054 file_announcements.push_back(
4055 SendableMediaAnnouncement(i->first, i->second.sha1_digest));
4059 std::ostringstream os(std::ios_base::binary);
4067 u16 length of sha1_digest
4072 writeU16(os, TOCLIENT_ANNOUNCE_MEDIA);
4073 writeU16(os, file_announcements.size());
4075 for(std::list<SendableMediaAnnouncement>::iterator
4076 j = file_announcements.begin();
4077 j != file_announcements.end(); ++j){
4078 os<<serializeString(j->name);
4079 os<<serializeString(j->sha1_digest);
4081 os<<serializeString(g_settings->get("remote_media"));
4084 std::string s = os.str();
4085 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
4088 m_clients.send(peer_id, 0, data, true);
4091 struct SendableMedia
4097 SendableMedia(const std::string &name_="", const std::string &path_="",
4098 const std::string &data_=""):
4105 void Server::sendRequestedMedia(u16 peer_id,
4106 const std::list<std::string> &tosend)
4108 DSTACK(__FUNCTION_NAME);
4110 verbosestream<<"Server::sendRequestedMedia(): "
4111 <<"Sending files to client"<<std::endl;
4115 // Put 5kB in one bunch (this is not accurate)
4116 u32 bytes_per_bunch = 5000;
4118 std::vector< std::list<SendableMedia> > file_bunches;
4119 file_bunches.push_back(std::list<SendableMedia>());
4121 u32 file_size_bunch_total = 0;
4123 for(std::list<std::string>::const_iterator i = tosend.begin();
4124 i != tosend.end(); ++i)
4126 const std::string &name = *i;
4128 if(m_media.find(name) == m_media.end()){
4129 errorstream<<"Server::sendRequestedMedia(): Client asked for "
4130 <<"unknown file \""<<(name)<<"\""<<std::endl;
4134 //TODO get path + name
4135 std::string tpath = m_media[name].path;
4138 std::ifstream fis(tpath.c_str(), std::ios_base::binary);
4139 if(fis.good() == false){
4140 errorstream<<"Server::sendRequestedMedia(): Could not open \""
4141 <<tpath<<"\" for reading"<<std::endl;
4144 std::ostringstream tmp_os(std::ios_base::binary);
4148 fis.read(buf, 1024);
4149 std::streamsize len = fis.gcount();
4150 tmp_os.write(buf, len);
4151 file_size_bunch_total += len;
4160 errorstream<<"Server::sendRequestedMedia(): Failed to read \""
4161 <<name<<"\""<<std::endl;
4164 /*infostream<<"Server::sendRequestedMedia(): Loaded \""
4165 <<tname<<"\""<<std::endl;*/
4167 file_bunches[file_bunches.size()-1].push_back(
4168 SendableMedia(name, tpath, tmp_os.str()));
4170 // Start next bunch if got enough data
4171 if(file_size_bunch_total >= bytes_per_bunch){
4172 file_bunches.push_back(std::list<SendableMedia>());
4173 file_size_bunch_total = 0;
4178 /* Create and send packets */
4180 u32 num_bunches = file_bunches.size();
4181 for(u32 i=0; i<num_bunches; i++)
4183 std::ostringstream os(std::ios_base::binary);
4187 u16 total number of texture bunches
4188 u16 index of this bunch
4189 u32 number of files in this bunch
4198 writeU16(os, TOCLIENT_MEDIA);
4199 writeU16(os, num_bunches);
4201 writeU32(os, file_bunches[i].size());
4203 for(std::list<SendableMedia>::iterator
4204 j = file_bunches[i].begin();
4205 j != file_bunches[i].end(); ++j){
4206 os<<serializeString(j->name);
4207 os<<serializeLongString(j->data);
4211 std::string s = os.str();
4212 verbosestream<<"Server::sendRequestedMedia(): bunch "
4213 <<i<<"/"<<num_bunches
4214 <<" files="<<file_bunches[i].size()
4215 <<" size=" <<s.size()<<std::endl;
4216 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
4218 m_clients.send(peer_id, 2, data, true);
4222 void Server::sendDetachedInventory(const std::string &name, u16 peer_id)
4224 if(m_detached_inventories.count(name) == 0){
4225 errorstream<<__FUNCTION_NAME<<": \""<<name<<"\" not found"<<std::endl;
4228 Inventory *inv = m_detached_inventories[name];
4230 std::ostringstream os(std::ios_base::binary);
4231 writeU16(os, TOCLIENT_DETACHED_INVENTORY);
4232 os<<serializeString(name);
4236 std::string s = os.str();
4237 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
4239 if (peer_id != PEER_ID_INEXISTENT)
4242 m_clients.send(peer_id, 0, data, true);
4246 m_clients.sendToAll(0,data,true);
4250 void Server::sendDetachedInventories(u16 peer_id)
4252 DSTACK(__FUNCTION_NAME);
4254 for(std::map<std::string, Inventory*>::iterator
4255 i = m_detached_inventories.begin();
4256 i != m_detached_inventories.end(); i++){
4257 const std::string &name = i->first;
4258 //Inventory *inv = i->second;
4259 sendDetachedInventory(name, peer_id);
4267 void Server::DiePlayer(u16 peer_id)
4269 DSTACK(__FUNCTION_NAME);
4271 PlayerSAO *playersao = getPlayerSAO(peer_id);
4274 infostream<<"Server::DiePlayer(): Player "
4275 <<playersao->getPlayer()->getName()
4276 <<" dies"<<std::endl;
4278 playersao->setHP(0);
4280 // Trigger scripted stuff
4281 m_script->on_dieplayer(playersao);
4283 SendPlayerHP(peer_id);
4284 SendDeathscreen(peer_id, false, v3f(0,0,0));
4287 void Server::RespawnPlayer(u16 peer_id)
4289 DSTACK(__FUNCTION_NAME);
4291 PlayerSAO *playersao = getPlayerSAO(peer_id);
4294 infostream<<"Server::RespawnPlayer(): Player "
4295 <<playersao->getPlayer()->getName()
4296 <<" respawns"<<std::endl;
4298 playersao->setHP(PLAYER_MAX_HP);
4300 bool repositioned = m_script->on_respawnplayer(playersao);
4302 v3f pos = findSpawnPos(m_env->getServerMap());
4303 playersao->setPos(pos);
4307 void Server::DenyAccess(u16 peer_id, const std::wstring &reason)
4309 DSTACK(__FUNCTION_NAME);
4311 SendAccessDenied(peer_id, reason);
4312 m_clients.event(peer_id, CSE_SetDenied);
4313 m_con.DisconnectPeer(peer_id);
4316 void Server::DeleteClient(u16 peer_id, ClientDeletionReason reason)
4318 DSTACK(__FUNCTION_NAME);
4319 std::wstring message;
4322 Clear references to playing sounds
4324 for(std::map<s32, ServerPlayingSound>::iterator
4325 i = m_playing_sounds.begin();
4326 i != m_playing_sounds.end();)
4328 ServerPlayingSound &psound = i->second;
4329 psound.clients.erase(peer_id);
4330 if(psound.clients.size() == 0)
4331 m_playing_sounds.erase(i++);
4336 Player *player = m_env->getPlayer(peer_id);
4338 // Collect information about leaving in chat
4340 if(player != NULL && reason != CDR_DENY)
4342 std::wstring name = narrow_to_wide(player->getName());
4345 message += L" left the game.";
4346 if(reason == CDR_TIMEOUT)
4347 message += L" (timed out)";
4351 /* Run scripts and remove from environment */
4355 PlayerSAO *playersao = player->getPlayerSAO();
4358 m_script->on_leaveplayer(playersao);
4360 playersao->disconnected();
4368 if(player != NULL && reason != CDR_DENY)
4370 std::ostringstream os(std::ios_base::binary);
4371 std::list<u16> clients = m_clients.getClientIDs();
4373 for(std::list<u16>::iterator
4374 i = clients.begin();
4375 i != clients.end(); ++i)
4378 Player *player = m_env->getPlayer(*i);
4381 // Get name of player
4382 os<<player->getName()<<" ";
4385 actionstream<<player->getName()<<" "
4386 <<(reason==CDR_TIMEOUT?"times out.":"leaves game.")
4387 <<" List of players: "<<os.str()<<std::endl;
4391 JMutexAutoLock env_lock(m_env_mutex);
4392 m_clients.DeleteClient(peer_id);
4396 // Send leave chat message to all remaining clients
4397 if(message.length() != 0)
4398 SendChatMessage(PEER_ID_INEXISTENT,message);
4401 void Server::UpdateCrafting(u16 peer_id)
4403 DSTACK(__FUNCTION_NAME);
4405 Player* player = m_env->getPlayer(peer_id);
4408 // Get a preview for crafting
4410 InventoryLocation loc;
4411 loc.setPlayer(player->getName());
4412 getCraftingResult(&player->inventory, preview, false, this);
4413 m_env->getScriptIface()->item_CraftPredict(preview, player->getPlayerSAO(), (&player->inventory)->getList("craft"), loc);
4415 // Put the new preview in
4416 InventoryList *plist = player->inventory.getList("craftpreview");
4418 assert(plist->getSize() >= 1);
4419 plist->changeItem(0, preview);
4422 RemoteClient* Server::getClient(u16 peer_id, ClientState state_min)
4424 RemoteClient *client = getClientNoEx(peer_id,state_min);
4426 throw ClientNotFoundException("Client not found");
4430 RemoteClient* Server::getClientNoEx(u16 peer_id, ClientState state_min)
4432 return m_clients.getClientNoEx(peer_id, state_min);
4435 std::string Server::getPlayerName(u16 peer_id)
4437 Player *player = m_env->getPlayer(peer_id);
4439 return "[id="+itos(peer_id)+"]";
4440 return player->getName();
4443 PlayerSAO* Server::getPlayerSAO(u16 peer_id)
4445 Player *player = m_env->getPlayer(peer_id);
4448 return player->getPlayerSAO();
4451 std::wstring Server::getStatusString()
4453 std::wostringstream os(std::ios_base::binary);
4456 os<<L"version="<<narrow_to_wide(minetest_version_simple);
4458 os<<L", uptime="<<m_uptime.get();
4460 os<<L", max_lag="<<m_env->getMaxLagEstimate();
4461 // Information about clients
4464 std::list<u16> clients = m_clients.getClientIDs();
4465 for(std::list<u16>::iterator i = clients.begin();
4466 i != clients.end(); ++i)
4469 Player *player = m_env->getPlayer(*i);
4470 // Get name of player
4471 std::wstring name = L"unknown";
4473 name = narrow_to_wide(player->getName());
4474 // Add name to information string
4482 if(((ServerMap*)(&m_env->getMap()))->isSavingEnabled() == false)
4483 os<<std::endl<<L"# Server: "<<" WARNING: Map saving is disabled.";
4484 if(g_settings->get("motd") != "")
4485 os<<std::endl<<L"# Server: "<<narrow_to_wide(g_settings->get("motd"));
4489 std::set<std::string> Server::getPlayerEffectivePrivs(const std::string &name)
4491 std::set<std::string> privs;
4492 m_script->getAuth(name, NULL, &privs);
4496 bool Server::checkPriv(const std::string &name, const std::string &priv)
4498 std::set<std::string> privs = getPlayerEffectivePrivs(name);
4499 return (privs.count(priv) != 0);
4502 void Server::reportPrivsModified(const std::string &name)
4505 std::list<u16> clients = m_clients.getClientIDs();
4506 for(std::list<u16>::iterator
4507 i = clients.begin();
4508 i != clients.end(); ++i){
4509 Player *player = m_env->getPlayer(*i);
4510 reportPrivsModified(player->getName());
4513 Player *player = m_env->getPlayer(name.c_str());
4516 SendPlayerPrivileges(player->peer_id);
4517 PlayerSAO *sao = player->getPlayerSAO();
4520 sao->updatePrivileges(
4521 getPlayerEffectivePrivs(name),
4526 void Server::reportInventoryFormspecModified(const std::string &name)
4528 Player *player = m_env->getPlayer(name.c_str());
4531 SendPlayerInventoryFormspec(player->peer_id);
4534 void Server::setIpBanned(const std::string &ip, const std::string &name)
4536 m_banmanager->add(ip, name);
4539 void Server::unsetIpBanned(const std::string &ip_or_name)
4541 m_banmanager->remove(ip_or_name);
4544 std::string Server::getBanDescription(const std::string &ip_or_name)
4546 return m_banmanager->getBanDescription(ip_or_name);
4549 void Server::notifyPlayer(const char *name, const std::wstring &msg)
4551 Player *player = m_env->getPlayer(name);
4555 if (player->peer_id == PEER_ID_INEXISTENT)
4558 SendChatMessage(player->peer_id, msg);
4561 bool Server::showFormspec(const char *playername, const std::string &formspec, const std::string &formname)
4563 Player *player = m_env->getPlayer(playername);
4567 infostream<<"showFormspec: couldn't find player:"<<playername<<std::endl;
4571 SendShowFormspecMessage(player->peer_id, formspec, formname);
4575 u32 Server::hudAdd(Player *player, HudElement *form) {
4579 u32 id = player->addHud(form);
4581 SendHUDAdd(player->peer_id, id, form);
4586 bool Server::hudRemove(Player *player, u32 id) {
4590 HudElement* todel = player->removeHud(id);
4597 SendHUDRemove(player->peer_id, id);
4601 bool Server::hudChange(Player *player, u32 id, HudElementStat stat, void *data) {
4605 SendHUDChange(player->peer_id, id, stat, data);
4609 bool Server::hudSetFlags(Player *player, u32 flags, u32 mask) {
4613 SendHUDSetFlags(player->peer_id, flags, mask);
4614 player->hud_flags = flags;
4616 PlayerSAO* playersao = player->getPlayerSAO();
4618 if (playersao == NULL)
4621 m_script->player_event(playersao, "hud_changed");
4625 bool Server::hudSetHotbarItemcount(Player *player, s32 hotbar_itemcount) {
4628 if (hotbar_itemcount <= 0 || hotbar_itemcount > HUD_HOTBAR_ITEMCOUNT_MAX)
4631 std::ostringstream os(std::ios::binary);
4632 writeS32(os, hotbar_itemcount);
4633 SendHUDSetParam(player->peer_id, HUD_PARAM_HOTBAR_ITEMCOUNT, os.str());
4637 void Server::hudSetHotbarImage(Player *player, std::string name) {
4641 SendHUDSetParam(player->peer_id, HUD_PARAM_HOTBAR_IMAGE, name);
4644 void Server::hudSetHotbarSelectedImage(Player *player, std::string name) {
4648 SendHUDSetParam(player->peer_id, HUD_PARAM_HOTBAR_SELECTED_IMAGE, name);
4651 bool Server::setLocalPlayerAnimations(Player *player, v2s32 animation_frames[4], f32 frame_speed)
4656 SendLocalPlayerAnimations(player->peer_id, animation_frames, frame_speed);
4660 bool Server::setPlayerEyeOffset(Player *player, v3f first, v3f third)
4665 SendEyeOffset(player->peer_id, first, third);
4669 bool Server::setSky(Player *player, const video::SColor &bgcolor,
4670 const std::string &type, const std::vector<std::string> ¶ms)
4675 SendSetSky(player->peer_id, bgcolor, type, params);
4679 bool Server::overrideDayNightRatio(Player *player, bool do_override,
4685 SendOverrideDayNightRatio(player->peer_id, do_override, ratio);
4689 void Server::notifyPlayers(const std::wstring &msg)
4691 SendChatMessage(PEER_ID_INEXISTENT,msg);
4694 void Server::spawnParticle(const char *playername, v3f pos,
4695 v3f velocity, v3f acceleration,
4696 float expirationtime, float size, bool
4697 collisiondetection, bool vertical, std::string texture)
4699 Player *player = m_env->getPlayer(playername);
4702 SendSpawnParticle(player->peer_id, pos, velocity, acceleration,
4703 expirationtime, size, collisiondetection, vertical, texture);
4706 void Server::spawnParticleAll(v3f pos, v3f velocity, v3f acceleration,
4707 float expirationtime, float size,
4708 bool collisiondetection, bool vertical, std::string texture)
4710 SendSpawnParticle(PEER_ID_INEXISTENT,pos, velocity, acceleration,
4711 expirationtime, size, collisiondetection, vertical, texture);
4714 u32 Server::addParticleSpawner(const char *playername,
4715 u16 amount, float spawntime,
4716 v3f minpos, v3f maxpos,
4717 v3f minvel, v3f maxvel,
4718 v3f minacc, v3f maxacc,
4719 float minexptime, float maxexptime,
4720 float minsize, float maxsize,
4721 bool collisiondetection, bool vertical, std::string texture)
4723 Player *player = m_env->getPlayer(playername);
4728 for(;;) // look for unused particlespawner id
4731 if (std::find(m_particlespawner_ids.begin(),
4732 m_particlespawner_ids.end(), id)
4733 == m_particlespawner_ids.end())
4735 m_particlespawner_ids.push_back(id);
4740 SendAddParticleSpawner(player->peer_id, amount, spawntime,
4741 minpos, maxpos, minvel, maxvel, minacc, maxacc,
4742 minexptime, maxexptime, minsize, maxsize,
4743 collisiondetection, vertical, texture, id);
4748 u32 Server::addParticleSpawnerAll(u16 amount, float spawntime,
4749 v3f minpos, v3f maxpos,
4750 v3f minvel, v3f maxvel,
4751 v3f minacc, v3f maxacc,
4752 float minexptime, float maxexptime,
4753 float minsize, float maxsize,
4754 bool collisiondetection, bool vertical, std::string texture)
4757 for(;;) // look for unused particlespawner id
4760 if (std::find(m_particlespawner_ids.begin(),
4761 m_particlespawner_ids.end(), id)
4762 == m_particlespawner_ids.end())
4764 m_particlespawner_ids.push_back(id);
4769 SendAddParticleSpawner(PEER_ID_INEXISTENT, amount, spawntime,
4770 minpos, maxpos, minvel, maxvel, minacc, maxacc,
4771 minexptime, maxexptime, minsize, maxsize,
4772 collisiondetection, vertical, texture, id);
4777 void Server::deleteParticleSpawner(const char *playername, u32 id)
4779 Player *player = m_env->getPlayer(playername);
4783 m_particlespawner_ids.erase(
4784 std::remove(m_particlespawner_ids.begin(),
4785 m_particlespawner_ids.end(), id),
4786 m_particlespawner_ids.end());
4787 SendDeleteParticleSpawner(player->peer_id, id);
4790 void Server::deleteParticleSpawnerAll(u32 id)
4792 m_particlespawner_ids.erase(
4793 std::remove(m_particlespawner_ids.begin(),
4794 m_particlespawner_ids.end(), id),
4795 m_particlespawner_ids.end());
4796 SendDeleteParticleSpawner(PEER_ID_INEXISTENT, id);
4799 Inventory* Server::createDetachedInventory(const std::string &name)
4801 if(m_detached_inventories.count(name) > 0){
4802 infostream<<"Server clearing detached inventory \""<<name<<"\""<<std::endl;
4803 delete m_detached_inventories[name];
4805 infostream<<"Server creating detached inventory \""<<name<<"\""<<std::endl;
4807 Inventory *inv = new Inventory(m_itemdef);
4809 m_detached_inventories[name] = inv;
4810 //TODO find a better way to do this
4811 sendDetachedInventory(name,PEER_ID_INEXISTENT);
4818 BoolScopeSet(bool *dst, bool val):
4821 m_orig_state = *m_dst;
4826 *m_dst = m_orig_state;
4833 // actions: time-reversed list
4834 // Return value: success/failure
4835 bool Server::rollbackRevertActions(const std::list<RollbackAction> &actions,
4836 std::list<std::string> *log)
4838 infostream<<"Server::rollbackRevertActions(len="<<actions.size()<<")"<<std::endl;
4839 ServerMap *map = (ServerMap*)(&m_env->getMap());
4840 // Disable rollback report sink while reverting
4841 BoolScopeSet rollback_scope_disable(&m_rollback_sink_enabled, false);
4843 // Fail if no actions to handle
4844 if(actions.empty()){
4845 log->push_back("Nothing to do.");
4852 for(std::list<RollbackAction>::const_iterator
4853 i = actions.begin();
4854 i != actions.end(); i++)
4856 const RollbackAction &action = *i;
4858 bool success = action.applyRevert(map, this, this);
4861 std::ostringstream os;
4862 os<<"Revert of step ("<<num_tried<<") "<<action.toString()<<" failed";
4863 infostream<<"Map::rollbackRevertActions(): "<<os.str()<<std::endl;
4865 log->push_back(os.str());
4867 std::ostringstream os;
4868 os<<"Successfully reverted step ("<<num_tried<<") "<<action.toString();
4869 infostream<<"Map::rollbackRevertActions(): "<<os.str()<<std::endl;
4871 log->push_back(os.str());
4875 infostream<<"Map::rollbackRevertActions(): "<<num_failed<<"/"<<num_tried
4876 <<" failed"<<std::endl;
4878 // Call it done if less than half failed
4879 return num_failed <= num_tried/2;
4882 // IGameDef interface
4884 IItemDefManager* Server::getItemDefManager()
4888 INodeDefManager* Server::getNodeDefManager()
4892 ICraftDefManager* Server::getCraftDefManager()
4896 ITextureSource* Server::getTextureSource()
4900 IShaderSource* Server::getShaderSource()
4904 scene::ISceneManager* Server::getSceneManager()
4909 u16 Server::allocateUnknownNodeId(const std::string &name)
4911 return m_nodedef->allocateDummy(name);
4913 ISoundManager* Server::getSoundManager()
4915 return &dummySoundManager;
4917 MtEventManager* Server::getEventManager()
4921 IRollbackReportSink* Server::getRollbackReportSink()
4923 if(!m_enable_rollback_recording)
4925 if(!m_rollback_sink_enabled)
4930 IWritableItemDefManager* Server::getWritableItemDefManager()
4934 IWritableNodeDefManager* Server::getWritableNodeDefManager()
4938 IWritableCraftDefManager* Server::getWritableCraftDefManager()
4943 const ModSpec* Server::getModSpec(const std::string &modname)
4945 for(std::vector<ModSpec>::iterator i = m_mods.begin();
4946 i != m_mods.end(); i++){
4947 const ModSpec &mod = *i;
4948 if(mod.name == modname)
4953 void Server::getModNames(std::list<std::string> &modlist)
4955 for(std::vector<ModSpec>::iterator i = m_mods.begin(); i != m_mods.end(); i++)
4957 modlist.push_back(i->name);
4960 std::string Server::getBuiltinLuaPath()
4962 return porting::path_share + DIR_DELIM + "builtin";
4965 v3f findSpawnPos(ServerMap &map)
4967 //return v3f(50,50,50)*BS;
4972 nodepos = v2s16(0,0);
4977 s16 water_level = map.getWaterLevel();
4979 // Try to find a good place a few times
4980 for(s32 i=0; i<1000; i++)
4983 // We're going to try to throw the player to this position
4984 v2s16 nodepos2d = v2s16(
4985 -range + (myrand() % (range * 2)),
4986 -range + (myrand() % (range * 2)));
4988 // Get ground height at point
4989 s16 groundheight = map.findGroundLevel(nodepos2d);
4990 if (groundheight <= water_level) // Don't go underwater
4992 if (groundheight > water_level + 6) // Don't go to high places
4995 nodepos = v3s16(nodepos2d.X, groundheight, nodepos2d.Y);
4996 bool is_good = false;
4998 for (s32 i = 0; i < 10; i++) {
4999 v3s16 blockpos = getNodeBlockPos(nodepos);
5000 map.emergeBlock(blockpos, true);
5001 content_t c = map.getNodeNoEx(nodepos).getContent();
5002 if (c == CONTENT_AIR || c == CONTENT_IGNORE) {
5004 if (air_count >= 2){
5012 // Found a good place
5013 //infostream<<"Searched through "<<i<<" places."<<std::endl;
5019 return intToFloat(nodepos, BS);
5022 PlayerSAO* Server::emergePlayer(const char *name, u16 peer_id)
5024 RemotePlayer *player = NULL;
5025 bool newplayer = false;
5028 Try to get an existing player
5030 player = static_cast<RemotePlayer*>(m_env->getPlayer(name));
5032 // If player is already connected, cancel
5033 if(player != NULL && player->peer_id != 0)
5035 infostream<<"emergePlayer(): Player already connected"<<std::endl;
5040 If player with the wanted peer_id already exists, cancel.
5042 if(m_env->getPlayer(peer_id) != NULL)
5044 infostream<<"emergePlayer(): Player with wrong name but same"
5045 " peer_id already exists"<<std::endl;
5049 // Load player if it isn't already loaded
5051 player = static_cast<RemotePlayer*>(m_env->loadPlayer(name));
5054 // Create player if it doesn't exist
5057 player = new RemotePlayer(this, name);
5058 // Set player position
5059 infostream<<"Server: Finding spawn place for player \""
5060 <<name<<"\""<<std::endl;
5061 v3f pos = findSpawnPos(m_env->getServerMap());
5062 player->setPosition(pos);
5064 // Make sure the player is saved
5065 player->setModified(true);
5067 // Add player to environment
5068 m_env->addPlayer(player);
5071 // Create a new player active object
5072 PlayerSAO *playersao = new PlayerSAO(m_env, player, peer_id,
5073 getPlayerEffectivePrivs(player->getName()),
5076 /* Clean up old HUD elements from previous sessions */
5079 /* Add object to environment */
5080 m_env->addActiveObject(playersao);
5084 m_script->on_newplayer(playersao);
5090 void dedicated_server_loop(Server &server, bool &kill)
5092 DSTACK(__FUNCTION_NAME);
5094 verbosestream<<"dedicated_server_loop()"<<std::endl;
5096 IntervalLimiter m_profiler_interval;
5100 float steplen = g_settings->getFloat("dedicated_server_step");
5101 // This is kind of a hack but can be done like this
5102 // because server.step() is very light
5104 ScopeProfiler sp(g_profiler, "dedicated server sleep");
5105 sleep_ms((int)(steplen*1000.0));
5107 server.step(steplen);
5109 if(server.getShutdownRequested() || kill)
5111 infostream<<"Dedicated server quitting"<<std::endl;
5113 if(g_settings->getBool("server_announce") == true)
5114 ServerList::sendAnnounce("delete");
5122 float profiler_print_interval =
5123 g_settings->getFloat("profiler_print_interval");
5124 if(profiler_print_interval != 0)
5126 if(m_profiler_interval.step(steplen, profiler_print_interval))
5128 infostream<<"Profiler:"<<std::endl;
5129 g_profiler->print(infostream);
5130 g_profiler->clear();