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);
2428 n = m_env->getMap().getNodeNoEx(p_under, &pos_ok);
2430 n = m_env->getMap().getNodeNoEx(p_under, &pos_ok);
2433 infostream<<"Server: Not punching: Node not found."
2434 <<" Adding block to emerge queue."
2436 m_emerge->enqueueBlockEmerge(peer_id, getNodeBlockPos(p_above), false);
2439 if(n.getContent() != CONTENT_IGNORE)
2440 m_script->node_on_punch(p_under, n, playersao, pointed);
2442 playersao->noCheatDigStart(p_under);
2444 else if(pointed.type == POINTEDTHING_OBJECT)
2446 // Skip if object has been removed
2447 if(pointed_object->m_removed)
2450 actionstream<<player->getName()<<" punches object "
2451 <<pointed.object_id<<": "
2452 <<pointed_object->getDescription()<<std::endl;
2454 ItemStack punchitem = playersao->getWieldedItem();
2455 ToolCapabilities toolcap =
2456 punchitem.getToolCapabilities(m_itemdef);
2457 v3f dir = (pointed_object->getBasePosition() -
2458 (player->getPosition() + player->getEyeOffset())
2460 float time_from_last_punch =
2461 playersao->resetTimeFromLastPunch();
2462 pointed_object->punch(dir, &toolcap, playersao,
2463 time_from_last_punch);
2471 else if(action == 1)
2476 2: Digging completed
2478 else if(action == 2)
2480 // Only digging of nodes
2481 if(pointed.type == POINTEDTHING_NODE)
2484 MapNode n = m_env->getMap().getNodeNoEx(p_under, &pos_ok);
2486 infostream << "Server: Not finishing digging: Node not found."
2487 << " Adding block to emerge queue."
2489 m_emerge->enqueueBlockEmerge(peer_id, getNodeBlockPos(p_above), false);
2492 /* Cheat prevention */
2493 bool is_valid_dig = true;
2494 if(!isSingleplayer() && !g_settings->getBool("disable_anticheat"))
2496 v3s16 nocheat_p = playersao->getNoCheatDigPos();
2497 float nocheat_t = playersao->getNoCheatDigTime();
2498 playersao->noCheatDigEnd();
2499 // If player didn't start digging this, ignore dig
2500 if(nocheat_p != p_under){
2501 infostream<<"Server: NoCheat: "<<player->getName()
2502 <<" started digging "
2503 <<PP(nocheat_p)<<" and completed digging "
2504 <<PP(p_under)<<"; not digging."<<std::endl;
2505 is_valid_dig = false;
2507 m_script->on_cheat(playersao, "finished_unknown_dig");
2509 // Get player's wielded item
2510 ItemStack playeritem;
2511 InventoryList *mlist = playersao->getInventory()->getList("main");
2513 playeritem = mlist->getItem(playersao->getWieldIndex());
2514 ToolCapabilities playeritem_toolcap =
2515 playeritem.getToolCapabilities(m_itemdef);
2516 // Get diggability and expected digging time
2517 DigParams params = getDigParams(m_nodedef->get(n).groups,
2518 &playeritem_toolcap);
2519 // If can't dig, try hand
2520 if(!params.diggable){
2521 const ItemDefinition &hand = m_itemdef->get("");
2522 const ToolCapabilities *tp = hand.tool_capabilities;
2524 params = getDigParams(m_nodedef->get(n).groups, tp);
2526 // If can't dig, ignore dig
2527 if(!params.diggable){
2528 infostream<<"Server: NoCheat: "<<player->getName()
2529 <<" completed digging "<<PP(p_under)
2530 <<", which is not diggable with tool. not digging."
2532 is_valid_dig = false;
2534 m_script->on_cheat(playersao, "dug_unbreakable");
2536 // Check digging time
2537 // If already invalidated, we don't have to
2539 // Well not our problem then
2541 // Clean and long dig
2542 else if(params.time > 2.0 && nocheat_t * 1.2 > params.time){
2543 // All is good, but grab time from pool; don't care if
2544 // it's actually available
2545 playersao->getDigPool().grab(params.time);
2547 // Short or laggy dig
2548 // Try getting the time from pool
2549 else if(playersao->getDigPool().grab(params.time)){
2554 infostream<<"Server: NoCheat: "<<player->getName()
2555 <<" completed digging "<<PP(p_under)
2556 <<"too fast; not digging."<<std::endl;
2557 is_valid_dig = false;
2559 m_script->on_cheat(playersao, "dug_too_fast");
2563 /* Actually dig node */
2565 if(is_valid_dig && n.getContent() != CONTENT_IGNORE)
2566 m_script->node_on_dig(p_under, n, playersao);
2568 v3s16 blockpos = getNodeBlockPos(floatToInt(pointed_pos_under, BS));
2569 RemoteClient *client = getClient(peer_id);
2570 // Send unusual result (that is, node not being removed)
2571 if(m_env->getMap().getNodeNoEx(p_under).getContent() != CONTENT_AIR)
2573 // Re-send block to revert change on client-side
2574 client->SetBlockNotSent(blockpos);
2577 client->ResendBlockIfOnWire(blockpos);
2583 3: place block or right-click object
2585 else if(action == 3)
2587 ItemStack item = playersao->getWieldedItem();
2589 // Reset build time counter
2590 if(pointed.type == POINTEDTHING_NODE &&
2591 item.getDefinition(m_itemdef).type == ITEM_NODE)
2592 getClient(peer_id)->m_time_from_building = 0.0;
2594 if(pointed.type == POINTEDTHING_OBJECT)
2596 // Right click object
2598 // Skip if object has been removed
2599 if(pointed_object->m_removed)
2602 actionstream<<player->getName()<<" right-clicks object "
2603 <<pointed.object_id<<": "
2604 <<pointed_object->getDescription()<<std::endl;
2607 pointed_object->rightClick(playersao);
2609 else if(m_script->item_OnPlace(
2610 item, playersao, pointed))
2612 // Placement was handled in lua
2614 // Apply returned ItemStack
2615 playersao->setWieldedItem(item);
2618 // If item has node placement prediction, always send the
2619 // blocks to make sure the client knows what exactly happened
2620 RemoteClient *client = getClient(peer_id);
2621 v3s16 blockpos = getNodeBlockPos(floatToInt(pointed_pos_above, BS));
2622 v3s16 blockpos2 = getNodeBlockPos(floatToInt(pointed_pos_under, BS));
2623 if(item.getDefinition(m_itemdef).node_placement_prediction != "") {
2624 client->SetBlockNotSent(blockpos);
2625 if(blockpos2 != blockpos) {
2626 client->SetBlockNotSent(blockpos2);
2630 client->ResendBlockIfOnWire(blockpos);
2631 if(blockpos2 != blockpos) {
2632 client->ResendBlockIfOnWire(blockpos2);
2640 else if(action == 4)
2642 ItemStack item = playersao->getWieldedItem();
2644 actionstream<<player->getName()<<" uses "<<item.name
2645 <<", pointing at "<<pointed.dump()<<std::endl;
2647 if(m_script->item_OnUse(
2648 item, playersao, pointed))
2650 // Apply returned ItemStack
2651 playersao->setWieldedItem(item);
2658 Catch invalid actions
2662 infostream<<"WARNING: Server: Invalid action "
2663 <<action<<std::endl;
2666 else if(command == TOSERVER_REMOVED_SOUNDS)
2668 std::string datastring((char*)&data[2], datasize-2);
2669 std::istringstream is(datastring, std::ios_base::binary);
2671 int num = readU16(is);
2672 for(int k=0; k<num; k++){
2673 s32 id = readS32(is);
2674 std::map<s32, ServerPlayingSound>::iterator i =
2675 m_playing_sounds.find(id);
2676 if(i == m_playing_sounds.end())
2678 ServerPlayingSound &psound = i->second;
2679 psound.clients.erase(peer_id);
2680 if(psound.clients.size() == 0)
2681 m_playing_sounds.erase(i++);
2684 else if(command == TOSERVER_NODEMETA_FIELDS)
2686 std::string datastring((char*)&data[2], datasize-2);
2687 std::istringstream is(datastring, std::ios_base::binary);
2689 v3s16 p = readV3S16(is);
2690 std::string formname = deSerializeString(is);
2691 int num = readU16(is);
2692 std::map<std::string, std::string> fields;
2693 for(int k=0; k<num; k++){
2694 std::string fieldname = deSerializeString(is);
2695 std::string fieldvalue = deSerializeLongString(is);
2696 fields[fieldname] = fieldvalue;
2699 // If something goes wrong, this player is to blame
2700 RollbackScopeActor rollback_scope(m_rollback,
2701 std::string("player:")+player->getName());
2703 // Check the target node for rollback data; leave others unnoticed
2704 RollbackNode rn_old(&m_env->getMap(), p, this);
2706 m_script->node_on_receive_fields(p, formname, fields,playersao);
2708 // Report rollback data
2709 RollbackNode rn_new(&m_env->getMap(), p, this);
2710 if(rollback() && rn_new != rn_old){
2711 RollbackAction action;
2712 action.setSetNode(p, rn_old, rn_new);
2713 rollback()->reportAction(action);
2716 else if(command == TOSERVER_INVENTORY_FIELDS)
2718 std::string datastring((char*)&data[2], datasize-2);
2719 std::istringstream is(datastring, std::ios_base::binary);
2721 std::string formname = deSerializeString(is);
2722 int num = readU16(is);
2723 std::map<std::string, std::string> fields;
2724 for(int k=0; k<num; k++){
2725 std::string fieldname = deSerializeString(is);
2726 std::string fieldvalue = deSerializeLongString(is);
2727 fields[fieldname] = fieldvalue;
2730 m_script->on_playerReceiveFields(playersao, formname, fields);
2734 infostream<<"Server::ProcessData(): Ignoring "
2735 "unknown command "<<command<<std::endl;
2739 catch(SendFailedException &e)
2741 errorstream<<"Server::ProcessData(): SendFailedException: "
2747 void Server::setTimeOfDay(u32 time)
2749 m_env->setTimeOfDay(time);
2750 m_time_of_day_send_timer = 0;
2753 void Server::onMapEditEvent(MapEditEvent *event)
2755 //infostream<<"Server::onMapEditEvent()"<<std::endl;
2756 if(m_ignore_map_edit_events)
2758 if(m_ignore_map_edit_events_area.contains(event->getArea()))
2760 MapEditEvent *e = event->clone();
2761 m_unsent_map_edit_queue.push_back(e);
2764 Inventory* Server::getInventory(const InventoryLocation &loc)
2767 case InventoryLocation::UNDEFINED:
2770 case InventoryLocation::CURRENT_PLAYER:
2773 case InventoryLocation::PLAYER:
2775 Player *player = m_env->getPlayer(loc.name.c_str());
2778 PlayerSAO *playersao = player->getPlayerSAO();
2781 return playersao->getInventory();
2784 case InventoryLocation::NODEMETA:
2786 NodeMetadata *meta = m_env->getMap().getNodeMetadata(loc.p);
2789 return meta->getInventory();
2792 case InventoryLocation::DETACHED:
2794 if(m_detached_inventories.count(loc.name) == 0)
2796 return m_detached_inventories[loc.name];
2804 void Server::setInventoryModified(const InventoryLocation &loc)
2807 case InventoryLocation::UNDEFINED:
2810 case InventoryLocation::PLAYER:
2812 Player *player = m_env->getPlayer(loc.name.c_str());
2815 PlayerSAO *playersao = player->getPlayerSAO();
2818 playersao->m_inventory_not_sent = true;
2819 playersao->m_wielded_item_not_sent = true;
2822 case InventoryLocation::NODEMETA:
2824 v3s16 blockpos = getNodeBlockPos(loc.p);
2826 MapBlock *block = m_env->getMap().getBlockNoCreateNoEx(blockpos);
2828 block->raiseModified(MOD_STATE_WRITE_NEEDED);
2830 setBlockNotSent(blockpos);
2833 case InventoryLocation::DETACHED:
2835 sendDetachedInventory(loc.name,PEER_ID_INEXISTENT);
2843 void Server::SetBlocksNotSent(std::map<v3s16, MapBlock *>& block)
2845 std::list<u16> clients = m_clients.getClientIDs();
2847 // Set the modified blocks unsent for all the clients
2848 for (std::list<u16>::iterator
2849 i = clients.begin();
2850 i != clients.end(); ++i) {
2851 RemoteClient *client = m_clients.lockedGetClientNoEx(*i);
2853 client->SetBlocksNotSent(block);
2858 void Server::peerAdded(con::Peer *peer)
2860 DSTACK(__FUNCTION_NAME);
2861 verbosestream<<"Server::peerAdded(): peer->id="
2862 <<peer->id<<std::endl;
2865 c.type = con::PEER_ADDED;
2866 c.peer_id = peer->id;
2868 m_peer_change_queue.push_back(c);
2871 void Server::deletingPeer(con::Peer *peer, bool timeout)
2873 DSTACK(__FUNCTION_NAME);
2874 verbosestream<<"Server::deletingPeer(): peer->id="
2875 <<peer->id<<", timeout="<<timeout<<std::endl;
2877 m_clients.event(peer->id, CSE_Disconnect);
2879 c.type = con::PEER_REMOVED;
2880 c.peer_id = peer->id;
2881 c.timeout = timeout;
2882 m_peer_change_queue.push_back(c);
2885 bool Server::getClientConInfo(u16 peer_id, con::rtt_stat_type type, float* retval)
2887 *retval = m_con.getPeerStat(peer_id,type);
2888 if (*retval == -1) return false;
2892 bool Server::getClientInfo(
2901 std::string* vers_string
2904 *state = m_clients.getClientState(peer_id);
2906 RemoteClient* client = m_clients.lockedGetClientNoEx(peer_id, CS_Invalid);
2908 if (client == NULL) {
2913 *uptime = client->uptime();
2914 *ser_vers = client->serialization_version;
2915 *prot_vers = client->net_proto_version;
2917 *major = client->getMajor();
2918 *minor = client->getMinor();
2919 *patch = client->getPatch();
2920 *vers_string = client->getPatch();
2927 void Server::handlePeerChanges()
2929 while(m_peer_change_queue.size() > 0)
2931 con::PeerChange c = m_peer_change_queue.pop_front();
2933 verbosestream<<"Server: Handling peer change: "
2934 <<"id="<<c.peer_id<<", timeout="<<c.timeout
2939 case con::PEER_ADDED:
2940 m_clients.CreateClient(c.peer_id);
2943 case con::PEER_REMOVED:
2944 DeleteClient(c.peer_id, c.timeout?CDR_TIMEOUT:CDR_LEAVE);
2948 assert("Invalid peer change event received!" == 0);
2954 void Server::SendMovement(u16 peer_id)
2956 DSTACK(__FUNCTION_NAME);
2957 std::ostringstream os(std::ios_base::binary);
2959 writeU16(os, TOCLIENT_MOVEMENT);
2960 writeF1000(os, g_settings->getFloat("movement_acceleration_default"));
2961 writeF1000(os, g_settings->getFloat("movement_acceleration_air"));
2962 writeF1000(os, g_settings->getFloat("movement_acceleration_fast"));
2963 writeF1000(os, g_settings->getFloat("movement_speed_walk"));
2964 writeF1000(os, g_settings->getFloat("movement_speed_crouch"));
2965 writeF1000(os, g_settings->getFloat("movement_speed_fast"));
2966 writeF1000(os, g_settings->getFloat("movement_speed_climb"));
2967 writeF1000(os, g_settings->getFloat("movement_speed_jump"));
2968 writeF1000(os, g_settings->getFloat("movement_liquid_fluidity"));
2969 writeF1000(os, g_settings->getFloat("movement_liquid_fluidity_smooth"));
2970 writeF1000(os, g_settings->getFloat("movement_liquid_sink"));
2971 writeF1000(os, g_settings->getFloat("movement_gravity"));
2974 std::string s = os.str();
2975 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
2977 m_clients.send(peer_id, 0, data, true);
2980 void Server::SendHP(u16 peer_id, u8 hp)
2982 DSTACK(__FUNCTION_NAME);
2983 std::ostringstream os(std::ios_base::binary);
2985 writeU16(os, TOCLIENT_HP);
2989 std::string s = os.str();
2990 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
2992 m_clients.send(peer_id, 0, data, true);
2995 void Server::SendBreath(u16 peer_id, u16 breath)
2997 DSTACK(__FUNCTION_NAME);
2998 std::ostringstream os(std::ios_base::binary);
3000 writeU16(os, TOCLIENT_BREATH);
3001 writeU16(os, breath);
3004 std::string s = os.str();
3005 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3007 m_clients.send(peer_id, 0, data, true);
3010 void Server::SendAccessDenied(u16 peer_id,const std::wstring &reason)
3012 DSTACK(__FUNCTION_NAME);
3013 std::ostringstream os(std::ios_base::binary);
3015 writeU16(os, TOCLIENT_ACCESS_DENIED);
3016 os<<serializeWideString(reason);
3019 std::string s = os.str();
3020 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3022 m_clients.send(peer_id, 0, data, true);
3025 void Server::SendDeathscreen(u16 peer_id,bool set_camera_point_target,
3026 v3f camera_point_target)
3028 DSTACK(__FUNCTION_NAME);
3029 std::ostringstream os(std::ios_base::binary);
3031 writeU16(os, TOCLIENT_DEATHSCREEN);
3032 writeU8(os, set_camera_point_target);
3033 writeV3F1000(os, camera_point_target);
3036 std::string s = os.str();
3037 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3039 m_clients.send(peer_id, 0, data, true);
3042 void Server::SendItemDef(u16 peer_id,
3043 IItemDefManager *itemdef, u16 protocol_version)
3045 DSTACK(__FUNCTION_NAME);
3046 std::ostringstream os(std::ios_base::binary);
3050 u32 length of the next item
3051 zlib-compressed serialized ItemDefManager
3053 writeU16(os, TOCLIENT_ITEMDEF);
3054 std::ostringstream tmp_os(std::ios::binary);
3055 itemdef->serialize(tmp_os, protocol_version);
3056 std::ostringstream tmp_os2(std::ios::binary);
3057 compressZlib(tmp_os.str(), tmp_os2);
3058 os<<serializeLongString(tmp_os2.str());
3061 std::string s = os.str();
3062 verbosestream<<"Server: Sending item definitions to id("<<peer_id
3063 <<"): size="<<s.size()<<std::endl;
3064 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3066 m_clients.send(peer_id, 0, data, true);
3069 void Server::SendNodeDef(u16 peer_id,
3070 INodeDefManager *nodedef, u16 protocol_version)
3072 DSTACK(__FUNCTION_NAME);
3073 std::ostringstream os(std::ios_base::binary);
3077 u32 length of the next item
3078 zlib-compressed serialized NodeDefManager
3080 writeU16(os, TOCLIENT_NODEDEF);
3081 std::ostringstream tmp_os(std::ios::binary);
3082 nodedef->serialize(tmp_os, protocol_version);
3083 std::ostringstream tmp_os2(std::ios::binary);
3084 compressZlib(tmp_os.str(), tmp_os2);
3085 os<<serializeLongString(tmp_os2.str());
3088 std::string s = os.str();
3089 verbosestream<<"Server: Sending node definitions to id("<<peer_id
3090 <<"): size="<<s.size()<<std::endl;
3091 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3093 m_clients.send(peer_id, 0, data, true);
3097 Non-static send methods
3100 void Server::SendInventory(u16 peer_id)
3102 DSTACK(__FUNCTION_NAME);
3104 PlayerSAO *playersao = getPlayerSAO(peer_id);
3107 playersao->m_inventory_not_sent = false;
3113 std::ostringstream os;
3114 playersao->getInventory()->serialize(os);
3116 std::string s = os.str();
3118 SharedBuffer<u8> data(s.size()+2);
3119 writeU16(&data[0], TOCLIENT_INVENTORY);
3120 memcpy(&data[2], s.c_str(), s.size());
3123 m_clients.send(peer_id, 0, data, true);
3126 void Server::SendChatMessage(u16 peer_id, const std::wstring &message)
3128 DSTACK(__FUNCTION_NAME);
3130 std::ostringstream os(std::ios_base::binary);
3134 writeU16(buf, TOCLIENT_CHAT_MESSAGE);
3135 os.write((char*)buf, 2);
3138 writeU16(buf, message.size());
3139 os.write((char*)buf, 2);
3142 for(u32 i=0; i<message.size(); i++)
3146 os.write((char*)buf, 2);
3150 std::string s = os.str();
3151 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3153 if (peer_id != PEER_ID_INEXISTENT)
3156 m_clients.send(peer_id, 0, data, true);
3160 m_clients.sendToAll(0,data,true);
3164 void Server::SendShowFormspecMessage(u16 peer_id, const std::string &formspec,
3165 const std::string &formname)
3167 DSTACK(__FUNCTION_NAME);
3169 std::ostringstream os(std::ios_base::binary);
3174 writeU16(buf, TOCLIENT_SHOW_FORMSPEC);
3175 os.write((char*)buf, 2);
3176 os<<serializeLongString(FORMSPEC_VERSION_STRING + formspec);
3177 os<<serializeString(formname);
3180 std::string s = os.str();
3181 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3183 m_clients.send(peer_id, 0, data, true);
3186 // Spawns a particle on peer with peer_id
3187 void Server::SendSpawnParticle(u16 peer_id, v3f pos, v3f velocity, v3f acceleration,
3188 float expirationtime, float size, bool collisiondetection,
3189 bool vertical, std::string texture)
3191 DSTACK(__FUNCTION_NAME);
3193 std::ostringstream os(std::ios_base::binary);
3194 writeU16(os, TOCLIENT_SPAWN_PARTICLE);
3195 writeV3F1000(os, pos);
3196 writeV3F1000(os, velocity);
3197 writeV3F1000(os, acceleration);
3198 writeF1000(os, expirationtime);
3199 writeF1000(os, size);
3200 writeU8(os, collisiondetection);
3201 os<<serializeLongString(texture);
3202 writeU8(os, vertical);
3205 std::string s = os.str();
3206 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3208 if (peer_id != PEER_ID_INEXISTENT)
3211 m_clients.send(peer_id, 0, data, true);
3215 m_clients.sendToAll(0,data,true);
3219 // Adds a ParticleSpawner on peer with peer_id
3220 void Server::SendAddParticleSpawner(u16 peer_id, u16 amount, float spawntime, v3f minpos, v3f maxpos,
3221 v3f minvel, v3f maxvel, v3f minacc, v3f maxacc, float minexptime, float maxexptime,
3222 float minsize, float maxsize, bool collisiondetection, bool vertical, std::string texture, u32 id)
3224 DSTACK(__FUNCTION_NAME);
3226 std::ostringstream os(std::ios_base::binary);
3227 writeU16(os, TOCLIENT_ADD_PARTICLESPAWNER);
3229 writeU16(os, amount);
3230 writeF1000(os, spawntime);
3231 writeV3F1000(os, minpos);
3232 writeV3F1000(os, maxpos);
3233 writeV3F1000(os, minvel);
3234 writeV3F1000(os, maxvel);
3235 writeV3F1000(os, minacc);
3236 writeV3F1000(os, maxacc);
3237 writeF1000(os, minexptime);
3238 writeF1000(os, maxexptime);
3239 writeF1000(os, minsize);
3240 writeF1000(os, maxsize);
3241 writeU8(os, collisiondetection);
3242 os<<serializeLongString(texture);
3244 writeU8(os, vertical);
3247 std::string s = os.str();
3248 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3250 if (peer_id != PEER_ID_INEXISTENT)
3253 m_clients.send(peer_id, 0, data, true);
3256 m_clients.sendToAll(0,data,true);
3260 void Server::SendDeleteParticleSpawner(u16 peer_id, u32 id)
3262 DSTACK(__FUNCTION_NAME);
3264 std::ostringstream os(std::ios_base::binary);
3265 writeU16(os, TOCLIENT_DELETE_PARTICLESPAWNER);
3270 std::string s = os.str();
3271 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3273 if (peer_id != PEER_ID_INEXISTENT) {
3275 m_clients.send(peer_id, 0, data, true);
3278 m_clients.sendToAll(0,data,true);
3283 void Server::SendHUDAdd(u16 peer_id, u32 id, HudElement *form)
3285 std::ostringstream os(std::ios_base::binary);
3288 writeU16(os, TOCLIENT_HUDADD);
3290 writeU8(os, (u8)form->type);
3291 writeV2F1000(os, form->pos);
3292 os << serializeString(form->name);
3293 writeV2F1000(os, form->scale);
3294 os << serializeString(form->text);
3295 writeU32(os, form->number);
3296 writeU32(os, form->item);
3297 writeU32(os, form->dir);
3298 writeV2F1000(os, form->align);
3299 writeV2F1000(os, form->offset);
3300 writeV3F1000(os, form->world_pos);
3301 writeV2S32(os,form->size);
3304 std::string s = os.str();
3305 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3307 m_clients.send(peer_id, 1, data, true);
3310 void Server::SendHUDRemove(u16 peer_id, u32 id)
3312 std::ostringstream os(std::ios_base::binary);
3315 writeU16(os, TOCLIENT_HUDRM);
3319 std::string s = os.str();
3320 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3323 m_clients.send(peer_id, 1, data, true);
3326 void Server::SendHUDChange(u16 peer_id, u32 id, HudElementStat stat, void *value)
3328 std::ostringstream os(std::ios_base::binary);
3331 writeU16(os, TOCLIENT_HUDCHANGE);
3333 writeU8(os, (u8)stat);
3336 case HUD_STAT_SCALE:
3337 case HUD_STAT_ALIGN:
3338 case HUD_STAT_OFFSET:
3339 writeV2F1000(os, *(v2f *)value);
3343 os << serializeString(*(std::string *)value);
3345 case HUD_STAT_WORLD_POS:
3346 writeV3F1000(os, *(v3f *)value);
3349 writeV2S32(os,*(v2s32 *)value);
3351 case HUD_STAT_NUMBER:
3355 writeU32(os, *(u32 *)value);
3360 std::string s = os.str();
3361 SharedBuffer<u8> data((u8 *)s.c_str(), s.size());
3363 m_clients.send(peer_id, 0, data, true);
3366 void Server::SendHUDSetFlags(u16 peer_id, u32 flags, u32 mask)
3368 std::ostringstream os(std::ios_base::binary);
3371 writeU16(os, TOCLIENT_HUD_SET_FLAGS);
3373 //////////////////////////// compatibility code to be removed //////////////
3374 flags &= ~(HUD_FLAG_HEALTHBAR_VISIBLE | HUD_FLAG_BREATHBAR_VISIBLE);
3375 ////////////////////////////////////////////////////////////////////////////
3376 writeU32(os, flags);
3380 std::string s = os.str();
3381 SharedBuffer<u8> data((u8 *)s.c_str(), s.size());
3383 m_clients.send(peer_id, 0, data, true);
3386 void Server::SendHUDSetParam(u16 peer_id, u16 param, const std::string &value)
3388 std::ostringstream os(std::ios_base::binary);
3391 writeU16(os, TOCLIENT_HUD_SET_PARAM);
3392 writeU16(os, param);
3393 os<<serializeString(value);
3396 std::string s = os.str();
3397 SharedBuffer<u8> data((u8 *)s.c_str(), s.size());
3399 m_clients.send(peer_id, 0, data, true);
3402 void Server::SendSetSky(u16 peer_id, const video::SColor &bgcolor,
3403 const std::string &type, const std::vector<std::string> ¶ms)
3405 std::ostringstream os(std::ios_base::binary);
3408 writeU16(os, TOCLIENT_SET_SKY);
3409 writeARGB8(os, bgcolor);
3410 os<<serializeString(type);
3411 writeU16(os, params.size());
3412 for(size_t i=0; i<params.size(); i++)
3413 os<<serializeString(params[i]);
3416 std::string s = os.str();
3417 SharedBuffer<u8> data((u8 *)s.c_str(), s.size());
3419 m_clients.send(peer_id, 0, data, true);
3422 void Server::SendOverrideDayNightRatio(u16 peer_id, bool do_override,
3425 std::ostringstream os(std::ios_base::binary);
3428 writeU16(os, TOCLIENT_OVERRIDE_DAY_NIGHT_RATIO);
3429 writeU8(os, do_override);
3430 writeU16(os, ratio*65535);
3433 std::string s = os.str();
3434 SharedBuffer<u8> data((u8 *)s.c_str(), s.size());
3436 m_clients.send(peer_id, 0, data, true);
3439 void Server::SendTimeOfDay(u16 peer_id, u16 time, f32 time_speed)
3441 DSTACK(__FUNCTION_NAME);
3444 SharedBuffer<u8> data(2+2+4);
3445 writeU16(&data[0], TOCLIENT_TIME_OF_DAY);
3446 writeU16(&data[2], time);
3447 writeF1000(&data[4], time_speed);
3449 if (peer_id == PEER_ID_INEXISTENT) {
3450 m_clients.sendToAll(0,data,true);
3454 m_clients.send(peer_id, 0, data, true);
3458 void Server::SendPlayerHP(u16 peer_id)
3460 DSTACK(__FUNCTION_NAME);
3461 PlayerSAO *playersao = getPlayerSAO(peer_id);
3463 playersao->m_hp_not_sent = false;
3464 SendHP(peer_id, playersao->getHP());
3465 m_script->player_event(playersao,"health_changed");
3467 // Send to other clients
3468 std::string str = gob_cmd_punched(playersao->readDamage(), playersao->getHP());
3469 ActiveObjectMessage aom(playersao->getId(), true, str);
3470 playersao->m_messages_out.push_back(aom);
3473 void Server::SendPlayerBreath(u16 peer_id)
3475 DSTACK(__FUNCTION_NAME);
3476 PlayerSAO *playersao = getPlayerSAO(peer_id);
3478 playersao->m_breath_not_sent = false;
3479 m_script->player_event(playersao,"breath_changed");
3480 SendBreath(peer_id, playersao->getBreath());
3483 void Server::SendMovePlayer(u16 peer_id)
3485 DSTACK(__FUNCTION_NAME);
3486 Player *player = m_env->getPlayer(peer_id);
3489 std::ostringstream os(std::ios_base::binary);
3490 writeU16(os, TOCLIENT_MOVE_PLAYER);
3491 writeV3F1000(os, player->getPosition());
3492 writeF1000(os, player->getPitch());
3493 writeF1000(os, player->getYaw());
3496 v3f pos = player->getPosition();
3497 f32 pitch = player->getPitch();
3498 f32 yaw = player->getYaw();
3499 verbosestream<<"Server: Sending TOCLIENT_MOVE_PLAYER"
3500 <<" pos=("<<pos.X<<","<<pos.Y<<","<<pos.Z<<")"
3507 std::string s = os.str();
3508 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3510 m_clients.send(peer_id, 0, data, true);
3513 void Server::SendLocalPlayerAnimations(u16 peer_id, v2s32 animation_frames[4], f32 animation_speed)
3515 std::ostringstream os(std::ios_base::binary);
3517 writeU16(os, TOCLIENT_LOCAL_PLAYER_ANIMATIONS);
3518 writeV2S32(os, animation_frames[0]);
3519 writeV2S32(os, animation_frames[1]);
3520 writeV2S32(os, animation_frames[2]);
3521 writeV2S32(os, animation_frames[3]);
3522 writeF1000(os, animation_speed);
3525 std::string s = os.str();
3526 SharedBuffer<u8> data((u8 *)s.c_str(), s.size());
3528 m_clients.send(peer_id, 0, data, true);
3531 void Server::SendEyeOffset(u16 peer_id, v3f first, v3f third)
3533 std::ostringstream os(std::ios_base::binary);
3535 writeU16(os, TOCLIENT_EYE_OFFSET);
3536 writeV3F1000(os, first);
3537 writeV3F1000(os, third);
3540 std::string s = os.str();
3541 SharedBuffer<u8> data((u8 *)s.c_str(), s.size());
3543 m_clients.send(peer_id, 0, data, true);
3545 void Server::SendPlayerPrivileges(u16 peer_id)
3547 Player *player = m_env->getPlayer(peer_id);
3549 if(player->peer_id == PEER_ID_INEXISTENT)
3552 std::set<std::string> privs;
3553 m_script->getAuth(player->getName(), NULL, &privs);
3555 std::ostringstream os(std::ios_base::binary);
3556 writeU16(os, TOCLIENT_PRIVILEGES);
3557 writeU16(os, privs.size());
3558 for(std::set<std::string>::const_iterator i = privs.begin();
3559 i != privs.end(); i++){
3560 os<<serializeString(*i);
3564 std::string s = os.str();
3565 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3567 m_clients.send(peer_id, 0, data, true);
3570 void Server::SendPlayerInventoryFormspec(u16 peer_id)
3572 Player *player = m_env->getPlayer(peer_id);
3574 if(player->peer_id == PEER_ID_INEXISTENT)
3577 std::ostringstream os(std::ios_base::binary);
3578 writeU16(os, TOCLIENT_INVENTORY_FORMSPEC);
3579 os<<serializeLongString(FORMSPEC_VERSION_STRING + player->inventory_formspec);
3582 std::string s = os.str();
3583 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3585 m_clients.send(peer_id, 0, data, true);
3588 s32 Server::playSound(const SimpleSoundSpec &spec,
3589 const ServerSoundParams ¶ms)
3591 // Find out initial position of sound
3592 bool pos_exists = false;
3593 v3f pos = params.getPos(m_env, &pos_exists);
3594 // If position is not found while it should be, cancel sound
3595 if(pos_exists != (params.type != ServerSoundParams::SSP_LOCAL))
3598 // Filter destination clients
3599 std::list<u16> dst_clients;
3600 if(params.to_player != "")
3602 Player *player = m_env->getPlayer(params.to_player.c_str());
3604 infostream<<"Server::playSound: Player \""<<params.to_player
3605 <<"\" not found"<<std::endl;
3608 if(player->peer_id == PEER_ID_INEXISTENT){
3609 infostream<<"Server::playSound: Player \""<<params.to_player
3610 <<"\" not connected"<<std::endl;
3613 dst_clients.push_back(player->peer_id);
3617 std::list<u16> clients = m_clients.getClientIDs();
3619 for(std::list<u16>::iterator
3620 i = clients.begin(); i != clients.end(); ++i)
3622 Player *player = m_env->getPlayer(*i);
3626 if(player->getPosition().getDistanceFrom(pos) >
3627 params.max_hear_distance)
3630 dst_clients.push_back(*i);
3633 if(dst_clients.size() == 0)
3637 s32 id = m_next_sound_id++;
3638 // The sound will exist as a reference in m_playing_sounds
3639 m_playing_sounds[id] = ServerPlayingSound();
3640 ServerPlayingSound &psound = m_playing_sounds[id];
3641 psound.params = params;
3642 for(std::list<u16>::iterator i = dst_clients.begin();
3643 i != dst_clients.end(); i++)
3644 psound.clients.insert(*i);
3646 std::ostringstream os(std::ios_base::binary);
3647 writeU16(os, TOCLIENT_PLAY_SOUND);
3649 os<<serializeString(spec.name);
3650 writeF1000(os, spec.gain * params.gain);
3651 writeU8(os, params.type);
3652 writeV3F1000(os, pos);
3653 writeU16(os, params.object);
3654 writeU8(os, params.loop);
3656 std::string s = os.str();
3657 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3659 for(std::list<u16>::iterator i = dst_clients.begin();
3660 i != dst_clients.end(); i++){
3662 m_clients.send(*i, 0, data, true);
3666 void Server::stopSound(s32 handle)
3668 // Get sound reference
3669 std::map<s32, ServerPlayingSound>::iterator i =
3670 m_playing_sounds.find(handle);
3671 if(i == m_playing_sounds.end())
3673 ServerPlayingSound &psound = i->second;
3675 std::ostringstream os(std::ios_base::binary);
3676 writeU16(os, TOCLIENT_STOP_SOUND);
3677 writeS32(os, handle);
3679 std::string s = os.str();
3680 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3682 for(std::set<u16>::iterator i = psound.clients.begin();
3683 i != psound.clients.end(); i++){
3685 m_clients.send(*i, 0, data, true);
3687 // Remove sound reference
3688 m_playing_sounds.erase(i);
3691 void Server::sendRemoveNode(v3s16 p, u16 ignore_id,
3692 std::list<u16> *far_players, float far_d_nodes)
3694 float maxd = far_d_nodes*BS;
3695 v3f p_f = intToFloat(p, BS);
3699 SharedBuffer<u8> reply(replysize);
3700 writeU16(&reply[0], TOCLIENT_REMOVENODE);
3701 writeS16(&reply[2], p.X);
3702 writeS16(&reply[4], p.Y);
3703 writeS16(&reply[6], p.Z);
3705 std::list<u16> clients = m_clients.getClientIDs();
3706 for(std::list<u16>::iterator
3707 i = clients.begin();
3708 i != clients.end(); ++i)
3713 Player *player = m_env->getPlayer(*i);
3716 // If player is far away, only set modified blocks not sent
3717 v3f player_pos = player->getPosition();
3718 if(player_pos.getDistanceFrom(p_f) > maxd)
3720 far_players->push_back(*i);
3727 m_clients.send(*i, 0, reply, true);
3731 void Server::sendAddNode(v3s16 p, MapNode n, u16 ignore_id,
3732 std::list<u16> *far_players, float far_d_nodes,
3733 bool remove_metadata)
3735 float maxd = far_d_nodes*BS;
3736 v3f p_f = intToFloat(p, BS);
3738 std::list<u16> clients = m_clients.getClientIDs();
3739 for(std::list<u16>::iterator
3740 i = clients.begin();
3741 i != clients.end(); ++i)
3747 Player *player = m_env->getPlayer(*i);
3750 // If player is far away, only set modified blocks not sent
3751 v3f player_pos = player->getPosition();
3752 if(player_pos.getDistanceFrom(p_f) > maxd)
3754 far_players->push_back(*i);
3759 SharedBuffer<u8> reply(0);
3761 RemoteClient* client = m_clients.lockedGetClientNoEx(*i);
3765 u32 replysize = 9 + MapNode::serializedLength(client->serialization_version);
3766 reply = SharedBuffer<u8>(replysize);
3767 writeU16(&reply[0], TOCLIENT_ADDNODE);
3768 writeS16(&reply[2], p.X);
3769 writeS16(&reply[4], p.Y);
3770 writeS16(&reply[6], p.Z);
3771 n.serialize(&reply[8], client->serialization_version);
3772 u32 index = 8 + MapNode::serializedLength(client->serialization_version);
3773 writeU8(&reply[index], remove_metadata ? 0 : 1);
3775 if (!remove_metadata) {
3776 if (client->net_proto_version <= 21) {
3777 // Old clients always clear metadata; fix it
3778 // by sending the full block again.
3779 client->SetBlockNotSent(p);
3786 if (reply.getSize() > 0)
3787 m_clients.send(*i, 0, reply, true);
3791 void Server::setBlockNotSent(v3s16 p)
3793 std::list<u16> clients = m_clients.getClientIDs();
3795 for(std::list<u16>::iterator
3796 i = clients.begin();
3797 i != clients.end(); ++i)
3799 RemoteClient *client = m_clients.lockedGetClientNoEx(*i);
3800 client->SetBlockNotSent(p);
3805 void Server::SendBlockNoLock(u16 peer_id, MapBlock *block, u8 ver, u16 net_proto_version)
3807 DSTACK(__FUNCTION_NAME);
3809 v3s16 p = block->getPos();
3813 bool completely_air = true;
3814 for(s16 z0=0; z0<MAP_BLOCKSIZE; z0++)
3815 for(s16 x0=0; x0<MAP_BLOCKSIZE; x0++)
3816 for(s16 y0=0; y0<MAP_BLOCKSIZE; y0++)
3818 if(block->getNodeNoEx(v3s16(x0,y0,z0)).d != CONTENT_AIR)
3820 completely_air = false;
3821 x0 = y0 = z0 = MAP_BLOCKSIZE; // Break out
3826 infostream<<"Server: Sending block ("<<p.X<<","<<p.Y<<","<<p.Z<<"): ";
3828 infostream<<"[completely air] ";
3829 infostream<<std::endl;
3833 Create a packet with the block in the right format
3836 std::ostringstream os(std::ios_base::binary);
3837 block->serialize(os, ver, false);
3838 block->serializeNetworkSpecific(os, net_proto_version);
3839 std::string s = os.str();
3840 SharedBuffer<u8> blockdata((u8*)s.c_str(), s.size());
3842 u32 replysize = 8 + blockdata.getSize();
3843 SharedBuffer<u8> reply(replysize);
3844 writeU16(&reply[0], TOCLIENT_BLOCKDATA);
3845 writeS16(&reply[2], p.X);
3846 writeS16(&reply[4], p.Y);
3847 writeS16(&reply[6], p.Z);
3848 memcpy(&reply[8], *blockdata, blockdata.getSize());
3850 /*infostream<<"Server: Sending block ("<<p.X<<","<<p.Y<<","<<p.Z<<")"
3851 <<": \tpacket size: "<<replysize<<std::endl;*/
3856 m_clients.send(peer_id, 2, reply, true);
3859 void Server::SendBlocks(float dtime)
3861 DSTACK(__FUNCTION_NAME);
3863 JMutexAutoLock envlock(m_env_mutex);
3864 //TODO check if one big lock could be faster then multiple small ones
3866 ScopeProfiler sp(g_profiler, "Server: sel and send blocks to clients");
3868 std::vector<PrioritySortedBlockTransfer> queue;
3870 s32 total_sending = 0;
3873 ScopeProfiler sp(g_profiler, "Server: selecting blocks for sending");
3875 std::list<u16> clients = m_clients.getClientIDs();
3878 for(std::list<u16>::iterator
3879 i = clients.begin();
3880 i != clients.end(); ++i)
3882 RemoteClient *client = m_clients.lockedGetClientNoEx(*i, CS_Active);
3887 total_sending += client->SendingCount();
3888 client->GetNextBlocks(m_env,m_emerge, dtime, queue);
3894 // Lowest priority number comes first.
3895 // Lowest is most important.
3896 std::sort(queue.begin(), queue.end());
3899 for(u32 i=0; i<queue.size(); i++)
3901 //TODO: Calculate limit dynamically
3902 if(total_sending >= g_settings->getS32
3903 ("max_simultaneous_block_sends_server_total"))
3906 PrioritySortedBlockTransfer q = queue[i];
3908 MapBlock *block = NULL;
3911 block = m_env->getMap().getBlockNoCreate(q.pos);
3913 catch(InvalidPositionException &e)
3918 RemoteClient *client = m_clients.lockedGetClientNoEx(q.peer_id, CS_Active);
3923 SendBlockNoLock(q.peer_id, block, client->serialization_version, client->net_proto_version);
3925 client->SentBlock(q.pos);
3931 void Server::fillMediaCache()
3933 DSTACK(__FUNCTION_NAME);
3935 infostream<<"Server: Calculating media file checksums"<<std::endl;
3937 // Collect all media file paths
3938 std::list<std::string> paths;
3939 for(std::vector<ModSpec>::iterator i = m_mods.begin();
3940 i != m_mods.end(); i++){
3941 const ModSpec &mod = *i;
3942 paths.push_back(mod.path + DIR_DELIM + "textures");
3943 paths.push_back(mod.path + DIR_DELIM + "sounds");
3944 paths.push_back(mod.path + DIR_DELIM + "media");
3945 paths.push_back(mod.path + DIR_DELIM + "models");
3947 paths.push_back(porting::path_user + DIR_DELIM + "textures" + DIR_DELIM + "server");
3949 // Collect media file information from paths into cache
3950 for(std::list<std::string>::iterator i = paths.begin();
3951 i != paths.end(); i++)
3953 std::string mediapath = *i;
3954 std::vector<fs::DirListNode> dirlist = fs::GetDirListing(mediapath);
3955 for(u32 j=0; j<dirlist.size(); j++){
3956 if(dirlist[j].dir) // Ignode dirs
3958 std::string filename = dirlist[j].name;
3959 // If name contains illegal characters, ignore the file
3960 if(!string_allowed(filename, TEXTURENAME_ALLOWED_CHARS)){
3961 infostream<<"Server: ignoring illegal file name: \""
3962 <<filename<<"\""<<std::endl;
3965 // If name is not in a supported format, ignore it
3966 const char *supported_ext[] = {
3967 ".png", ".jpg", ".bmp", ".tga",
3968 ".pcx", ".ppm", ".psd", ".wal", ".rgb",
3970 ".x", ".b3d", ".md2", ".obj",
3973 if(removeStringEnd(filename, supported_ext) == ""){
3974 infostream<<"Server: ignoring unsupported file extension: \""
3975 <<filename<<"\""<<std::endl;
3978 // Ok, attempt to load the file and add to cache
3979 std::string filepath = mediapath + DIR_DELIM + filename;
3981 std::ifstream fis(filepath.c_str(), std::ios_base::binary);
3982 if(fis.good() == false){
3983 errorstream<<"Server::fillMediaCache(): Could not open \""
3984 <<filename<<"\" for reading"<<std::endl;
3987 std::ostringstream tmp_os(std::ios_base::binary);
3991 fis.read(buf, 1024);
3992 std::streamsize len = fis.gcount();
3993 tmp_os.write(buf, len);
4002 errorstream<<"Server::fillMediaCache(): Failed to read \""
4003 <<filename<<"\""<<std::endl;
4006 if(tmp_os.str().length() == 0){
4007 errorstream<<"Server::fillMediaCache(): Empty file \""
4008 <<filepath<<"\""<<std::endl;
4013 sha1.addBytes(tmp_os.str().c_str(), tmp_os.str().length());
4015 unsigned char *digest = sha1.getDigest();
4016 std::string sha1_base64 = base64_encode(digest, 20);
4017 std::string sha1_hex = hex_encode((char*)digest, 20);
4021 this->m_media[filename] = MediaInfo(filepath, sha1_base64);
4022 verbosestream<<"Server: "<<sha1_hex<<" is "<<filename<<std::endl;
4027 struct SendableMediaAnnouncement
4030 std::string sha1_digest;
4032 SendableMediaAnnouncement(const std::string &name_="",
4033 const std::string &sha1_digest_=""):
4035 sha1_digest(sha1_digest_)
4039 void Server::sendMediaAnnouncement(u16 peer_id)
4041 DSTACK(__FUNCTION_NAME);
4043 verbosestream<<"Server: Announcing files to id("<<peer_id<<")"
4046 std::list<SendableMediaAnnouncement> file_announcements;
4048 for(std::map<std::string, MediaInfo>::iterator i = m_media.begin();
4049 i != m_media.end(); i++){
4051 file_announcements.push_back(
4052 SendableMediaAnnouncement(i->first, i->second.sha1_digest));
4056 std::ostringstream os(std::ios_base::binary);
4064 u16 length of sha1_digest
4069 writeU16(os, TOCLIENT_ANNOUNCE_MEDIA);
4070 writeU16(os, file_announcements.size());
4072 for(std::list<SendableMediaAnnouncement>::iterator
4073 j = file_announcements.begin();
4074 j != file_announcements.end(); ++j){
4075 os<<serializeString(j->name);
4076 os<<serializeString(j->sha1_digest);
4078 os<<serializeString(g_settings->get("remote_media"));
4081 std::string s = os.str();
4082 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
4085 m_clients.send(peer_id, 0, data, true);
4088 struct SendableMedia
4094 SendableMedia(const std::string &name_="", const std::string &path_="",
4095 const std::string &data_=""):
4102 void Server::sendRequestedMedia(u16 peer_id,
4103 const std::list<std::string> &tosend)
4105 DSTACK(__FUNCTION_NAME);
4107 verbosestream<<"Server::sendRequestedMedia(): "
4108 <<"Sending files to client"<<std::endl;
4112 // Put 5kB in one bunch (this is not accurate)
4113 u32 bytes_per_bunch = 5000;
4115 std::vector< std::list<SendableMedia> > file_bunches;
4116 file_bunches.push_back(std::list<SendableMedia>());
4118 u32 file_size_bunch_total = 0;
4120 for(std::list<std::string>::const_iterator i = tosend.begin();
4121 i != tosend.end(); ++i)
4123 const std::string &name = *i;
4125 if(m_media.find(name) == m_media.end()){
4126 errorstream<<"Server::sendRequestedMedia(): Client asked for "
4127 <<"unknown file \""<<(name)<<"\""<<std::endl;
4131 //TODO get path + name
4132 std::string tpath = m_media[name].path;
4135 std::ifstream fis(tpath.c_str(), std::ios_base::binary);
4136 if(fis.good() == false){
4137 errorstream<<"Server::sendRequestedMedia(): Could not open \""
4138 <<tpath<<"\" for reading"<<std::endl;
4141 std::ostringstream tmp_os(std::ios_base::binary);
4145 fis.read(buf, 1024);
4146 std::streamsize len = fis.gcount();
4147 tmp_os.write(buf, len);
4148 file_size_bunch_total += len;
4157 errorstream<<"Server::sendRequestedMedia(): Failed to read \""
4158 <<name<<"\""<<std::endl;
4161 /*infostream<<"Server::sendRequestedMedia(): Loaded \""
4162 <<tname<<"\""<<std::endl;*/
4164 file_bunches[file_bunches.size()-1].push_back(
4165 SendableMedia(name, tpath, tmp_os.str()));
4167 // Start next bunch if got enough data
4168 if(file_size_bunch_total >= bytes_per_bunch){
4169 file_bunches.push_back(std::list<SendableMedia>());
4170 file_size_bunch_total = 0;
4175 /* Create and send packets */
4177 u32 num_bunches = file_bunches.size();
4178 for(u32 i=0; i<num_bunches; i++)
4180 std::ostringstream os(std::ios_base::binary);
4184 u16 total number of texture bunches
4185 u16 index of this bunch
4186 u32 number of files in this bunch
4195 writeU16(os, TOCLIENT_MEDIA);
4196 writeU16(os, num_bunches);
4198 writeU32(os, file_bunches[i].size());
4200 for(std::list<SendableMedia>::iterator
4201 j = file_bunches[i].begin();
4202 j != file_bunches[i].end(); ++j){
4203 os<<serializeString(j->name);
4204 os<<serializeLongString(j->data);
4208 std::string s = os.str();
4209 verbosestream<<"Server::sendRequestedMedia(): bunch "
4210 <<i<<"/"<<num_bunches
4211 <<" files="<<file_bunches[i].size()
4212 <<" size=" <<s.size()<<std::endl;
4213 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
4215 m_clients.send(peer_id, 2, data, true);
4219 void Server::sendDetachedInventory(const std::string &name, u16 peer_id)
4221 if(m_detached_inventories.count(name) == 0){
4222 errorstream<<__FUNCTION_NAME<<": \""<<name<<"\" not found"<<std::endl;
4225 Inventory *inv = m_detached_inventories[name];
4227 std::ostringstream os(std::ios_base::binary);
4228 writeU16(os, TOCLIENT_DETACHED_INVENTORY);
4229 os<<serializeString(name);
4233 std::string s = os.str();
4234 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
4236 if (peer_id != PEER_ID_INEXISTENT)
4239 m_clients.send(peer_id, 0, data, true);
4243 m_clients.sendToAll(0,data,true);
4247 void Server::sendDetachedInventories(u16 peer_id)
4249 DSTACK(__FUNCTION_NAME);
4251 for(std::map<std::string, Inventory*>::iterator
4252 i = m_detached_inventories.begin();
4253 i != m_detached_inventories.end(); i++){
4254 const std::string &name = i->first;
4255 //Inventory *inv = i->second;
4256 sendDetachedInventory(name, peer_id);
4264 void Server::DiePlayer(u16 peer_id)
4266 DSTACK(__FUNCTION_NAME);
4268 PlayerSAO *playersao = getPlayerSAO(peer_id);
4271 infostream<<"Server::DiePlayer(): Player "
4272 <<playersao->getPlayer()->getName()
4273 <<" dies"<<std::endl;
4275 playersao->setHP(0);
4277 // Trigger scripted stuff
4278 m_script->on_dieplayer(playersao);
4280 SendPlayerHP(peer_id);
4281 SendDeathscreen(peer_id, false, v3f(0,0,0));
4284 void Server::RespawnPlayer(u16 peer_id)
4286 DSTACK(__FUNCTION_NAME);
4288 PlayerSAO *playersao = getPlayerSAO(peer_id);
4291 infostream<<"Server::RespawnPlayer(): Player "
4292 <<playersao->getPlayer()->getName()
4293 <<" respawns"<<std::endl;
4295 playersao->setHP(PLAYER_MAX_HP);
4297 bool repositioned = m_script->on_respawnplayer(playersao);
4299 v3f pos = findSpawnPos(m_env->getServerMap());
4300 playersao->setPos(pos);
4304 void Server::DenyAccess(u16 peer_id, const std::wstring &reason)
4306 DSTACK(__FUNCTION_NAME);
4308 SendAccessDenied(peer_id, reason);
4309 m_clients.event(peer_id, CSE_SetDenied);
4310 m_con.DisconnectPeer(peer_id);
4313 void Server::DeleteClient(u16 peer_id, ClientDeletionReason reason)
4315 DSTACK(__FUNCTION_NAME);
4316 std::wstring message;
4319 Clear references to playing sounds
4321 for(std::map<s32, ServerPlayingSound>::iterator
4322 i = m_playing_sounds.begin();
4323 i != m_playing_sounds.end();)
4325 ServerPlayingSound &psound = i->second;
4326 psound.clients.erase(peer_id);
4327 if(psound.clients.size() == 0)
4328 m_playing_sounds.erase(i++);
4333 Player *player = m_env->getPlayer(peer_id);
4335 // Collect information about leaving in chat
4337 if(player != NULL && reason != CDR_DENY)
4339 std::wstring name = narrow_to_wide(player->getName());
4342 message += L" left the game.";
4343 if(reason == CDR_TIMEOUT)
4344 message += L" (timed out)";
4348 /* Run scripts and remove from environment */
4352 PlayerSAO *playersao = player->getPlayerSAO();
4355 m_script->on_leaveplayer(playersao);
4357 playersao->disconnected();
4365 if(player != NULL && reason != CDR_DENY)
4367 std::ostringstream os(std::ios_base::binary);
4368 std::list<u16> clients = m_clients.getClientIDs();
4370 for(std::list<u16>::iterator
4371 i = clients.begin();
4372 i != clients.end(); ++i)
4375 Player *player = m_env->getPlayer(*i);
4378 // Get name of player
4379 os<<player->getName()<<" ";
4382 actionstream<<player->getName()<<" "
4383 <<(reason==CDR_TIMEOUT?"times out.":"leaves game.")
4384 <<" List of players: "<<os.str()<<std::endl;
4388 JMutexAutoLock env_lock(m_env_mutex);
4389 m_clients.DeleteClient(peer_id);
4393 // Send leave chat message to all remaining clients
4394 if(message.length() != 0)
4395 SendChatMessage(PEER_ID_INEXISTENT,message);
4398 void Server::UpdateCrafting(u16 peer_id)
4400 DSTACK(__FUNCTION_NAME);
4402 Player* player = m_env->getPlayer(peer_id);
4405 // Get a preview for crafting
4407 InventoryLocation loc;
4408 loc.setPlayer(player->getName());
4409 getCraftingResult(&player->inventory, preview, false, this);
4410 m_env->getScriptIface()->item_CraftPredict(preview, player->getPlayerSAO(), (&player->inventory)->getList("craft"), loc);
4412 // Put the new preview in
4413 InventoryList *plist = player->inventory.getList("craftpreview");
4415 assert(plist->getSize() >= 1);
4416 plist->changeItem(0, preview);
4419 RemoteClient* Server::getClient(u16 peer_id, ClientState state_min)
4421 RemoteClient *client = getClientNoEx(peer_id,state_min);
4423 throw ClientNotFoundException("Client not found");
4427 RemoteClient* Server::getClientNoEx(u16 peer_id, ClientState state_min)
4429 return m_clients.getClientNoEx(peer_id, state_min);
4432 std::string Server::getPlayerName(u16 peer_id)
4434 Player *player = m_env->getPlayer(peer_id);
4436 return "[id="+itos(peer_id)+"]";
4437 return player->getName();
4440 PlayerSAO* Server::getPlayerSAO(u16 peer_id)
4442 Player *player = m_env->getPlayer(peer_id);
4445 return player->getPlayerSAO();
4448 std::wstring Server::getStatusString()
4450 std::wostringstream os(std::ios_base::binary);
4453 os<<L"version="<<narrow_to_wide(minetest_version_simple);
4455 os<<L", uptime="<<m_uptime.get();
4457 os<<L", max_lag="<<m_env->getMaxLagEstimate();
4458 // Information about clients
4461 std::list<u16> clients = m_clients.getClientIDs();
4462 for(std::list<u16>::iterator i = clients.begin();
4463 i != clients.end(); ++i)
4466 Player *player = m_env->getPlayer(*i);
4467 // Get name of player
4468 std::wstring name = L"unknown";
4470 name = narrow_to_wide(player->getName());
4471 // Add name to information string
4479 if(((ServerMap*)(&m_env->getMap()))->isSavingEnabled() == false)
4480 os<<std::endl<<L"# Server: "<<" WARNING: Map saving is disabled.";
4481 if(g_settings->get("motd") != "")
4482 os<<std::endl<<L"# Server: "<<narrow_to_wide(g_settings->get("motd"));
4486 std::set<std::string> Server::getPlayerEffectivePrivs(const std::string &name)
4488 std::set<std::string> privs;
4489 m_script->getAuth(name, NULL, &privs);
4493 bool Server::checkPriv(const std::string &name, const std::string &priv)
4495 std::set<std::string> privs = getPlayerEffectivePrivs(name);
4496 return (privs.count(priv) != 0);
4499 void Server::reportPrivsModified(const std::string &name)
4502 std::list<u16> clients = m_clients.getClientIDs();
4503 for(std::list<u16>::iterator
4504 i = clients.begin();
4505 i != clients.end(); ++i){
4506 Player *player = m_env->getPlayer(*i);
4507 reportPrivsModified(player->getName());
4510 Player *player = m_env->getPlayer(name.c_str());
4513 SendPlayerPrivileges(player->peer_id);
4514 PlayerSAO *sao = player->getPlayerSAO();
4517 sao->updatePrivileges(
4518 getPlayerEffectivePrivs(name),
4523 void Server::reportInventoryFormspecModified(const std::string &name)
4525 Player *player = m_env->getPlayer(name.c_str());
4528 SendPlayerInventoryFormspec(player->peer_id);
4531 void Server::setIpBanned(const std::string &ip, const std::string &name)
4533 m_banmanager->add(ip, name);
4536 void Server::unsetIpBanned(const std::string &ip_or_name)
4538 m_banmanager->remove(ip_or_name);
4541 std::string Server::getBanDescription(const std::string &ip_or_name)
4543 return m_banmanager->getBanDescription(ip_or_name);
4546 void Server::notifyPlayer(const char *name, const std::wstring &msg)
4548 Player *player = m_env->getPlayer(name);
4552 if (player->peer_id == PEER_ID_INEXISTENT)
4555 SendChatMessage(player->peer_id, msg);
4558 bool Server::showFormspec(const char *playername, const std::string &formspec, const std::string &formname)
4560 Player *player = m_env->getPlayer(playername);
4564 infostream<<"showFormspec: couldn't find player:"<<playername<<std::endl;
4568 SendShowFormspecMessage(player->peer_id, formspec, formname);
4572 u32 Server::hudAdd(Player *player, HudElement *form) {
4576 u32 id = player->addHud(form);
4578 SendHUDAdd(player->peer_id, id, form);
4583 bool Server::hudRemove(Player *player, u32 id) {
4587 HudElement* todel = player->removeHud(id);
4594 SendHUDRemove(player->peer_id, id);
4598 bool Server::hudChange(Player *player, u32 id, HudElementStat stat, void *data) {
4602 SendHUDChange(player->peer_id, id, stat, data);
4606 bool Server::hudSetFlags(Player *player, u32 flags, u32 mask) {
4610 SendHUDSetFlags(player->peer_id, flags, mask);
4611 player->hud_flags = flags;
4613 PlayerSAO* playersao = player->getPlayerSAO();
4615 if (playersao == NULL)
4618 m_script->player_event(playersao, "hud_changed");
4622 bool Server::hudSetHotbarItemcount(Player *player, s32 hotbar_itemcount) {
4625 if (hotbar_itemcount <= 0 || hotbar_itemcount > HUD_HOTBAR_ITEMCOUNT_MAX)
4628 std::ostringstream os(std::ios::binary);
4629 writeS32(os, hotbar_itemcount);
4630 SendHUDSetParam(player->peer_id, HUD_PARAM_HOTBAR_ITEMCOUNT, os.str());
4634 void Server::hudSetHotbarImage(Player *player, std::string name) {
4638 SendHUDSetParam(player->peer_id, HUD_PARAM_HOTBAR_IMAGE, name);
4641 void Server::hudSetHotbarSelectedImage(Player *player, std::string name) {
4645 SendHUDSetParam(player->peer_id, HUD_PARAM_HOTBAR_SELECTED_IMAGE, name);
4648 bool Server::setLocalPlayerAnimations(Player *player, v2s32 animation_frames[4], f32 frame_speed)
4653 SendLocalPlayerAnimations(player->peer_id, animation_frames, frame_speed);
4657 bool Server::setPlayerEyeOffset(Player *player, v3f first, v3f third)
4662 SendEyeOffset(player->peer_id, first, third);
4666 bool Server::setSky(Player *player, const video::SColor &bgcolor,
4667 const std::string &type, const std::vector<std::string> ¶ms)
4672 SendSetSky(player->peer_id, bgcolor, type, params);
4676 bool Server::overrideDayNightRatio(Player *player, bool do_override,
4682 SendOverrideDayNightRatio(player->peer_id, do_override, ratio);
4686 void Server::notifyPlayers(const std::wstring &msg)
4688 SendChatMessage(PEER_ID_INEXISTENT,msg);
4691 void Server::spawnParticle(const char *playername, v3f pos,
4692 v3f velocity, v3f acceleration,
4693 float expirationtime, float size, bool
4694 collisiondetection, bool vertical, std::string texture)
4696 Player *player = m_env->getPlayer(playername);
4699 SendSpawnParticle(player->peer_id, pos, velocity, acceleration,
4700 expirationtime, size, collisiondetection, vertical, texture);
4703 void Server::spawnParticleAll(v3f pos, v3f velocity, v3f acceleration,
4704 float expirationtime, float size,
4705 bool collisiondetection, bool vertical, std::string texture)
4707 SendSpawnParticle(PEER_ID_INEXISTENT,pos, velocity, acceleration,
4708 expirationtime, size, collisiondetection, vertical, texture);
4711 u32 Server::addParticleSpawner(const char *playername,
4712 u16 amount, float spawntime,
4713 v3f minpos, v3f maxpos,
4714 v3f minvel, v3f maxvel,
4715 v3f minacc, v3f maxacc,
4716 float minexptime, float maxexptime,
4717 float minsize, float maxsize,
4718 bool collisiondetection, bool vertical, std::string texture)
4720 Player *player = m_env->getPlayer(playername);
4725 for(;;) // look for unused particlespawner id
4728 if (std::find(m_particlespawner_ids.begin(),
4729 m_particlespawner_ids.end(), id)
4730 == m_particlespawner_ids.end())
4732 m_particlespawner_ids.push_back(id);
4737 SendAddParticleSpawner(player->peer_id, amount, spawntime,
4738 minpos, maxpos, minvel, maxvel, minacc, maxacc,
4739 minexptime, maxexptime, minsize, maxsize,
4740 collisiondetection, vertical, texture, id);
4745 u32 Server::addParticleSpawnerAll(u16 amount, float spawntime,
4746 v3f minpos, v3f maxpos,
4747 v3f minvel, v3f maxvel,
4748 v3f minacc, v3f maxacc,
4749 float minexptime, float maxexptime,
4750 float minsize, float maxsize,
4751 bool collisiondetection, bool vertical, std::string texture)
4754 for(;;) // look for unused particlespawner id
4757 if (std::find(m_particlespawner_ids.begin(),
4758 m_particlespawner_ids.end(), id)
4759 == m_particlespawner_ids.end())
4761 m_particlespawner_ids.push_back(id);
4766 SendAddParticleSpawner(PEER_ID_INEXISTENT, amount, spawntime,
4767 minpos, maxpos, minvel, maxvel, minacc, maxacc,
4768 minexptime, maxexptime, minsize, maxsize,
4769 collisiondetection, vertical, texture, id);
4774 void Server::deleteParticleSpawner(const char *playername, u32 id)
4776 Player *player = m_env->getPlayer(playername);
4780 m_particlespawner_ids.erase(
4781 std::remove(m_particlespawner_ids.begin(),
4782 m_particlespawner_ids.end(), id),
4783 m_particlespawner_ids.end());
4784 SendDeleteParticleSpawner(player->peer_id, id);
4787 void Server::deleteParticleSpawnerAll(u32 id)
4789 m_particlespawner_ids.erase(
4790 std::remove(m_particlespawner_ids.begin(),
4791 m_particlespawner_ids.end(), id),
4792 m_particlespawner_ids.end());
4793 SendDeleteParticleSpawner(PEER_ID_INEXISTENT, id);
4796 Inventory* Server::createDetachedInventory(const std::string &name)
4798 if(m_detached_inventories.count(name) > 0){
4799 infostream<<"Server clearing detached inventory \""<<name<<"\""<<std::endl;
4800 delete m_detached_inventories[name];
4802 infostream<<"Server creating detached inventory \""<<name<<"\""<<std::endl;
4804 Inventory *inv = new Inventory(m_itemdef);
4806 m_detached_inventories[name] = inv;
4807 //TODO find a better way to do this
4808 sendDetachedInventory(name,PEER_ID_INEXISTENT);
4815 BoolScopeSet(bool *dst, bool val):
4818 m_orig_state = *m_dst;
4823 *m_dst = m_orig_state;
4830 // actions: time-reversed list
4831 // Return value: success/failure
4832 bool Server::rollbackRevertActions(const std::list<RollbackAction> &actions,
4833 std::list<std::string> *log)
4835 infostream<<"Server::rollbackRevertActions(len="<<actions.size()<<")"<<std::endl;
4836 ServerMap *map = (ServerMap*)(&m_env->getMap());
4837 // Disable rollback report sink while reverting
4838 BoolScopeSet rollback_scope_disable(&m_rollback_sink_enabled, false);
4840 // Fail if no actions to handle
4841 if(actions.empty()){
4842 log->push_back("Nothing to do.");
4849 for(std::list<RollbackAction>::const_iterator
4850 i = actions.begin();
4851 i != actions.end(); i++)
4853 const RollbackAction &action = *i;
4855 bool success = action.applyRevert(map, this, this);
4858 std::ostringstream os;
4859 os<<"Revert of step ("<<num_tried<<") "<<action.toString()<<" failed";
4860 infostream<<"Map::rollbackRevertActions(): "<<os.str()<<std::endl;
4862 log->push_back(os.str());
4864 std::ostringstream os;
4865 os<<"Successfully reverted step ("<<num_tried<<") "<<action.toString();
4866 infostream<<"Map::rollbackRevertActions(): "<<os.str()<<std::endl;
4868 log->push_back(os.str());
4872 infostream<<"Map::rollbackRevertActions(): "<<num_failed<<"/"<<num_tried
4873 <<" failed"<<std::endl;
4875 // Call it done if less than half failed
4876 return num_failed <= num_tried/2;
4879 // IGameDef interface
4881 IItemDefManager* Server::getItemDefManager()
4885 INodeDefManager* Server::getNodeDefManager()
4889 ICraftDefManager* Server::getCraftDefManager()
4893 ITextureSource* Server::getTextureSource()
4897 IShaderSource* Server::getShaderSource()
4901 scene::ISceneManager* Server::getSceneManager()
4906 u16 Server::allocateUnknownNodeId(const std::string &name)
4908 return m_nodedef->allocateDummy(name);
4910 ISoundManager* Server::getSoundManager()
4912 return &dummySoundManager;
4914 MtEventManager* Server::getEventManager()
4918 IRollbackReportSink* Server::getRollbackReportSink()
4920 if(!m_enable_rollback_recording)
4922 if(!m_rollback_sink_enabled)
4927 IWritableItemDefManager* Server::getWritableItemDefManager()
4931 IWritableNodeDefManager* Server::getWritableNodeDefManager()
4935 IWritableCraftDefManager* Server::getWritableCraftDefManager()
4940 const ModSpec* Server::getModSpec(const std::string &modname)
4942 for(std::vector<ModSpec>::iterator i = m_mods.begin();
4943 i != m_mods.end(); i++){
4944 const ModSpec &mod = *i;
4945 if(mod.name == modname)
4950 void Server::getModNames(std::list<std::string> &modlist)
4952 for(std::vector<ModSpec>::iterator i = m_mods.begin(); i != m_mods.end(); i++)
4954 modlist.push_back(i->name);
4957 std::string Server::getBuiltinLuaPath()
4959 return porting::path_share + DIR_DELIM + "builtin";
4962 v3f findSpawnPos(ServerMap &map)
4964 //return v3f(50,50,50)*BS;
4969 nodepos = v2s16(0,0);
4974 s16 water_level = map.getWaterLevel();
4976 // Try to find a good place a few times
4977 for(s32 i=0; i<1000; i++)
4980 // We're going to try to throw the player to this position
4981 v2s16 nodepos2d = v2s16(
4982 -range + (myrand() % (range * 2)),
4983 -range + (myrand() % (range * 2)));
4985 // Get ground height at point
4986 s16 groundheight = map.findGroundLevel(nodepos2d);
4987 if (groundheight <= water_level) // Don't go underwater
4989 if (groundheight > water_level + 6) // Don't go to high places
4992 nodepos = v3s16(nodepos2d.X, groundheight, nodepos2d.Y);
4993 bool is_good = false;
4995 for (s32 i = 0; i < 10; i++) {
4996 v3s16 blockpos = getNodeBlockPos(nodepos);
4997 map.emergeBlock(blockpos, true);
4998 content_t c = map.getNodeNoEx(nodepos).getContent();
4999 if (c == CONTENT_AIR || c == CONTENT_IGNORE) {
5001 if (air_count >= 2){
5009 // Found a good place
5010 //infostream<<"Searched through "<<i<<" places."<<std::endl;
5016 return intToFloat(nodepos, BS);
5019 PlayerSAO* Server::emergePlayer(const char *name, u16 peer_id)
5021 RemotePlayer *player = NULL;
5022 bool newplayer = false;
5025 Try to get an existing player
5027 player = static_cast<RemotePlayer*>(m_env->getPlayer(name));
5029 // If player is already connected, cancel
5030 if(player != NULL && player->peer_id != 0)
5032 infostream<<"emergePlayer(): Player already connected"<<std::endl;
5037 If player with the wanted peer_id already exists, cancel.
5039 if(m_env->getPlayer(peer_id) != NULL)
5041 infostream<<"emergePlayer(): Player with wrong name but same"
5042 " peer_id already exists"<<std::endl;
5046 // Load player if it isn't already loaded
5048 player = static_cast<RemotePlayer*>(m_env->loadPlayer(name));
5051 // Create player if it doesn't exist
5054 player = new RemotePlayer(this, name);
5055 // Set player position
5056 infostream<<"Server: Finding spawn place for player \""
5057 <<name<<"\""<<std::endl;
5058 v3f pos = findSpawnPos(m_env->getServerMap());
5059 player->setPosition(pos);
5061 // Make sure the player is saved
5062 player->setModified(true);
5064 // Add player to environment
5065 m_env->addPlayer(player);
5068 // Create a new player active object
5069 PlayerSAO *playersao = new PlayerSAO(m_env, player, peer_id,
5070 getPlayerEffectivePrivs(player->getName()),
5073 /* Clean up old HUD elements from previous sessions */
5076 /* Add object to environment */
5077 m_env->addActiveObject(playersao);
5081 m_script->on_newplayer(playersao);
5087 void dedicated_server_loop(Server &server, bool &kill)
5089 DSTACK(__FUNCTION_NAME);
5091 verbosestream<<"dedicated_server_loop()"<<std::endl;
5093 IntervalLimiter m_profiler_interval;
5097 float steplen = g_settings->getFloat("dedicated_server_step");
5098 // This is kind of a hack but can be done like this
5099 // because server.step() is very light
5101 ScopeProfiler sp(g_profiler, "dedicated server sleep");
5102 sleep_ms((int)(steplen*1000.0));
5104 server.step(steplen);
5106 if(server.getShutdownRequested() || kill)
5108 infostream<<"Dedicated server quitting"<<std::endl;
5110 if(g_settings->getBool("server_announce") == true)
5111 ServerList::sendAnnounce("delete");
5119 float profiler_print_interval =
5120 g_settings->getFloat("profiler_print_interval");
5121 if(profiler_print_interval != 0)
5123 if(m_profiler_interval.step(steplen, profiler_print_interval))
5125 infostream<<"Profiler:"<<std::endl;
5126 g_profiler->print(infostream);
5127 g_profiler->clear();