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 "network/networkprotocol.h"
25 #include "network/serveropcodes.h"
27 #include "environment.h"
29 #include "jthread/jmutexautolock.h"
31 #include "constants.h"
37 #include "serverobject.h"
38 #include "genericobject.h"
42 #include "scripting_game.h"
49 #include "content_mapnode.h"
50 #include "content_nodemeta.h"
51 #include "content_abm.h"
52 #include "content_sao.h"
57 #include "sound.h" // dummySoundManager
58 #include "event_manager.h"
60 #include "serverlist.h"
61 #include "util/string.h"
62 #include "util/pointedthing.h"
63 #include "util/mathconstants.h"
65 #include "util/serialize.h"
66 #include "util/thread.h"
67 #include "defaultsettings.h"
69 class ClientNotFoundException : public BaseException
72 ClientNotFoundException(const char *s):
77 class ServerThread : public JThread
83 ServerThread(Server *server):
92 void * ServerThread::Thread()
94 log_register_thread("ServerThread");
96 DSTACK(__FUNCTION_NAME);
97 BEGIN_DEBUG_EXCEPTION_HANDLER
99 m_server->AsyncRunStep(true);
103 porting::setThreadName("ServerThread");
105 while(!StopRequested())
108 //TimeTaker timer("AsyncRunStep() + Receive()");
110 m_server->AsyncRunStep();
115 catch(con::NoIncomingDataException &e)
118 catch(con::PeerNotFoundException &e)
120 infostream<<"Server: PeerNotFoundException"<<std::endl;
122 catch(ClientNotFoundException &e)
125 catch(con::ConnectionBindFailed &e)
127 m_server->setAsyncFatalError(e.what());
131 m_server->setAsyncFatalError(e.what());
135 END_DEBUG_EXCEPTION_HANDLER(errorstream)
140 v3f ServerSoundParams::getPos(ServerEnvironment *env, bool *pos_exists) const
142 if(pos_exists) *pos_exists = false;
147 if(pos_exists) *pos_exists = true;
152 ServerActiveObject *sao = env->getActiveObject(object);
155 if(pos_exists) *pos_exists = true;
156 return sao->getBasePosition(); }
168 const std::string &path_world,
169 const SubgameSpec &gamespec,
170 bool simple_singleplayer_mode,
173 m_path_world(path_world),
174 m_gamespec(gamespec),
175 m_simple_singleplayer_mode(simple_singleplayer_mode),
176 m_async_fatal_error(""),
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),
202 m_liquid_transform_timer = 0.0;
203 m_liquid_transform_every = 1.0;
204 m_print_info_timer = 0.0;
205 m_masterserver_timer = 0.0;
206 m_objectdata_timer = 0.0;
207 m_emergethread_trigger_timer = 0.0;
208 m_savemap_timer = 0.0;
211 m_lag = g_settings->getFloat("dedicated_server_step");
214 throw ServerError("Supplied empty world path");
216 if(!gamespec.isValid())
217 throw ServerError("Supplied invalid gamespec");
219 infostream<<"Server created for gameid \""<<m_gamespec.id<<"\"";
220 if(m_simple_singleplayer_mode)
221 infostream<<" in simple singleplayer mode"<<std::endl;
223 infostream<<std::endl;
224 infostream<<"- world: "<<m_path_world<<std::endl;
225 infostream<<"- game: "<<m_gamespec.path<<std::endl;
227 // Initialize default settings and override defaults with those provided
229 set_default_settings(g_settings);
230 Settings gamedefaults;
231 getGameMinetestConfig(gamespec.path, gamedefaults);
232 override_default_settings(g_settings, &gamedefaults);
234 // Create server thread
235 m_thread = new ServerThread(this);
237 // Create emerge manager
238 m_emerge = new EmergeManager(this);
240 // Create world if it doesn't exist
241 if(!initializeWorld(m_path_world, m_gamespec.id))
242 throw ServerError("Failed to initialize world");
244 // Create ban manager
245 std::string ban_path = m_path_world + DIR_DELIM "ipban.txt";
246 m_banmanager = new BanManager(ban_path);
248 // Create rollback manager
249 m_rollback = new RollbackManager(m_path_world, 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 // Load mapgen params from Settings
301 m_emerge->loadMapgenParams();
303 // Create the Map (loads map_meta.txt, overriding configured mapgen params)
304 ServerMap *servermap = new ServerMap(path_world, this, m_emerge);
306 // Initialize scripting
307 infostream<<"Server: Initializing Lua"<<std::endl;
309 m_script = new GameScripting(this);
311 std::string scriptpath = getBuiltinLuaPath() + DIR_DELIM "init.lua";
313 if (!m_script->loadScript(scriptpath))
314 throw ModError("Failed to load and run " + scriptpath);
317 infostream<<"Server: Loading mods: ";
318 for(std::vector<ModSpec>::iterator i = m_mods.begin();
319 i != m_mods.end(); i++){
320 const ModSpec &mod = *i;
321 infostream<<mod.name<<" ";
323 infostream<<std::endl;
324 // Load and run "mod" scripts
325 for(std::vector<ModSpec>::iterator i = m_mods.begin();
326 i != m_mods.end(); i++){
327 const ModSpec &mod = *i;
328 std::string scriptpath = mod.path + DIR_DELIM + "init.lua";
329 infostream<<" ["<<padStringRight(mod.name, 12)<<"] [\""
330 <<scriptpath<<"\"]"<<std::endl;
331 bool success = m_script->loadMod(scriptpath, mod.name);
333 errorstream<<"Server: Failed to load and run "
334 <<scriptpath<<std::endl;
335 throw ModError("Failed to load and run "+scriptpath);
339 // Read Textures and calculate sha1 sums
342 // Apply item aliases in the node definition manager
343 m_nodedef->updateAliases(m_itemdef);
345 m_nodedef->setNodeRegistrationStatus(true);
347 // Perform pending node name resolutions
348 m_nodedef->runNodeResolverCallbacks();
350 // Initialize Environment
351 m_env = new ServerEnvironment(servermap, m_script, this, m_path_world);
353 m_clients.setEnv(m_env);
355 // Initialize mapgens
356 m_emerge->initMapgens();
358 // Give environment reference to scripting api
359 m_script->initializeEnvironment(m_env);
361 // Register us to receive map edit events
362 servermap->addEventReceiver(this);
364 // If file exists, load environment metadata
365 if(fs::PathExists(m_path_world + DIR_DELIM "env_meta.txt"))
367 infostream<<"Server: Loading environment metadata"<<std::endl;
371 // Add some test ActiveBlockModifiers to environment
372 add_legacy_abms(m_env, m_nodedef);
374 m_liquid_transform_every = g_settings->getFloat("liquid_update");
379 infostream<<"Server destructing"<<std::endl;
381 // Send shutdown message
382 SendChatMessage(PEER_ID_INEXISTENT, L"*** Server shutting down");
385 JMutexAutoLock envlock(m_env_mutex);
387 // Execute script shutdown hooks
388 m_script->on_shutdown();
390 infostream<<"Server: Saving players"<<std::endl;
391 m_env->saveLoadedPlayers();
393 infostream<<"Server: Saving environment metadata"<<std::endl;
401 // stop all emerge threads before deleting players that may have
402 // requested blocks to be emerged
403 m_emerge->stopThreads();
405 // Delete things in the reverse order of creation
408 // N.B. the EmergeManager should be deleted after the Environment since Map
409 // depends on EmergeManager to write its current params to the map meta
418 // Deinitialize scripting
419 infostream<<"Server: Deinitializing scripting"<<std::endl;
422 // Delete detached inventories
423 for (std::map<std::string, Inventory*>::iterator
424 i = m_detached_inventories.begin();
425 i != m_detached_inventories.end(); i++) {
430 void Server::start(Address bind_addr)
432 DSTACK(__FUNCTION_NAME);
434 m_bind_addr = bind_addr;
436 infostream<<"Starting server on "
437 << bind_addr.serializeString() <<"..."<<std::endl;
439 // Stop thread if already running
442 // Initialize connection
443 m_con.SetTimeoutMs(30);
444 m_con.Serve(bind_addr);
449 // ASCII art for the win!
451 <<" .__ __ __ "<<std::endl
452 <<" _____ |__| ____ _____/ |_ ____ _______/ |_ "<<std::endl
453 <<" / \\| |/ \\_/ __ \\ __\\/ __ \\ / ___/\\ __\\"<<std::endl
454 <<"| Y Y \\ | | \\ ___/| | \\ ___/ \\___ \\ | | "<<std::endl
455 <<"|__|_| /__|___| /\\___ >__| \\___ >____ > |__| "<<std::endl
456 <<" \\/ \\/ \\/ \\/ \\/ "<<std::endl;
457 actionstream<<"World at ["<<m_path_world<<"]"<<std::endl;
458 actionstream<<"Server for gameid=\""<<m_gamespec.id
459 <<"\" listening on "<<bind_addr.serializeString()<<":"
460 <<bind_addr.getPort() << "."<<std::endl;
465 DSTACK(__FUNCTION_NAME);
467 infostream<<"Server: Stopping and waiting threads"<<std::endl;
469 // Stop threads (set run=false first so both start stopping)
471 //m_emergethread.setRun(false);
473 //m_emergethread.stop();
475 infostream<<"Server: Threads stopped"<<std::endl;
478 void Server::step(float dtime)
480 DSTACK(__FUNCTION_NAME);
485 JMutexAutoLock lock(m_step_dtime_mutex);
486 m_step_dtime += dtime;
488 // Throw if fatal error occurred in thread
489 std::string async_err = m_async_fatal_error.get();
491 throw ServerError(async_err);
495 void Server::AsyncRunStep(bool initial_step)
497 DSTACK(__FUNCTION_NAME);
499 g_profiler->add("Server::AsyncRunStep (num)", 1);
503 JMutexAutoLock lock1(m_step_dtime_mutex);
504 dtime = m_step_dtime;
508 // Send blocks to clients
512 if((dtime < 0.001) && (initial_step == false))
515 g_profiler->add("Server::AsyncRunStep with dtime (num)", 1);
517 //infostream<<"Server steps "<<dtime<<std::endl;
518 //infostream<<"Server::AsyncRunStep(): dtime="<<dtime<<std::endl;
521 JMutexAutoLock lock1(m_step_dtime_mutex);
522 m_step_dtime -= dtime;
529 m_uptime.set(m_uptime.get() + dtime);
535 Update time of day and overall game time
538 JMutexAutoLock envlock(m_env_mutex);
540 m_env->setTimeOfDaySpeed(g_settings->getFloat("time_speed"));
543 Send to clients at constant intervals
546 m_time_of_day_send_timer -= dtime;
547 if(m_time_of_day_send_timer < 0.0)
549 m_time_of_day_send_timer = g_settings->getFloat("time_send_interval");
550 u16 time = m_env->getTimeOfDay();
551 float time_speed = g_settings->getFloat("time_speed");
552 SendTimeOfDay(PEER_ID_INEXISTENT, time, time_speed);
557 JMutexAutoLock lock(m_env_mutex);
558 // Figure out and report maximum lag to environment
559 float max_lag = m_env->getMaxLagEstimate();
560 max_lag *= 0.9998; // Decrease slowly (about half per 5 minutes)
562 if(dtime > 0.1 && dtime > max_lag * 2.0)
563 infostream<<"Server: Maximum lag peaked to "<<dtime
567 m_env->reportMaxLagEstimate(max_lag);
569 ScopeProfiler sp(g_profiler, "SEnv step");
570 ScopeProfiler sp2(g_profiler, "SEnv step avg", SPT_AVG);
574 static const float map_timer_and_unload_dtime = 2.92;
575 if(m_map_timer_and_unload_interval.step(dtime, map_timer_and_unload_dtime))
577 JMutexAutoLock lock(m_env_mutex);
578 // Run Map's timers and unload unused data
579 ScopeProfiler sp(g_profiler, "Server: map timer and unload");
580 m_env->getMap().timerUpdate(map_timer_and_unload_dtime,
581 g_settings->getFloat("server_unload_unused_data_timeout"));
592 JMutexAutoLock lock(m_env_mutex);
594 std::list<u16> clientids = m_clients.getClientIDs();
596 ScopeProfiler sp(g_profiler, "Server: handle players");
598 for(std::list<u16>::iterator
599 i = clientids.begin();
600 i != clientids.end(); ++i)
602 PlayerSAO *playersao = getPlayerSAO(*i);
603 if(playersao == NULL)
607 Handle player HPs (die if hp=0)
609 if(playersao->m_hp_not_sent && g_settings->getBool("enable_damage"))
611 if(playersao->getHP() == 0)
618 Send player breath if changed
620 if(playersao->m_breath_not_sent) {
621 SendPlayerBreath(*i);
625 Send player inventories if necessary
627 if(playersao->m_moved){
629 playersao->m_moved = false;
631 if(playersao->m_inventory_not_sent){
638 /* Transform liquids */
639 m_liquid_transform_timer += dtime;
640 if(m_liquid_transform_timer >= m_liquid_transform_every)
642 m_liquid_transform_timer -= m_liquid_transform_every;
644 JMutexAutoLock lock(m_env_mutex);
646 ScopeProfiler sp(g_profiler, "Server: liquid transform");
648 std::map<v3s16, MapBlock*> modified_blocks;
649 m_env->getMap().transformLiquids(modified_blocks);
654 core::map<v3s16, MapBlock*> lighting_modified_blocks;
655 ServerMap &map = ((ServerMap&)m_env->getMap());
656 map.updateLighting(modified_blocks, lighting_modified_blocks);
658 // Add blocks modified by lighting to modified_blocks
659 for(core::map<v3s16, MapBlock*>::Iterator
660 i = lighting_modified_blocks.getIterator();
661 i.atEnd() == false; i++)
663 MapBlock *block = i.getNode()->getValue();
664 modified_blocks.insert(block->getPos(), block);
668 Set the modified blocks unsent for all the clients
670 if(!modified_blocks.empty())
672 SetBlocksNotSent(modified_blocks);
675 m_clients.step(dtime);
677 m_lag += (m_lag > dtime ? -1 : 1) * dtime/100;
679 // send masterserver announce
681 float &counter = m_masterserver_timer;
682 if(!isSingleplayer() && (!counter || counter >= 300.0) &&
683 g_settings->getBool("server_announce"))
685 ServerList::sendAnnounce(counter ? "update" : "start",
686 m_bind_addr.getPort(),
687 m_clients.getPlayerNames(),
689 m_env->getGameTime(),
692 m_emerge->params.mg_name,
701 Check added and deleted active objects
704 //infostream<<"Server: Checking added and deleted active objects"<<std::endl;
705 JMutexAutoLock envlock(m_env_mutex);
708 std::map<u16, RemoteClient*> clients = m_clients.getClientList();
709 ScopeProfiler sp(g_profiler, "Server: checking added and deleted objs");
711 // Radius inside which objects are active
712 s16 radius = g_settings->getS16("active_object_send_range_blocks");
713 s16 player_radius = g_settings->getS16("player_transfer_distance");
715 if (player_radius == 0 && g_settings->exists("unlimited_player_transfer_distance") &&
716 !g_settings->getBool("unlimited_player_transfer_distance"))
717 player_radius = radius;
719 radius *= MAP_BLOCKSIZE;
720 player_radius *= MAP_BLOCKSIZE;
722 for(std::map<u16, RemoteClient*>::iterator
724 i != clients.end(); ++i)
726 RemoteClient *client = i->second;
728 // If definitions and textures have not been sent, don't
729 // send objects either
730 if (client->getState() < CS_DefinitionsSent)
733 Player *player = m_env->getPlayer(client->peer_id);
736 // This can happen if the client timeouts somehow
737 /*infostream<<"WARNING: "<<__FUNCTION_NAME<<": Client "
739 <<" has no associated player"<<std::endl;*/
742 v3s16 pos = floatToInt(player->getPosition(), BS);
744 std::set<u16> removed_objects;
745 std::set<u16> added_objects;
746 m_env->getRemovedActiveObjects(pos, radius, player_radius,
747 client->m_known_objects, removed_objects);
748 m_env->getAddedActiveObjects(pos, radius, player_radius,
749 client->m_known_objects, added_objects);
751 // Ignore if nothing happened
752 if(removed_objects.empty() && added_objects.empty())
754 //infostream<<"active objects: none changed"<<std::endl;
758 std::string data_buffer;
762 // Handle removed objects
763 writeU16((u8*)buf, removed_objects.size());
764 data_buffer.append(buf, 2);
765 for(std::set<u16>::iterator
766 i = removed_objects.begin();
767 i != removed_objects.end(); ++i)
771 ServerActiveObject* obj = m_env->getActiveObject(id);
773 // Add to data buffer for sending
774 writeU16((u8*)buf, id);
775 data_buffer.append(buf, 2);
777 // Remove from known objects
778 client->m_known_objects.erase(id);
780 if(obj && obj->m_known_by_count > 0)
781 obj->m_known_by_count--;
784 // Handle added objects
785 writeU16((u8*)buf, added_objects.size());
786 data_buffer.append(buf, 2);
787 for(std::set<u16>::iterator
788 i = added_objects.begin();
789 i != added_objects.end(); ++i)
793 ServerActiveObject* obj = m_env->getActiveObject(id);
796 u8 type = ACTIVEOBJECT_TYPE_INVALID;
798 infostream<<"WARNING: "<<__FUNCTION_NAME
799 <<": NULL object"<<std::endl;
801 type = obj->getSendType();
803 // Add to data buffer for sending
804 writeU16((u8*)buf, id);
805 data_buffer.append(buf, 2);
806 writeU8((u8*)buf, type);
807 data_buffer.append(buf, 1);
810 data_buffer.append(serializeLongString(
811 obj->getClientInitializationData(client->net_proto_version)));
813 data_buffer.append(serializeLongString(""));
815 // Add to known objects
816 client->m_known_objects.insert(id);
819 obj->m_known_by_count++;
823 SharedBuffer<u8> reply(2 + data_buffer.size());
824 writeU16(&reply[0], TOCLIENT_ACTIVE_OBJECT_REMOVE_ADD);
825 memcpy((char*)&reply[2], data_buffer.c_str(),
828 m_clients.send(client->peer_id, 0, reply, true);
830 verbosestream<<"Server: Sent object remove/add: "
831 <<removed_objects.size()<<" removed, "
832 <<added_objects.size()<<" added, "
833 <<"packet size is "<<reply.getSize()<<std::endl;
838 Collect a list of all the objects known by the clients
839 and report it back to the environment.
842 core::map<u16, bool> all_known_objects;
844 for(core::map<u16, RemoteClient*>::Iterator
845 i = m_clients.getIterator();
846 i.atEnd() == false; i++)
848 RemoteClient *client = i.getNode()->getValue();
849 // Go through all known objects of client
850 for(core::map<u16, bool>::Iterator
851 i = client->m_known_objects.getIterator();
852 i.atEnd()==false; i++)
854 u16 id = i.getNode()->getKey();
855 all_known_objects[id] = true;
859 m_env->setKnownActiveObjects(whatever);
868 JMutexAutoLock envlock(m_env_mutex);
869 ScopeProfiler sp(g_profiler, "Server: sending object messages");
872 // Value = data sent by object
873 std::map<u16, std::list<ActiveObjectMessage>* > buffered_messages;
875 // Get active object messages from environment
878 ActiveObjectMessage aom = m_env->getActiveObjectMessage();
882 std::list<ActiveObjectMessage>* message_list = NULL;
883 std::map<u16, std::list<ActiveObjectMessage>* >::iterator n;
884 n = buffered_messages.find(aom.id);
885 if(n == buffered_messages.end())
887 message_list = new std::list<ActiveObjectMessage>;
888 buffered_messages[aom.id] = message_list;
892 message_list = n->second;
894 message_list->push_back(aom);
898 std::map<u16, RemoteClient*> clients = m_clients.getClientList();
899 // Route data to every client
900 for(std::map<u16, RemoteClient*>::iterator
902 i != clients.end(); ++i)
904 RemoteClient *client = i->second;
905 std::string reliable_data;
906 std::string unreliable_data;
907 // Go through all objects in message buffer
908 for(std::map<u16, std::list<ActiveObjectMessage>* >::iterator
909 j = buffered_messages.begin();
910 j != buffered_messages.end(); ++j)
912 // If object is not known by client, skip it
914 if(client->m_known_objects.find(id) == client->m_known_objects.end())
916 // Get message list of object
917 std::list<ActiveObjectMessage>* list = j->second;
918 // Go through every message
919 for(std::list<ActiveObjectMessage>::iterator
920 k = list->begin(); k != list->end(); ++k)
922 // Compose the full new data with header
923 ActiveObjectMessage aom = *k;
924 std::string new_data;
927 writeU16((u8*)&buf[0], aom.id);
928 new_data.append(buf, 2);
930 new_data += serializeString(aom.datastring);
931 // Add data to buffer
933 reliable_data += new_data;
935 unreliable_data += new_data;
939 reliable_data and unreliable_data are now ready.
942 if(reliable_data.size() > 0)
944 SharedBuffer<u8> reply(2 + reliable_data.size());
945 writeU16(&reply[0], TOCLIENT_ACTIVE_OBJECT_MESSAGES);
946 memcpy((char*)&reply[2], reliable_data.c_str(),
947 reliable_data.size());
949 m_clients.send(client->peer_id, 0, reply, true);
951 if(unreliable_data.size() > 0)
953 SharedBuffer<u8> reply(2 + unreliable_data.size());
954 writeU16(&reply[0], TOCLIENT_ACTIVE_OBJECT_MESSAGES);
955 memcpy((char*)&reply[2], unreliable_data.c_str(),
956 unreliable_data.size());
957 // Send as unreliable
958 m_clients.send(client->peer_id, 1, reply, false);
961 /*if(reliable_data.size() > 0 || unreliable_data.size() > 0)
963 infostream<<"Server: Size of object message data: "
964 <<"reliable: "<<reliable_data.size()
965 <<", unreliable: "<<unreliable_data.size()
971 // Clear buffered_messages
972 for(std::map<u16, std::list<ActiveObjectMessage>* >::iterator
973 i = buffered_messages.begin();
974 i != buffered_messages.end(); ++i)
981 Send queued-for-sending map edit events.
984 // We will be accessing the environment
985 JMutexAutoLock lock(m_env_mutex);
987 // Don't send too many at a time
990 // Single change sending is disabled if queue size is not small
991 bool disable_single_change_sending = false;
992 if(m_unsent_map_edit_queue.size() >= 4)
993 disable_single_change_sending = true;
995 int event_count = m_unsent_map_edit_queue.size();
997 // We'll log the amount of each
1000 while(m_unsent_map_edit_queue.size() != 0)
1002 MapEditEvent* event = m_unsent_map_edit_queue.pop_front();
1004 // Players far away from the change are stored here.
1005 // Instead of sending the changes, MapBlocks are set not sent
1007 std::list<u16> far_players;
1009 if(event->type == MEET_ADDNODE || event->type == MEET_SWAPNODE)
1011 //infostream<<"Server: MEET_ADDNODE"<<std::endl;
1012 prof.add("MEET_ADDNODE", 1);
1013 if(disable_single_change_sending)
1014 sendAddNode(event->p, event->n, event->already_known_by_peer,
1015 &far_players, 5, event->type == MEET_ADDNODE);
1017 sendAddNode(event->p, event->n, event->already_known_by_peer,
1018 &far_players, 30, event->type == MEET_ADDNODE);
1020 else if(event->type == MEET_REMOVENODE)
1022 //infostream<<"Server: MEET_REMOVENODE"<<std::endl;
1023 prof.add("MEET_REMOVENODE", 1);
1024 if(disable_single_change_sending)
1025 sendRemoveNode(event->p, event->already_known_by_peer,
1028 sendRemoveNode(event->p, event->already_known_by_peer,
1031 else if(event->type == MEET_BLOCK_NODE_METADATA_CHANGED)
1033 infostream<<"Server: MEET_BLOCK_NODE_METADATA_CHANGED"<<std::endl;
1034 prof.add("MEET_BLOCK_NODE_METADATA_CHANGED", 1);
1035 setBlockNotSent(event->p);
1037 else if(event->type == MEET_OTHER)
1039 infostream<<"Server: MEET_OTHER"<<std::endl;
1040 prof.add("MEET_OTHER", 1);
1041 for(std::set<v3s16>::iterator
1042 i = event->modified_blocks.begin();
1043 i != event->modified_blocks.end(); ++i)
1045 setBlockNotSent(*i);
1050 prof.add("unknown", 1);
1051 infostream<<"WARNING: Server: Unknown MapEditEvent "
1052 <<((u32)event->type)<<std::endl;
1056 Set blocks not sent to far players
1058 if(!far_players.empty())
1060 // Convert list format to that wanted by SetBlocksNotSent
1061 std::map<v3s16, MapBlock*> modified_blocks2;
1062 for(std::set<v3s16>::iterator
1063 i = event->modified_blocks.begin();
1064 i != event->modified_blocks.end(); ++i)
1066 modified_blocks2[*i] =
1067 m_env->getMap().getBlockNoCreateNoEx(*i);
1069 // Set blocks not sent
1070 for(std::list<u16>::iterator
1071 i = far_players.begin();
1072 i != far_players.end(); ++i)
1075 RemoteClient *client = getClient(peer_id);
1078 client->SetBlocksNotSent(modified_blocks2);
1084 /*// Don't send too many at a time
1086 if(count >= 1 && m_unsent_map_edit_queue.size() < 100)
1090 if(event_count >= 5){
1091 infostream<<"Server: MapEditEvents:"<<std::endl;
1092 prof.print(infostream);
1093 } else if(event_count != 0){
1094 verbosestream<<"Server: MapEditEvents:"<<std::endl;
1095 prof.print(verbosestream);
1101 Trigger emergethread (it somehow gets to a non-triggered but
1102 bysy state sometimes)
1105 float &counter = m_emergethread_trigger_timer;
1111 m_emerge->startThreads();
1113 // Update m_enable_rollback_recording here too
1114 m_enable_rollback_recording =
1115 g_settings->getBool("enable_rollback_recording");
1119 // Save map, players and auth stuff
1121 float &counter = m_savemap_timer;
1123 if(counter >= g_settings->getFloat("server_map_save_interval"))
1126 JMutexAutoLock lock(m_env_mutex);
1128 ScopeProfiler sp(g_profiler, "Server: saving stuff");
1131 if (m_banmanager->isModified()) {
1132 m_banmanager->save();
1135 // Save changed parts of map
1136 m_env->getMap().save(MOD_STATE_WRITE_NEEDED);
1139 m_env->saveLoadedPlayers();
1141 // Save environment metadata
1147 void Server::Receive()
1149 DSTACK(__FUNCTION_NAME);
1150 SharedBuffer<u8> data;
1154 datasize = m_con.Receive(peer_id,data);
1155 ProcessData(*data, datasize, peer_id);
1157 catch(con::InvalidIncomingDataException &e) {
1158 infostream<<"Server::Receive(): "
1159 "InvalidIncomingDataException: what()="
1160 <<e.what()<<std::endl;
1162 catch(SerializationError &e) {
1163 infostream<<"Server::Receive(): "
1164 "SerializationError: what()="
1165 <<e.what()<<std::endl;
1167 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) {
1177 PlayerSAO* Server::StageTwoClientInit(u16 peer_id)
1179 std::string playername = "";
1180 PlayerSAO *playersao = NULL;
1183 RemoteClient* client = m_clients.lockedGetClientNoEx(peer_id, CS_InitDone);
1184 if (client != NULL) {
1185 playername = client->getName();
1186 playersao = emergePlayer(playername.c_str(), peer_id);
1188 } catch (std::exception &e) {
1194 RemotePlayer *player =
1195 static_cast<RemotePlayer*>(m_env->getPlayer(peer_id));
1197 // If failed, cancel
1198 if((playersao == NULL) || (player == NULL)) {
1199 if(player && player->peer_id != 0) {
1200 errorstream<<"Server: "<<playername<<": Failed to emerge player"
1201 <<" (player allocated to an another client)"<<std::endl;
1202 DenyAccess(peer_id, L"Another client is connected with this "
1203 L"name. If your client closed unexpectedly, try again in "
1206 errorstream<<"Server: "<<playername<<": Failed to emerge player"
1208 DenyAccess(peer_id, L"Could not allocate player.");
1214 Send complete position information
1216 SendMovePlayer(peer_id);
1219 SendPlayerPrivileges(peer_id);
1221 // Send inventory formspec
1222 SendPlayerInventoryFormspec(peer_id);
1225 UpdateCrafting(peer_id);
1226 SendInventory(peer_id);
1229 if(g_settings->getBool("enable_damage"))
1230 SendPlayerHP(peer_id);
1233 SendPlayerBreath(peer_id);
1235 // Show death screen if necessary
1237 SendDeathscreen(peer_id, false, v3f(0,0,0));
1239 // Note things in chat if not in simple singleplayer mode
1240 if(!m_simple_singleplayer_mode) {
1241 // Send information about server to player in chat
1242 SendChatMessage(peer_id, getStatusString());
1244 // Send information about joining in chat
1246 std::wstring name = L"unknown";
1247 Player *player = m_env->getPlayer(peer_id);
1249 name = narrow_to_wide(player->getName());
1251 std::wstring message;
1254 message += L" joined the game.";
1255 SendChatMessage(PEER_ID_INEXISTENT,message);
1258 Address addr = getPeerAddress(player->peer_id);
1259 std::string ip_str = addr.serializeString();
1260 actionstream<<player->getName() <<" [" << ip_str << "] joins game. " << std::endl;
1265 std::vector<std::string> names = m_clients.getPlayerNames();
1267 actionstream<<player->getName() <<" joins game. List of players: ";
1269 for (std::vector<std::string>::iterator i = names.begin();
1270 i != names.end(); i++) {
1271 actionstream << *i << " ";
1274 actionstream << player->getName() <<std::endl;
1279 void Server::handleCommand_Deprecated(ToServerPacket* pkt)
1281 infostream << "Server: " << toServerCommandTable[pkt->getCommand()].name
1282 << " not supported anymore" << std::endl;
1285 void Server::handleCommand_Init(ToServerPacket* pkt)
1287 // [0] u16 TOSERVER_INIT
1288 // [2] u8 SER_FMT_VER_HIGHEST_READ
1289 // [3] u8[20] player_name
1290 // [23] u8[28] password <--- can be sent without this, from old versions
1292 if(pkt->getSize() < 1+PLAYERNAME_SIZE)
1295 RemoteClient* client = getClient(pkt->getPeerId(), CS_Created);
1299 Address address = getPeerAddress(pkt->getPeerId());
1300 addr_s = address.serializeString();
1302 catch (con::PeerNotFoundException &e) {
1304 * no peer for this packet found
1305 * most common reason is peer timeout, e.g. peer didn't
1306 * respond for some time, your server was overloaded or
1309 infostream << "Server::ProcessData(): Cancelling: peer "
1310 << pkt->getPeerId() << " not found" << std::endl;
1314 // If net_proto_version is set, this client has already been handled
1315 if(client->getState() > CS_Created) {
1316 verbosestream << "Server: Ignoring multiple TOSERVER_INITs from "
1317 << addr_s << " (peer_id=" << pkt->getPeerId() << ")" << std::endl;
1321 verbosestream << "Server: Got TOSERVER_INIT from " << addr_s << " (peer_id="
1322 << pkt->getPeerId() << ")" << std::endl;
1324 // Do not allow multiple players in simple singleplayer mode.
1325 // This isn't a perfect way to do it, but will suffice for now
1326 if(m_simple_singleplayer_mode && m_clients.getClientIDs().size() > 1){
1327 infostream << "Server: Not allowing another client (" << addr_s
1328 << ") to connect in simple singleplayer mode" << std::endl;
1329 DenyAccess(pkt->getPeerId(), L"Running in simple singleplayer mode.");
1333 // First byte after command is maximum supported
1334 // serialization version
1339 u8 our_max = SER_FMT_VER_HIGHEST_READ;
1340 // Use the highest version supported by both
1341 int deployed = std::min(client_max, our_max);
1342 // If it's lower than the lowest supported, give up.
1343 if(deployed < SER_FMT_CLIENT_VER_LOWEST)
1344 deployed = SER_FMT_VER_INVALID;
1346 if(deployed == SER_FMT_VER_INVALID) {
1347 actionstream << "Server: A mismatched client tried to connect from "
1348 << addr_s << std::endl;
1349 infostream<<"Server: Cannot negotiate serialization version with "
1350 << addr_s << std::endl;
1351 DenyAccess(pkt->getPeerId(), std::wstring(
1352 L"Your client's version is not supported.\n"
1353 L"Server version is ")
1354 + narrow_to_wide(minetest_version_simple) + L"."
1359 client->setPendingSerializationVersion(deployed);
1362 Read and check network protocol version
1365 u16 min_net_proto_version = 0;
1366 if(pkt->getSize() >= 1 + PLAYERNAME_SIZE + PASSWORD_SIZE + 2)
1367 min_net_proto_version = pkt->getU16(1 + PLAYERNAME_SIZE + PASSWORD_SIZE);
1369 // Use same version as minimum and maximum if maximum version field
1370 // doesn't exist (backwards compatibility)
1371 u16 max_net_proto_version = min_net_proto_version;
1372 if(pkt->getSize() >= 1 + PLAYERNAME_SIZE + PASSWORD_SIZE + 2 + 2)
1373 max_net_proto_version = pkt->getU16(1 + PLAYERNAME_SIZE + PASSWORD_SIZE + 2);
1375 // Start with client's maximum version
1376 u16 net_proto_version = max_net_proto_version;
1378 // Figure out a working version if it is possible at all
1379 if(max_net_proto_version >= SERVER_PROTOCOL_VERSION_MIN ||
1380 min_net_proto_version <= SERVER_PROTOCOL_VERSION_MAX) {
1381 // If maximum is larger than our maximum, go with our maximum
1382 if(max_net_proto_version > SERVER_PROTOCOL_VERSION_MAX)
1383 net_proto_version = SERVER_PROTOCOL_VERSION_MAX;
1384 // Else go with client's maximum
1386 net_proto_version = max_net_proto_version;
1389 verbosestream << "Server: " << addr_s << ": Protocol version: min: "
1390 << min_net_proto_version << ", max: " << max_net_proto_version
1391 << ", chosen: " << net_proto_version << std::endl;
1393 client->net_proto_version = net_proto_version;
1395 if(net_proto_version < SERVER_PROTOCOL_VERSION_MIN ||
1396 net_proto_version > SERVER_PROTOCOL_VERSION_MAX) {
1397 actionstream << "Server: A mismatched client tried to connect from "
1398 << addr_s << std::endl;
1399 DenyAccess(pkt->getPeerId(), std::wstring(
1400 L"Your client's version is not supported.\n"
1401 L"Server version is ")
1402 + narrow_to_wide(minetest_version_simple) + L",\n"
1403 + L"server's PROTOCOL_VERSION is "
1404 + narrow_to_wide(itos(SERVER_PROTOCOL_VERSION_MIN))
1406 + narrow_to_wide(itos(SERVER_PROTOCOL_VERSION_MAX))
1407 + L", client's PROTOCOL_VERSION is "
1408 + narrow_to_wide(itos(min_net_proto_version))
1410 + narrow_to_wide(itos(max_net_proto_version))
1415 if(g_settings->getBool("strict_protocol_version_checking")) {
1416 if(net_proto_version != LATEST_PROTOCOL_VERSION) {
1417 actionstream << "Server: A mismatched (strict) client tried to "
1418 << "connect from " << addr_s << std::endl;
1419 DenyAccess(pkt->getPeerId(), std::wstring(
1420 L"Your client's version is not supported.\n"
1421 L"Server version is ")
1422 + narrow_to_wide(minetest_version_simple) + L",\n"
1423 + L"server's PROTOCOL_VERSION (strict) is "
1424 + narrow_to_wide(itos(LATEST_PROTOCOL_VERSION))
1425 + L", client's PROTOCOL_VERSION is "
1426 + narrow_to_wide(itos(min_net_proto_version))
1428 + narrow_to_wide(itos(max_net_proto_version))
1437 char playername[PLAYERNAME_SIZE];
1438 unsigned int playername_length = 0;
1439 for (; playername_length < PLAYERNAME_SIZE; playername_length++ ) {
1440 playername[playername_length] = pkt->getChar(1+playername_length);
1441 if (pkt->getChar(1+playername_length) == 0)
1445 if (playername_length == PLAYERNAME_SIZE) {
1446 actionstream << "Server: Player with name exceeding max length "
1447 << "tried to connect from " << addr_s << std::endl;
1448 DenyAccess(pkt->getPeerId(), L"Name too long");
1453 if(playername[0]=='\0') {
1454 actionstream << "Server: Player with an empty name "
1455 << "tried to connect from " << addr_s << std::endl;
1456 DenyAccess(pkt->getPeerId(), L"Empty name");
1460 if(string_allowed(playername, PLAYERNAME_ALLOWED_CHARS) == false) {
1461 actionstream << "Server: Player with an invalid name "
1462 << "tried to connect from " << addr_s << std::endl;
1463 DenyAccess(pkt->getPeerId(), L"Name contains unallowed characters");
1467 if(!isSingleplayer() && strcasecmp(playername, "singleplayer") == 0) {
1468 actionstream << "Server: Player with the name \"singleplayer\" "
1469 << "tried to connect from " << addr_s << std::endl;
1470 DenyAccess(pkt->getPeerId(), L"Name is not allowed");
1476 if(m_script->on_prejoinplayer(playername, addr_s, reason)) {
1477 actionstream << "Server: Player with the name \"" << playername << "\" "
1478 << "tried to connect from " << addr_s << " "
1479 << "but it was disallowed for the following reason: "
1480 << reason << std::endl;
1481 DenyAccess(pkt->getPeerId(), narrow_to_wide(reason.c_str()));
1486 infostream<<"Server: New connection: \""<<playername<<"\" from "
1487 <<addr_s<<" (peer_id="<<pkt->getPeerId()<<")"<<std::endl;
1490 char given_password[PASSWORD_SIZE];
1491 if(pkt->getSize() < 1 + PLAYERNAME_SIZE + PASSWORD_SIZE) {
1492 // old version - assume blank password
1493 given_password[0] = 0;
1496 for(u32 i=0; i<PASSWORD_SIZE - 1; i++) {
1497 given_password[i] = pkt->getChar(21 + i);
1499 given_password[PASSWORD_SIZE - 1] = 0;
1502 if(!base64_is_valid(given_password)){
1503 actionstream << "Server: " << playername
1504 << " supplied invalid password hash" << std::endl;
1505 DenyAccess(pkt->getPeerId(), L"Invalid password hash");
1509 // Enforce user limit.
1510 // Don't enforce for users that have some admin right
1511 if(m_clients.getClientIDs(CS_Created).size() >= g_settings->getU16("max_users") &&
1512 !checkPriv(playername, "server") &&
1513 !checkPriv(playername, "ban") &&
1514 !checkPriv(playername, "privs") &&
1515 !checkPriv(playername, "password") &&
1516 playername != g_settings->get("name")) {
1517 actionstream << "Server: " << playername << " tried to join, but there"
1518 << " are already max_users="
1519 << g_settings->getU16("max_users") << " players." << std::endl;
1520 DenyAccess(pkt->getPeerId(), L"Too many users.");
1524 std::string checkpwd; // Password hash to check against
1525 bool has_auth = m_script->getAuth(playername, &checkpwd, NULL);
1527 // If no authentication info exists for user, create it
1529 if(!isSingleplayer() &&
1530 g_settings->getBool("disallow_empty_password") &&
1531 std::string(given_password) == "") {
1532 actionstream << "Server: " << playername
1533 << " supplied empty password" << std::endl;
1534 DenyAccess(pkt->getPeerId(), L"Empty passwords are "
1535 L"disallowed. Set a password and try again.");
1538 std::wstring raw_default_password =
1539 narrow_to_wide(g_settings->get("default_password"));
1540 std::string initial_password =
1541 translatePassword(playername, raw_default_password);
1543 // If default_password is empty, allow any initial password
1544 if (raw_default_password.length() == 0)
1545 initial_password = given_password;
1547 m_script->createAuth(playername, initial_password);
1550 has_auth = m_script->getAuth(playername, &checkpwd, NULL);
1553 actionstream << "Server: " << playername << " cannot be authenticated"
1554 << " (auth handler does not work?)" << std::endl;
1555 DenyAccess(pkt->getPeerId(), L"Not allowed to login");
1559 if(given_password != checkpwd) {
1560 actionstream << "Server: " << playername << " supplied wrong password"
1562 DenyAccess(pkt->getPeerId(), L"Wrong password");
1566 RemotePlayer *player =
1567 static_cast<RemotePlayer*>(m_env->getPlayer(playername));
1569 if(player && player->peer_id != 0) {
1570 errorstream << "Server: " << playername << ": Failed to emerge player"
1571 << " (player allocated to an another client)" << std::endl;
1572 DenyAccess(pkt->getPeerId(), L"Another client is connected with this "
1573 L"name. If your client closed unexpectedly, try again in "
1577 m_clients.setPlayerName(pkt->getPeerId(), playername);
1580 Answer with a TOCLIENT_INIT
1583 SharedBuffer<u8> reply(2 + 1 + 6 + 8 + 4);
1584 writeU16(&reply[0], TOCLIENT_INIT);
1585 writeU8(&reply[2], deployed);
1586 //send dummy pos for legacy reasons only
1587 writeV3S16(&reply[2 + 1], floatToInt(v3f(0,0,0), BS));
1588 writeU64(&reply[2 + 1 + 6], m_env->getServerMap().getSeed());
1589 writeF1000(&reply[2 + 1 + 6 + 8], g_settings->getFloat("dedicated_server_step"));
1592 m_clients.send(pkt->getPeerId(), 0, reply, true);
1593 m_clients.event(pkt->getPeerId(), CSE_Init);
1597 void Server::handleCommand_Init2(ToServerPacket* pkt)
1599 verbosestream << "Server: Got TOSERVER_INIT2 from "
1600 << pkt->getPeerId() << std::endl;
1602 m_clients.event(pkt->getPeerId(), CSE_GotInit2);
1603 u16 protocol_version = m_clients.getProtocolVersion(pkt->getPeerId());
1605 ///// begin compatibility code
1606 PlayerSAO* playersao = NULL;
1607 if (protocol_version <= 22) {
1608 playersao = StageTwoClientInit(pkt->getPeerId());
1610 if (playersao == NULL) {
1612 << "TOSERVER_INIT2 stage 2 client init failed for peer "
1613 << pkt->getPeerId() << std::endl;
1617 ///// end compatibility code
1620 Send some initialization data
1623 infostream << "Server: Sending content to "
1624 << getPlayerName(pkt->getPeerId()) << std::endl;
1626 // Send player movement settings
1627 SendMovement(pkt->getPeerId());
1629 // Send item definitions
1630 SendItemDef(pkt->getPeerId(), m_itemdef, protocol_version);
1632 // Send node definitions
1633 SendNodeDef(pkt->getPeerId(), m_nodedef, protocol_version);
1635 m_clients.event(pkt->getPeerId(), CSE_SetDefinitionsSent);
1637 // Send media announcement
1638 sendMediaAnnouncement(pkt->getPeerId());
1640 // Send detached inventories
1641 sendDetachedInventories(pkt->getPeerId());
1644 u16 time = m_env->getTimeOfDay();
1645 float time_speed = g_settings->getFloat("time_speed");
1646 SendTimeOfDay(pkt->getPeerId(), time, time_speed);
1648 ///// begin compatibility code
1649 if (protocol_version <= 22) {
1650 m_clients.event(pkt->getPeerId(), CSE_SetClientReady);
1651 m_script->on_joinplayer(playersao);
1653 ///// end compatibility code
1655 // Warnings about protocol version can be issued here
1656 if(getClient(pkt->getPeerId())->net_proto_version < LATEST_PROTOCOL_VERSION) {
1657 SendChatMessage(pkt->getPeerId(), L"# Server: WARNING: YOUR CLIENT'S "
1658 L"VERSION MAY NOT BE FULLY COMPATIBLE WITH THIS SERVER!");
1662 void Server::handleCommand_RequestMedia(ToServerPacket* pkt)
1664 std::list<std::string> tosend;
1669 infostream << "Sending " << numfiles << " files to "
1670 << getPlayerName(pkt->getPeerId()) << std::endl;
1671 verbosestream << "TOSERVER_REQUEST_MEDIA: " << std::endl;
1673 for(int i = 0; i < numfiles; i++) {
1678 tosend.push_back(name);
1679 verbosestream << "TOSERVER_REQUEST_MEDIA: requested file "
1680 << name << std::endl;
1683 sendRequestedMedia(pkt->getPeerId(), tosend);
1686 void Server::handleCommand_ReceivedMedia(ToServerPacket* pkt)
1690 void Server::handleCommand_ClientReady(ToServerPacket* pkt)
1692 u16 peer_id = pkt->getPeerId();
1693 u16 peer_proto_ver = getClient(peer_id, CS_InitDone)->net_proto_version;
1695 // clients <= protocol version 22 did not send ready message,
1696 // they're already initialized
1697 if (peer_proto_ver <= 22) {
1698 infostream << "Client sent message not expected by a "
1699 << "client using protocol version <= 22,"
1700 << "disconnecing peer_id: " << peer_id << std::endl;
1701 m_con.DisconnectPeer(peer_id);
1705 PlayerSAO* playersao = StageTwoClientInit(peer_id);
1707 if (playersao == NULL) {
1709 << "TOSERVER_CLIENT_READY stage 2 client init failed for peer_id: "
1710 << peer_id << std::endl;
1711 m_con.DisconnectPeer(peer_id);
1716 if(pkt->getSize() < 8) {
1718 << "TOSERVER_CLIENT_READY client sent inconsistent data, disconnecting peer_id: "
1719 << peer_id << std::endl;
1720 m_con.DisconnectPeer(peer_id);
1724 u8 major_ver, minor_ver, patch_ver;
1725 *pkt >> major_ver >> minor_ver >> patch_ver;
1727 m_clients.setClientVersion(
1728 peer_id, major_ver, minor_ver, patch_ver,
1729 std::string(pkt->getString(6),(u16) pkt->getU8(4)));
1731 m_clients.event(peer_id, CSE_SetClientReady);
1732 m_script->on_joinplayer(playersao);
1735 void Server::handleCommand_GotBlocks(ToServerPacket* pkt)
1737 if(pkt->getSize() < 1)
1751 RemoteClient *client = getClient(pkt->getPeerId());
1753 for(u16 i=0; i<count; i++) {
1754 if((s16)pkt->getSize() < 1 + (i + 1) * 6)
1755 throw con::InvalidIncomingDataException
1756 ("GOTBLOCKS length is too short");
1761 client->GotBlock(p);
1765 void Server::handleCommand_PlayerPos(ToServerPacket* pkt)
1767 if(pkt->getSize() < 12 + 12 + 4 + 4)
1771 s32 f32pitch, f32yaw;
1778 f32 pitch = (f32)f32pitch / 100.0;
1779 f32 yaw = (f32)f32yaw / 100.0;
1782 if(pkt->getSize() >= 12 + 12 + 4 + 4 + 4)
1785 v3f position((f32)ps.X / 100.0, (f32)ps.Y / 100.0, (f32)ps.Z / 100.0);
1786 v3f speed((f32)ss.X / 100.0, (f32)ss.Y / 100.0, (f32)ss.Z / 100.0);
1787 pitch = wrapDegrees(pitch);
1788 yaw = wrapDegrees(yaw);
1790 Player *player = m_env->getPlayer(pkt->getPeerId());
1791 if(player == NULL) {
1792 errorstream << "Server::ProcessData(): Cancelling: "
1793 "No player for peer_id=" << pkt->getPeerId()
1794 << " disconnecting peer!" << std::endl;
1795 m_con.DisconnectPeer(pkt->getPeerId());
1799 PlayerSAO *playersao = player->getPlayerSAO();
1800 if(playersao == NULL) {
1801 errorstream << "Server::ProcessData(): Cancelling: "
1802 "No player object for peer_id=" << pkt->getPeerId()
1803 << " disconnecting peer!" << std::endl;
1804 m_con.DisconnectPeer(pkt->getPeerId());
1808 player->setPosition(position);
1809 player->setSpeed(speed);
1810 player->setPitch(pitch);
1811 player->setYaw(yaw);
1812 player->keyPressed=keyPressed;
1813 player->control.up = (bool)(keyPressed & 1);
1814 player->control.down = (bool)(keyPressed & 2);
1815 player->control.left = (bool)(keyPressed & 4);
1816 player->control.right = (bool)(keyPressed & 8);
1817 player->control.jump = (bool)(keyPressed & 16);
1818 player->control.aux1 = (bool)(keyPressed & 32);
1819 player->control.sneak = (bool)(keyPressed & 64);
1820 player->control.LMB = (bool)(keyPressed & 128);
1821 player->control.RMB = (bool)(keyPressed & 256);
1823 bool cheated = playersao->checkMovementCheat();
1826 m_script->on_cheat(playersao, "moved_too_fast");
1830 void Server::handleCommand_DeletedBlocks(ToServerPacket* pkt)
1832 if(pkt->getSize() < 1)
1846 RemoteClient *client = getClient(pkt->getPeerId());
1848 for(u16 i=0; i<count; i++) {
1849 if((s16)pkt->getSize() < 1 + (i + 1) * 6)
1850 throw con::InvalidIncomingDataException
1851 ("DELETEDBLOCKS length is too short");
1855 client->SetBlockNotSent(p);
1859 void Server::handleCommand_InventoryAction(ToServerPacket* pkt)
1861 Player *player = m_env->getPlayer(pkt->getPeerId());
1862 if(player == NULL) {
1863 errorstream << "Server::ProcessData(): Cancelling: "
1864 "No player for peer_id=" << pkt->getPeerId()
1865 << " disconnecting peer!" << std::endl;
1866 m_con.DisconnectPeer(pkt->getPeerId());
1870 PlayerSAO *playersao = player->getPlayerSAO();
1871 if(playersao == NULL) {
1872 errorstream << "Server::ProcessData(): Cancelling: "
1873 "No player object for peer_id=" << pkt->getPeerId()
1874 << " disconnecting peer!" << std::endl;
1875 m_con.DisconnectPeer(pkt->getPeerId());
1879 // Strip command and create a stream
1880 std::string datastring(pkt->getString(0), pkt->getSize());
1881 verbosestream << "TOSERVER_INVENTORY_ACTION: data=" << datastring
1883 std::istringstream is(datastring, std::ios_base::binary);
1885 InventoryAction *a = InventoryAction::deSerialize(is);
1887 infostream << "TOSERVER_INVENTORY_ACTION: "
1888 << "InventoryAction::deSerialize() returned NULL"
1893 // If something goes wrong, this player is to blame
1894 RollbackScopeActor rollback_scope(m_rollback,
1895 std::string("player:")+player->getName());
1898 Note: Always set inventory not sent, to repair cases
1899 where the client made a bad prediction.
1903 Handle restrictions and special cases of the move action
1905 if(a->getType() == IACTION_MOVE) {
1906 IMoveAction *ma = (IMoveAction*)a;
1908 ma->from_inv.applyCurrentPlayer(player->getName());
1909 ma->to_inv.applyCurrentPlayer(player->getName());
1911 setInventoryModified(ma->from_inv);
1912 setInventoryModified(ma->to_inv);
1914 bool from_inv_is_current_player =
1915 (ma->from_inv.type == InventoryLocation::PLAYER) &&
1916 (ma->from_inv.name == player->getName());
1918 bool to_inv_is_current_player =
1919 (ma->to_inv.type == InventoryLocation::PLAYER) &&
1920 (ma->to_inv.name == player->getName());
1923 Disable moving items out of craftpreview
1925 if(ma->from_list == "craftpreview") {
1926 infostream << "Ignoring IMoveAction from "
1927 << (ma->from_inv.dump()) << ":" << ma->from_list
1928 << " to " << (ma->to_inv.dump()) << ":" << ma->to_list
1929 << " because src is " << ma->from_list << std::endl;
1935 Disable moving items into craftresult and craftpreview
1937 if(ma->to_list == "craftpreview" || ma->to_list == "craftresult") {
1938 infostream << "Ignoring IMoveAction from "
1939 << (ma->from_inv.dump()) << ":" << ma->from_list
1940 << " to " << (ma->to_inv.dump()) << ":" << ma->to_list
1941 << " because dst is " << ma->to_list << std::endl;
1946 // Disallow moving items in elsewhere than player's inventory
1947 // if not allowed to interact
1948 if(!checkPriv(player->getName(), "interact") &&
1949 (!from_inv_is_current_player ||
1950 !to_inv_is_current_player)) {
1951 infostream << "Cannot move outside of player's inventory: "
1952 << "No interact privilege" << std::endl;
1958 Handle restrictions and special cases of the drop action
1960 else if(a->getType() == IACTION_DROP) {
1961 IDropAction *da = (IDropAction*)a;
1963 da->from_inv.applyCurrentPlayer(player->getName());
1965 setInventoryModified(da->from_inv);
1968 Disable dropping items out of craftpreview
1970 if(da->from_list == "craftpreview") {
1971 infostream << "Ignoring IDropAction from "
1972 << (da->from_inv.dump()) << ":" << da->from_list
1973 << " because src is " << da->from_list << std::endl;
1978 // Disallow dropping items if not allowed to interact
1979 if(!checkPriv(player->getName(), "interact")) {
1985 Handle restrictions and special cases of the craft action
1987 else if(a->getType() == IACTION_CRAFT) {
1988 ICraftAction *ca = (ICraftAction*)a;
1990 ca->craft_inv.applyCurrentPlayer(player->getName());
1992 setInventoryModified(ca->craft_inv);
1994 //bool craft_inv_is_current_player =
1995 // (ca->craft_inv.type == InventoryLocation::PLAYER) &&
1996 // (ca->craft_inv.name == player->getName());
1998 // Disallow crafting if not allowed to interact
1999 if(!checkPriv(player->getName(), "interact")) {
2000 infostream << "Cannot craft: "
2001 << "No interact privilege" << std::endl;
2008 a->apply(this, playersao, this);
2013 void Server::handleCommand_ChatMessage(ToServerPacket* pkt)
2023 std::wstring message;
2024 for(u16 i=0; i<len; i++) {
2028 message += (wchar_t)tmp_wchar;
2031 Player *player = m_env->getPlayer(pkt->getPeerId());
2032 if(player == NULL) {
2033 errorstream << "Server::ProcessData(): Cancelling: "
2034 "No player for peer_id=" << pkt->getPeerId()
2035 << " disconnecting peer!" << std::endl;
2036 m_con.DisconnectPeer(pkt->getPeerId());
2040 // If something goes wrong, this player is to blame
2041 RollbackScopeActor rollback_scope(m_rollback,
2042 std::string("player:")+player->getName());
2044 // Get player name of this client
2045 std::wstring name = narrow_to_wide(player->getName());
2048 bool ate = m_script->on_chat_message(player->getName(),
2049 wide_to_narrow(message));
2050 // If script ate the message, don't proceed
2054 // Line to send to players
2056 // Whether to send to the player that sent the line
2057 bool send_to_sender_only = false;
2059 // Commands are implemented in Lua, so only catch invalid
2060 // commands that were not "eaten" and send an error back
2061 if(message[0] == L'/') {
2062 message = message.substr(1);
2063 send_to_sender_only = true;
2064 if(message.length() == 0)
2065 line += L"-!- Empty command";
2067 line += L"-!- Invalid command: " + str_split(message, L' ')[0];
2070 if(checkPriv(player->getName(), "shout")) {
2076 line += L"-!- You don't have permission to shout.";
2077 send_to_sender_only = true;
2084 Send the message to sender
2086 if (send_to_sender_only) {
2087 SendChatMessage(pkt->getPeerId(), line);
2090 Send the message to others
2093 actionstream << "CHAT: " << wide_to_narrow(line)<<std::endl;
2095 std::list<u16> clients = m_clients.getClientIDs();
2097 for(std::list<u16>::iterator
2098 i = clients.begin();
2099 i != clients.end(); ++i) {
2100 if (*i != pkt->getPeerId())
2101 SendChatMessage(*i, line);
2107 void Server::handleCommand_Damage(ToServerPacket* pkt)
2113 Player *player = m_env->getPlayer(pkt->getPeerId());
2114 if(player == NULL) {
2115 errorstream << "Server::ProcessData(): Cancelling: "
2116 "No player for peer_id=" << pkt->getPeerId()
2117 << " disconnecting peer!" << std::endl;
2118 m_con.DisconnectPeer(pkt->getPeerId());
2122 PlayerSAO *playersao = player->getPlayerSAO();
2123 if(playersao == NULL) {
2124 errorstream << "Server::ProcessData(): Cancelling: "
2125 "No player object for peer_id=" << pkt->getPeerId()
2126 << " disconnecting peer!" << std::endl;
2127 m_con.DisconnectPeer(pkt->getPeerId());
2131 if(g_settings->getBool("enable_damage")) {
2132 actionstream << player->getName() << " damaged by "
2133 << (int)damage << " hp at " << PP(player->getPosition() / BS)
2136 playersao->setHP(playersao->getHP() - damage);
2138 if(playersao->getHP() == 0 && playersao->m_hp_not_sent)
2139 DiePlayer(pkt->getPeerId());
2141 if(playersao->m_hp_not_sent)
2142 SendPlayerHP(pkt->getPeerId());
2146 void Server::handleCommand_Breath(ToServerPacket* pkt)
2152 Player *player = m_env->getPlayer(pkt->getPeerId());
2153 if(player == NULL) {
2154 errorstream << "Server::ProcessData(): Cancelling: "
2155 "No player for peer_id=" << pkt->getPeerId()
2156 << " disconnecting peer!" << std::endl;
2157 m_con.DisconnectPeer(pkt->getPeerId());
2161 PlayerSAO *playersao = player->getPlayerSAO();
2162 if(playersao == NULL) {
2163 errorstream << "Server::ProcessData(): Cancelling: "
2164 "No player object for peer_id=" << pkt->getPeerId()
2165 << " disconnecting peer!" << std::endl;
2166 m_con.DisconnectPeer(pkt->getPeerId());
2170 playersao->setBreath(breath);
2171 m_script->player_event(playersao,"breath_changed");
2174 void Server::handleCommand_Password(ToServerPacket* pkt)
2177 [0] u16 TOSERVER_PASSWORD
2178 [2] u8[28] old password
2179 [30] u8[28] new password
2182 if(pkt->getSize() != PASSWORD_SIZE * 2)
2188 for(u32 i=0; i<PASSWORD_SIZE - 1; i++) {
2189 char c = pkt->getChar(i);
2195 for(u32 i=0; i<PASSWORD_SIZE - 1; i++) {
2196 char c = pkt->getChar(PASSWORD_SIZE + i);
2202 Player *player = m_env->getPlayer(pkt->getPeerId());
2203 if(player == NULL) {
2204 errorstream << "Server::ProcessData(): Cancelling: "
2205 "No player for peer_id=" << pkt->getPeerId()
2206 << " disconnecting peer!" << std::endl;
2207 m_con.DisconnectPeer(pkt->getPeerId());
2211 if(!base64_is_valid(newpwd)) {
2212 infostream<<"Server: " << player->getName() <<
2213 " supplied invalid password hash" << std::endl;
2214 // Wrong old password supplied!!
2215 SendChatMessage(pkt->getPeerId(), L"Invalid new password hash supplied. Password NOT changed.");
2219 infostream << "Server: Client requests a password change from "
2220 << "'" << oldpwd << "' to '" << newpwd << "'" << std::endl;
2222 std::string playername = player->getName();
2224 std::string checkpwd;
2225 m_script->getAuth(playername, &checkpwd, NULL);
2227 if(oldpwd != checkpwd) {
2228 infostream << "Server: invalid old password" << std::endl;
2229 // Wrong old password supplied!!
2230 SendChatMessage(pkt->getPeerId(), L"Invalid old password supplied. Password NOT changed.");
2234 bool success = m_script->setPassword(playername, newpwd);
2236 actionstream << player->getName() << " changes password" << std::endl;
2237 SendChatMessage(pkt->getPeerId(), L"Password change successful.");
2239 actionstream << player->getName() << " tries to change password but "
2240 << "it fails" << std::endl;
2241 SendChatMessage(pkt->getPeerId(), L"Password change failed or inavailable.");
2245 void Server::handleCommand_PlayerItem(ToServerPacket* pkt)
2247 if (pkt->getSize() < 2)
2250 Player *player = m_env->getPlayer(pkt->getPeerId());
2251 if(player == NULL) {
2252 errorstream << "Server::ProcessData(): Cancelling: "
2253 "No player for peer_id=" << pkt->getPeerId()
2254 << " disconnecting peer!" << std::endl;
2255 m_con.DisconnectPeer(pkt->getPeerId());
2259 PlayerSAO *playersao = player->getPlayerSAO();
2260 if(playersao == NULL) {
2261 errorstream << "Server::ProcessData(): Cancelling: "
2262 "No player object for peer_id=" << pkt->getPeerId()
2263 << " disconnecting peer!" << std::endl;
2264 m_con.DisconnectPeer(pkt->getPeerId());
2272 playersao->setWieldIndex(item);
2275 void Server::handleCommand_Respawn(ToServerPacket* pkt)
2277 Player *player = m_env->getPlayer(pkt->getPeerId());
2278 if(player == NULL) {
2279 errorstream << "Server::ProcessData(): Cancelling: "
2280 "No player for peer_id=" << pkt->getPeerId()
2281 << " disconnecting peer!" << std::endl;
2282 m_con.DisconnectPeer(pkt->getPeerId());
2286 if(player->hp != 0 || !g_settings->getBool("enable_damage"))
2289 RespawnPlayer(pkt->getPeerId());
2291 actionstream<<player->getName()<<" respawns at "
2292 <<PP(player->getPosition()/BS)<<std::endl;
2294 // ActiveObject is added to environment in AsyncRunStep after
2295 // the previous addition has been succesfully removed
2298 void Server::handleCommand_Interact(ToServerPacket* pkt)
2300 std::string datastring(pkt->getString(0), pkt->getSize());
2301 std::istringstream is(datastring, std::ios_base::binary);
2307 [5] u32 length of the next item
2308 [9] serialized PointedThing
2310 0: start digging (from undersurface) or use
2311 1: stop digging (all parameters ignored)
2312 2: digging completed
2313 3: place block or item (to abovesurface)
2316 u8 action = readU8(is);
2317 u16 item_i = readU16(is);
2318 std::istringstream tmp_is(deSerializeLongString(is), std::ios::binary);
2319 PointedThing pointed;
2320 pointed.deSerialize(tmp_is);
2322 verbosestream << "TOSERVER_INTERACT: action=" << (int)action << ", item="
2323 << item_i << ", pointed=" << pointed.dump() << std::endl;
2325 Player *player = m_env->getPlayer(pkt->getPeerId());
2326 if(player == NULL) {
2327 errorstream << "Server::ProcessData(): Cancelling: "
2328 "No player for peer_id=" << pkt->getPeerId()
2329 << " disconnecting peer!" << std::endl;
2330 m_con.DisconnectPeer(pkt->getPeerId());
2334 PlayerSAO *playersao = player->getPlayerSAO();
2335 if(playersao == NULL) {
2336 errorstream << "Server::ProcessData(): Cancelling: "
2337 "No player object for peer_id=" << pkt->getPeerId()
2338 << " disconnecting peer!" << std::endl;
2339 m_con.DisconnectPeer(pkt->getPeerId());
2343 if(player->hp == 0) {
2344 verbosestream << "TOSERVER_INTERACT: " << player->getName()
2345 << " tried to interact, but is dead!" << std::endl;
2349 v3f player_pos = playersao->getLastGoodPosition();
2351 // Update wielded item
2352 playersao->setWieldIndex(item_i);
2354 // Get pointed to node (undefined if not POINTEDTYPE_NODE)
2355 v3s16 p_under = pointed.node_undersurface;
2356 v3s16 p_above = pointed.node_abovesurface;
2358 // Get pointed to object (NULL if not POINTEDTYPE_OBJECT)
2359 ServerActiveObject *pointed_object = NULL;
2360 if(pointed.type == POINTEDTHING_OBJECT) {
2361 pointed_object = m_env->getActiveObject(pointed.object_id);
2362 if(pointed_object == NULL) {
2363 verbosestream << "TOSERVER_INTERACT: "
2364 "pointed object is NULL" << std::endl;
2370 v3f pointed_pos_under = player_pos;
2371 v3f pointed_pos_above = player_pos;
2372 if(pointed.type == POINTEDTHING_NODE) {
2373 pointed_pos_under = intToFloat(p_under, BS);
2374 pointed_pos_above = intToFloat(p_above, BS);
2376 else if(pointed.type == POINTEDTHING_OBJECT) {
2377 pointed_pos_under = pointed_object->getBasePosition();
2378 pointed_pos_above = pointed_pos_under;
2382 Check that target is reasonably close
2383 (only when digging or placing things)
2385 if(action == 0 || action == 2 || action == 3) {
2386 float d = player_pos.getDistanceFrom(pointed_pos_under);
2387 float max_d = BS * 14; // Just some large enough value
2389 actionstream << "Player " << player->getName()
2390 << " tried to access " << pointed.dump()
2391 << " from too far: "
2392 << "d=" << d <<", max_d=" << max_d
2393 << ". ignoring." << std::endl;
2394 // Re-send block to revert change on client-side
2395 RemoteClient *client = getClient(pkt->getPeerId());
2396 v3s16 blockpos = getNodeBlockPos(floatToInt(pointed_pos_under, BS));
2397 client->SetBlockNotSent(blockpos);
2399 m_script->on_cheat(playersao, "interacted_too_far");
2406 Make sure the player is allowed to do it
2408 if(!checkPriv(player->getName(), "interact")) {
2409 actionstream<<player->getName()<<" attempted to interact with "
2410 <<pointed.dump()<<" without 'interact' privilege"
2412 // Re-send block to revert change on client-side
2413 RemoteClient *client = getClient(pkt->getPeerId());
2414 // Digging completed -> under
2416 v3s16 blockpos = getNodeBlockPos(floatToInt(pointed_pos_under, BS));
2417 client->SetBlockNotSent(blockpos);
2419 // Placement -> above
2421 v3s16 blockpos = getNodeBlockPos(floatToInt(pointed_pos_above, BS));
2422 client->SetBlockNotSent(blockpos);
2428 If something goes wrong, this player is to blame
2430 RollbackScopeActor rollback_scope(m_rollback,
2431 std::string("player:")+player->getName());
2434 0: start digging or punch object
2437 if(pointed.type == POINTEDTHING_NODE) {
2439 NOTE: This can be used in the future to check if
2440 somebody is cheating, by checking the timing.
2442 MapNode n(CONTENT_IGNORE);
2444 n = m_env->getMap().getNodeNoEx(p_under, &pos_ok);
2446 n = m_env->getMap().getNodeNoEx(p_under, &pos_ok);
2449 infostream << "Server: Not punching: Node not found."
2450 << " Adding block to emerge queue."
2452 m_emerge->enqueueBlockEmerge(pkt->getPeerId(), getNodeBlockPos(p_above), false);
2455 if(n.getContent() != CONTENT_IGNORE)
2456 m_script->node_on_punch(p_under, n, playersao, pointed);
2458 playersao->noCheatDigStart(p_under);
2460 else if(pointed.type == POINTEDTHING_OBJECT) {
2461 // Skip if object has been removed
2462 if(pointed_object->m_removed)
2465 actionstream<<player->getName()<<" punches object "
2466 <<pointed.object_id<<": "
2467 <<pointed_object->getDescription()<<std::endl;
2469 ItemStack punchitem = playersao->getWieldedItem();
2470 ToolCapabilities toolcap =
2471 punchitem.getToolCapabilities(m_itemdef);
2472 v3f dir = (pointed_object->getBasePosition() -
2473 (player->getPosition() + player->getEyeOffset())
2475 float time_from_last_punch =
2476 playersao->resetTimeFromLastPunch();
2477 pointed_object->punch(dir, &toolcap, playersao,
2478 time_from_last_punch);
2486 else if(action == 1) {
2490 2: Digging completed
2492 else if(action == 2) {
2493 // Only digging of nodes
2494 if(pointed.type == POINTEDTHING_NODE) {
2496 MapNode n = m_env->getMap().getNodeNoEx(p_under, &pos_ok);
2498 infostream << "Server: Not finishing digging: Node not found."
2499 << " Adding block to emerge queue."
2501 m_emerge->enqueueBlockEmerge(pkt->getPeerId(), getNodeBlockPos(p_above), false);
2504 /* Cheat prevention */
2505 bool is_valid_dig = true;
2506 if(!isSingleplayer() && !g_settings->getBool("disable_anticheat")) {
2507 v3s16 nocheat_p = playersao->getNoCheatDigPos();
2508 float nocheat_t = playersao->getNoCheatDigTime();
2509 playersao->noCheatDigEnd();
2510 // If player didn't start digging this, ignore dig
2511 if(nocheat_p != p_under) {
2512 infostream << "Server: NoCheat: " << player->getName()
2513 << " started digging "
2514 << PP(nocheat_p) << " and completed digging "
2515 << PP(p_under) << "; not digging." << std::endl;
2516 is_valid_dig = false;
2518 m_script->on_cheat(playersao, "finished_unknown_dig");
2520 // Get player's wielded item
2521 ItemStack playeritem;
2522 InventoryList *mlist = playersao->getInventory()->getList("main");
2524 playeritem = mlist->getItem(playersao->getWieldIndex());
2525 ToolCapabilities playeritem_toolcap =
2526 playeritem.getToolCapabilities(m_itemdef);
2527 // Get diggability and expected digging time
2528 DigParams params = getDigParams(m_nodedef->get(n).groups,
2529 &playeritem_toolcap);
2530 // If can't dig, try hand
2531 if(!params.diggable) {
2532 const ItemDefinition &hand = m_itemdef->get("");
2533 const ToolCapabilities *tp = hand.tool_capabilities;
2535 params = getDigParams(m_nodedef->get(n).groups, tp);
2537 // If can't dig, ignore dig
2538 if(!params.diggable) {
2539 infostream << "Server: NoCheat: " << player->getName()
2540 << " completed digging " << PP(p_under)
2541 << ", which is not diggable with tool. not digging."
2543 is_valid_dig = false;
2545 m_script->on_cheat(playersao, "dug_unbreakable");
2547 // Check digging time
2548 // If already invalidated, we don't have to
2550 // Well not our problem then
2552 // Clean and long dig
2553 else if(params.time > 2.0 && nocheat_t * 1.2 > params.time) {
2554 // All is good, but grab time from pool; don't care if
2555 // it's actually available
2556 playersao->getDigPool().grab(params.time);
2558 // Short or laggy dig
2559 // Try getting the time from pool
2560 else if(playersao->getDigPool().grab(params.time)) {
2565 infostream << "Server: NoCheat: " << player->getName()
2566 << " completed digging " << PP(p_under)
2567 << "too fast; not digging." << std::endl;
2568 is_valid_dig = false;
2570 m_script->on_cheat(playersao, "dug_too_fast");
2574 /* Actually dig node */
2576 if(is_valid_dig && n.getContent() != CONTENT_IGNORE)
2577 m_script->node_on_dig(p_under, n, playersao);
2579 v3s16 blockpos = getNodeBlockPos(floatToInt(pointed_pos_under, BS));
2580 RemoteClient *client = getClient(pkt->getPeerId());
2581 // Send unusual result (that is, node not being removed)
2582 if(m_env->getMap().getNodeNoEx(p_under).getContent() != CONTENT_AIR) {
2583 // Re-send block to revert change on client-side
2584 client->SetBlockNotSent(blockpos);
2587 client->ResendBlockIfOnWire(blockpos);
2593 3: place block or right-click object
2595 else if(action == 3) {
2596 ItemStack item = playersao->getWieldedItem();
2598 // Reset build time counter
2599 if(pointed.type == POINTEDTHING_NODE &&
2600 item.getDefinition(m_itemdef).type == ITEM_NODE)
2601 getClient(pkt->getPeerId())->m_time_from_building = 0.0;
2603 if(pointed.type == POINTEDTHING_OBJECT) {
2604 // Right click object
2606 // Skip if object has been removed
2607 if(pointed_object->m_removed)
2610 actionstream << player->getName() << " right-clicks object "
2611 << pointed.object_id << ": "
2612 << pointed_object->getDescription() << std::endl;
2615 pointed_object->rightClick(playersao);
2617 else if(m_script->item_OnPlace(
2618 item, playersao, pointed)) {
2619 // Placement was handled in lua
2621 // Apply returned ItemStack
2622 playersao->setWieldedItem(item);
2625 // If item has node placement prediction, always send the
2626 // blocks to make sure the client knows what exactly happened
2627 RemoteClient *client = getClient(pkt->getPeerId());
2628 v3s16 blockpos = getNodeBlockPos(floatToInt(pointed_pos_above, BS));
2629 v3s16 blockpos2 = getNodeBlockPos(floatToInt(pointed_pos_under, BS));
2630 if(item.getDefinition(m_itemdef).node_placement_prediction != "") {
2631 client->SetBlockNotSent(blockpos);
2632 if(blockpos2 != blockpos) {
2633 client->SetBlockNotSent(blockpos2);
2637 client->ResendBlockIfOnWire(blockpos);
2638 if(blockpos2 != blockpos) {
2639 client->ResendBlockIfOnWire(blockpos2);
2647 else if(action == 4) {
2648 ItemStack item = playersao->getWieldedItem();
2650 actionstream << player->getName() << " uses " << item.name
2651 << ", pointing at " << pointed.dump() << std::endl;
2653 if(m_script->item_OnUse(
2654 item, playersao, pointed)) {
2655 // Apply returned ItemStack
2656 playersao->setWieldedItem(item);
2663 Catch invalid actions
2666 infostream << "WARNING: Server: Invalid action "
2667 << action << std::endl;
2671 void Server::handleCommand_RemovedSounds(ToServerPacket* pkt)
2675 for(int k=0; k<num; k++) {
2680 std::map<s32, ServerPlayingSound>::iterator i =
2681 m_playing_sounds.find(id);
2683 if(i == m_playing_sounds.end())
2686 ServerPlayingSound &psound = i->second;
2687 psound.clients.erase(pkt->getPeerId());
2688 if(psound.clients.empty())
2689 m_playing_sounds.erase(i++);
2693 void Server::handleCommand_NodeMetaFields(ToServerPacket* pkt)
2696 std::string formname;
2699 *pkt >> p >> formname >> num;
2701 std::map<std::string, std::string> fields;
2702 for(int k=0; k<num; k++) {
2703 std::string fieldname;
2705 fields[fieldname] = pkt->readLongString();
2708 Player *player = m_env->getPlayer(pkt->getPeerId());
2709 if(player == NULL) {
2710 errorstream << "Server::ProcessData(): Cancelling: "
2711 "No player for peer_id=" << pkt->getPeerId()
2712 << " disconnecting peer!" << std::endl;
2713 m_con.DisconnectPeer(pkt->getPeerId());
2717 PlayerSAO *playersao = player->getPlayerSAO();
2718 if(playersao == NULL) {
2719 errorstream << "Server::ProcessData(): Cancelling: "
2720 "No player object for peer_id=" << pkt->getPeerId()
2721 << " disconnecting peer!" << std::endl;
2722 m_con.DisconnectPeer(pkt->getPeerId());
2726 // If something goes wrong, this player is to blame
2727 RollbackScopeActor rollback_scope(m_rollback,
2728 std::string("player:")+player->getName());
2730 // Check the target node for rollback data; leave others unnoticed
2731 RollbackNode rn_old(&m_env->getMap(), p, this);
2733 m_script->node_on_receive_fields(p, formname, fields, playersao);
2735 // Report rollback data
2736 RollbackNode rn_new(&m_env->getMap(), p, this);
2737 if(rollback() && rn_new != rn_old){
2738 RollbackAction action;
2739 action.setSetNode(p, rn_old, rn_new);
2740 rollback()->reportAction(action);
2744 void Server::handleCommand_InventoryFields(ToServerPacket* pkt)
2746 std::string formname;
2749 *pkt >> formname >> num;
2751 std::map<std::string, std::string> fields;
2752 for(int k=0; k<num; k++) {
2753 std::string fieldname;
2755 fields[fieldname] = pkt->readLongString();
2758 Player *player = m_env->getPlayer(pkt->getPeerId());
2759 if(player == NULL) {
2760 errorstream << "Server::ProcessData(): Cancelling: "
2761 "No player for peer_id=" << pkt->getPeerId()
2762 << " disconnecting peer!" << std::endl;
2763 m_con.DisconnectPeer(pkt->getPeerId());
2767 PlayerSAO *playersao = player->getPlayerSAO();
2768 if(playersao == NULL) {
2769 errorstream << "Server::ProcessData(): Cancelling: "
2770 "No player object for peer_id=" << pkt->getPeerId()
2771 << " disconnecting peer!" << std::endl;
2772 m_con.DisconnectPeer(pkt->getPeerId());
2776 m_script->on_playerReceiveFields(playersao, formname, fields);
2779 inline void Server::handleCommand(ToServerPacket* pkt)
2781 const ToServerCommandHandler& opHandle = toServerCommandTable[pkt->getCommand()];
2782 (this->*opHandle.handler)(pkt);
2785 void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
2787 DSTACK(__FUNCTION_NAME);
2788 // Environment is locked first.
2789 JMutexAutoLock envlock(m_env_mutex);
2791 ScopeProfiler sp(g_profiler, "Server::ProcessData");
2794 Address address = getPeerAddress(peer_id);
2795 std::string addr_s = address.serializeString();
2797 if(m_banmanager->isIpBanned(addr_s)) {
2798 std::string ban_name = m_banmanager->getBanName(addr_s);
2799 infostream << "Server: A banned client tried to connect from "
2800 << addr_s << "; banned name was "
2801 << ban_name << std::endl;
2802 // This actually doesn't seem to transfer to the client
2803 DenyAccess(peer_id, L"Your ip is banned. Banned name was "
2804 + narrow_to_wide(ban_name));
2808 catch(con::PeerNotFoundException &e) {
2810 * no peer for this packet found
2811 * most common reason is peer timeout, e.g. peer didn't
2812 * respond for some time, your server was overloaded or
2815 infostream << "Server::ProcessData(): Cancelling: peer "
2816 << peer_id << " not found" << std::endl;
2824 ToServerPacket* pkt = new ToServerPacket(data, datasize, peer_id);
2826 ToServerCommand command = pkt->getCommand();
2828 // Command must be handled into ToServerCommandHandler
2829 if (command >= TOSERVER_NUM_MSG_TYPES) {
2830 infostream << "Server: Ignoring unknown command "
2831 << command << std::endl;
2834 if (toServerCommandTable[command].state == TOSERVER_STATE_NOT_CONNECTED) {
2840 u8 peer_ser_ver = getClient(peer_id, CS_InitDone)->serialization_version;
2842 if(peer_ser_ver == SER_FMT_VER_INVALID) {
2843 errorstream << "Server::ProcessData(): Cancelling: Peer"
2844 " serialization format invalid or not initialized."
2845 " Skipping incoming command=" << command << std::endl;
2851 /* Handle commands related to client startup */
2852 if (toServerCommandTable[command].state == TOSERVER_STATE_STARTUP) {
2858 if (m_clients.getClientState(peer_id) < CS_Active) {
2859 if (command == TOSERVER_PLAYERPOS) return;
2861 errorstream << "Got packet command: " << command << " for peer id "
2862 << peer_id << " but client isn't active yet. Dropping packet "
2873 catch(SendFailedException &e) {
2874 errorstream << "Server::ProcessData(): SendFailedException: "
2875 << "what=" << e.what()
2880 void Server::setTimeOfDay(u32 time)
2882 m_env->setTimeOfDay(time);
2883 m_time_of_day_send_timer = 0;
2886 void Server::onMapEditEvent(MapEditEvent *event)
2888 if(m_ignore_map_edit_events)
2890 if(m_ignore_map_edit_events_area.contains(event->getArea()))
2892 MapEditEvent *e = event->clone();
2893 m_unsent_map_edit_queue.push_back(e);
2896 Inventory* Server::getInventory(const InventoryLocation &loc)
2899 case InventoryLocation::UNDEFINED:
2900 case InventoryLocation::CURRENT_PLAYER:
2902 case InventoryLocation::PLAYER:
2904 Player *player = m_env->getPlayer(loc.name.c_str());
2907 PlayerSAO *playersao = player->getPlayerSAO();
2910 return playersao->getInventory();
2913 case InventoryLocation::NODEMETA:
2915 NodeMetadata *meta = m_env->getMap().getNodeMetadata(loc.p);
2918 return meta->getInventory();
2921 case InventoryLocation::DETACHED:
2923 if(m_detached_inventories.count(loc.name) == 0)
2925 return m_detached_inventories[loc.name];
2933 void Server::setInventoryModified(const InventoryLocation &loc)
2936 case InventoryLocation::UNDEFINED:
2938 case InventoryLocation::PLAYER:
2940 Player *player = m_env->getPlayer(loc.name.c_str());
2943 PlayerSAO *playersao = player->getPlayerSAO();
2946 playersao->m_inventory_not_sent = true;
2947 playersao->m_wielded_item_not_sent = true;
2950 case InventoryLocation::NODEMETA:
2952 v3s16 blockpos = getNodeBlockPos(loc.p);
2954 MapBlock *block = m_env->getMap().getBlockNoCreateNoEx(blockpos);
2956 block->raiseModified(MOD_STATE_WRITE_NEEDED);
2958 setBlockNotSent(blockpos);
2961 case InventoryLocation::DETACHED:
2963 sendDetachedInventory(loc.name,PEER_ID_INEXISTENT);
2971 void Server::SetBlocksNotSent(std::map<v3s16, MapBlock *>& block)
2973 std::list<u16> clients = m_clients.getClientIDs();
2975 // Set the modified blocks unsent for all the clients
2976 for (std::list<u16>::iterator
2977 i = clients.begin();
2978 i != clients.end(); ++i) {
2979 RemoteClient *client = m_clients.lockedGetClientNoEx(*i);
2981 client->SetBlocksNotSent(block);
2986 void Server::peerAdded(con::Peer *peer)
2988 DSTACK(__FUNCTION_NAME);
2989 verbosestream<<"Server::peerAdded(): peer->id="
2990 <<peer->id<<std::endl;
2993 c.type = con::PEER_ADDED;
2994 c.peer_id = peer->id;
2996 m_peer_change_queue.push_back(c);
2999 void Server::deletingPeer(con::Peer *peer, bool timeout)
3001 DSTACK(__FUNCTION_NAME);
3002 verbosestream<<"Server::deletingPeer(): peer->id="
3003 <<peer->id<<", timeout="<<timeout<<std::endl;
3005 m_clients.event(peer->id, CSE_Disconnect);
3007 c.type = con::PEER_REMOVED;
3008 c.peer_id = peer->id;
3009 c.timeout = timeout;
3010 m_peer_change_queue.push_back(c);
3013 bool Server::getClientConInfo(u16 peer_id, con::rtt_stat_type type, float* retval)
3015 *retval = m_con.getPeerStat(peer_id,type);
3016 if (*retval == -1) return false;
3020 bool Server::getClientInfo(
3029 std::string* vers_string
3032 *state = m_clients.getClientState(peer_id);
3034 RemoteClient* client = m_clients.lockedGetClientNoEx(peer_id, CS_Invalid);
3036 if (client == NULL) {
3041 *uptime = client->uptime();
3042 *ser_vers = client->serialization_version;
3043 *prot_vers = client->net_proto_version;
3045 *major = client->getMajor();
3046 *minor = client->getMinor();
3047 *patch = client->getPatch();
3048 *vers_string = client->getPatch();
3055 void Server::handlePeerChanges()
3057 while(m_peer_change_queue.size() > 0)
3059 con::PeerChange c = m_peer_change_queue.pop_front();
3061 verbosestream<<"Server: Handling peer change: "
3062 <<"id="<<c.peer_id<<", timeout="<<c.timeout
3067 case con::PEER_ADDED:
3068 m_clients.CreateClient(c.peer_id);
3071 case con::PEER_REMOVED:
3072 DeleteClient(c.peer_id, c.timeout?CDR_TIMEOUT:CDR_LEAVE);
3076 assert("Invalid peer change event received!" == 0);
3082 void Server::SendMovement(u16 peer_id)
3084 DSTACK(__FUNCTION_NAME);
3085 std::ostringstream os(std::ios_base::binary);
3087 writeU16(os, TOCLIENT_MOVEMENT);
3088 writeF1000(os, g_settings->getFloat("movement_acceleration_default"));
3089 writeF1000(os, g_settings->getFloat("movement_acceleration_air"));
3090 writeF1000(os, g_settings->getFloat("movement_acceleration_fast"));
3091 writeF1000(os, g_settings->getFloat("movement_speed_walk"));
3092 writeF1000(os, g_settings->getFloat("movement_speed_crouch"));
3093 writeF1000(os, g_settings->getFloat("movement_speed_fast"));
3094 writeF1000(os, g_settings->getFloat("movement_speed_climb"));
3095 writeF1000(os, g_settings->getFloat("movement_speed_jump"));
3096 writeF1000(os, g_settings->getFloat("movement_liquid_fluidity"));
3097 writeF1000(os, g_settings->getFloat("movement_liquid_fluidity_smooth"));
3098 writeF1000(os, g_settings->getFloat("movement_liquid_sink"));
3099 writeF1000(os, g_settings->getFloat("movement_gravity"));
3102 std::string s = os.str();
3103 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3105 m_clients.send(peer_id, 0, data, true);
3108 void Server::SendHP(u16 peer_id, u8 hp)
3110 DSTACK(__FUNCTION_NAME);
3111 std::ostringstream os(std::ios_base::binary);
3113 writeU16(os, TOCLIENT_HP);
3117 std::string s = os.str();
3118 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3120 m_clients.send(peer_id, 0, data, true);
3123 void Server::SendBreath(u16 peer_id, u16 breath)
3125 DSTACK(__FUNCTION_NAME);
3126 std::ostringstream os(std::ios_base::binary);
3128 writeU16(os, TOCLIENT_BREATH);
3129 writeU16(os, breath);
3132 std::string s = os.str();
3133 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3135 m_clients.send(peer_id, 0, data, true);
3138 void Server::SendAccessDenied(u16 peer_id,const std::wstring &reason)
3140 DSTACK(__FUNCTION_NAME);
3141 std::ostringstream os(std::ios_base::binary);
3143 writeU16(os, TOCLIENT_ACCESS_DENIED);
3144 os<<serializeWideString(reason);
3147 std::string s = os.str();
3148 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3150 m_clients.send(peer_id, 0, data, true);
3153 void Server::SendDeathscreen(u16 peer_id,bool set_camera_point_target,
3154 v3f camera_point_target)
3156 DSTACK(__FUNCTION_NAME);
3157 std::ostringstream os(std::ios_base::binary);
3159 writeU16(os, TOCLIENT_DEATHSCREEN);
3160 writeU8(os, set_camera_point_target);
3161 writeV3F1000(os, camera_point_target);
3164 std::string s = os.str();
3165 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3167 m_clients.send(peer_id, 0, data, true);
3170 void Server::SendItemDef(u16 peer_id,
3171 IItemDefManager *itemdef, u16 protocol_version)
3173 DSTACK(__FUNCTION_NAME);
3174 std::ostringstream os(std::ios_base::binary);
3178 u32 length of the next item
3179 zlib-compressed serialized ItemDefManager
3181 writeU16(os, TOCLIENT_ITEMDEF);
3182 std::ostringstream tmp_os(std::ios::binary);
3183 itemdef->serialize(tmp_os, protocol_version);
3184 std::ostringstream tmp_os2(std::ios::binary);
3185 compressZlib(tmp_os.str(), tmp_os2);
3186 os<<serializeLongString(tmp_os2.str());
3189 std::string s = os.str();
3190 verbosestream<<"Server: Sending item definitions to id("<<peer_id
3191 <<"): size="<<s.size()<<std::endl;
3192 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3194 m_clients.send(peer_id, 0, data, true);
3197 void Server::SendNodeDef(u16 peer_id,
3198 INodeDefManager *nodedef, u16 protocol_version)
3200 DSTACK(__FUNCTION_NAME);
3201 std::ostringstream os(std::ios_base::binary);
3205 u32 length of the next item
3206 zlib-compressed serialized NodeDefManager
3208 writeU16(os, TOCLIENT_NODEDEF);
3209 std::ostringstream tmp_os(std::ios::binary);
3210 nodedef->serialize(tmp_os, protocol_version);
3211 std::ostringstream tmp_os2(std::ios::binary);
3212 compressZlib(tmp_os.str(), tmp_os2);
3213 os<<serializeLongString(tmp_os2.str());
3216 std::string s = os.str();
3217 verbosestream<<"Server: Sending node definitions to id("<<peer_id
3218 <<"): size="<<s.size()<<std::endl;
3219 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3221 m_clients.send(peer_id, 0, data, true);
3225 Non-static send methods
3228 void Server::SendInventory(u16 peer_id)
3230 DSTACK(__FUNCTION_NAME);
3232 PlayerSAO *playersao = getPlayerSAO(peer_id);
3235 playersao->m_inventory_not_sent = false;
3241 std::ostringstream os;
3242 playersao->getInventory()->serialize(os);
3244 std::string s = os.str();
3246 SharedBuffer<u8> data(s.size()+2);
3247 writeU16(&data[0], TOCLIENT_INVENTORY);
3248 memcpy(&data[2], s.c_str(), s.size());
3251 m_clients.send(peer_id, 0, data, true);
3254 void Server::SendChatMessage(u16 peer_id, const std::wstring &message)
3256 DSTACK(__FUNCTION_NAME);
3258 std::ostringstream os(std::ios_base::binary);
3262 writeU16(buf, TOCLIENT_CHAT_MESSAGE);
3263 os.write((char*)buf, 2);
3266 writeU16(buf, message.size());
3267 os.write((char*)buf, 2);
3270 for(u32 i=0; i<message.size(); i++)
3274 os.write((char*)buf, 2);
3278 std::string s = os.str();
3279 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3281 if (peer_id != PEER_ID_INEXISTENT)
3284 m_clients.send(peer_id, 0, data, true);
3288 m_clients.sendToAll(0,data,true);
3292 void Server::SendShowFormspecMessage(u16 peer_id, const std::string &formspec,
3293 const std::string &formname)
3295 DSTACK(__FUNCTION_NAME);
3297 std::ostringstream os(std::ios_base::binary);
3302 writeU16(buf, TOCLIENT_SHOW_FORMSPEC);
3303 os.write((char*)buf, 2);
3304 os<<serializeLongString(FORMSPEC_VERSION_STRING + formspec);
3305 os<<serializeString(formname);
3308 std::string s = os.str();
3309 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3311 m_clients.send(peer_id, 0, data, true);
3314 // Spawns a particle on peer with peer_id
3315 void Server::SendSpawnParticle(u16 peer_id, v3f pos, v3f velocity, v3f acceleration,
3316 float expirationtime, float size, bool collisiondetection,
3317 bool vertical, std::string texture)
3319 DSTACK(__FUNCTION_NAME);
3321 std::ostringstream os(std::ios_base::binary);
3322 writeU16(os, TOCLIENT_SPAWN_PARTICLE);
3323 writeV3F1000(os, pos);
3324 writeV3F1000(os, velocity);
3325 writeV3F1000(os, acceleration);
3326 writeF1000(os, expirationtime);
3327 writeF1000(os, size);
3328 writeU8(os, collisiondetection);
3329 os<<serializeLongString(texture);
3330 writeU8(os, vertical);
3333 std::string s = os.str();
3334 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3336 if (peer_id != PEER_ID_INEXISTENT)
3339 m_clients.send(peer_id, 0, data, true);
3343 m_clients.sendToAll(0,data,true);
3347 // Adds a ParticleSpawner on peer with peer_id
3348 void Server::SendAddParticleSpawner(u16 peer_id, u16 amount, float spawntime, v3f minpos, v3f maxpos,
3349 v3f minvel, v3f maxvel, v3f minacc, v3f maxacc, float minexptime, float maxexptime,
3350 float minsize, float maxsize, bool collisiondetection, bool vertical, std::string texture, u32 id)
3352 DSTACK(__FUNCTION_NAME);
3354 std::ostringstream os(std::ios_base::binary);
3355 writeU16(os, TOCLIENT_ADD_PARTICLESPAWNER);
3357 writeU16(os, amount);
3358 writeF1000(os, spawntime);
3359 writeV3F1000(os, minpos);
3360 writeV3F1000(os, maxpos);
3361 writeV3F1000(os, minvel);
3362 writeV3F1000(os, maxvel);
3363 writeV3F1000(os, minacc);
3364 writeV3F1000(os, maxacc);
3365 writeF1000(os, minexptime);
3366 writeF1000(os, maxexptime);
3367 writeF1000(os, minsize);
3368 writeF1000(os, maxsize);
3369 writeU8(os, collisiondetection);
3370 os<<serializeLongString(texture);
3372 writeU8(os, vertical);
3375 std::string s = os.str();
3376 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3378 if (peer_id != PEER_ID_INEXISTENT)
3381 m_clients.send(peer_id, 0, data, true);
3384 m_clients.sendToAll(0,data,true);
3388 void Server::SendDeleteParticleSpawner(u16 peer_id, u32 id)
3390 DSTACK(__FUNCTION_NAME);
3392 std::ostringstream os(std::ios_base::binary);
3393 writeU16(os, TOCLIENT_DELETE_PARTICLESPAWNER);
3398 std::string s = os.str();
3399 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3401 if (peer_id != PEER_ID_INEXISTENT) {
3403 m_clients.send(peer_id, 0, data, true);
3406 m_clients.sendToAll(0,data,true);
3411 void Server::SendHUDAdd(u16 peer_id, u32 id, HudElement *form)
3413 std::ostringstream os(std::ios_base::binary);
3416 writeU16(os, TOCLIENT_HUDADD);
3418 writeU8(os, (u8)form->type);
3419 writeV2F1000(os, form->pos);
3420 os << serializeString(form->name);
3421 writeV2F1000(os, form->scale);
3422 os << serializeString(form->text);
3423 writeU32(os, form->number);
3424 writeU32(os, form->item);
3425 writeU32(os, form->dir);
3426 writeV2F1000(os, form->align);
3427 writeV2F1000(os, form->offset);
3428 writeV3F1000(os, form->world_pos);
3429 writeV2S32(os,form->size);
3432 std::string s = os.str();
3433 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3435 m_clients.send(peer_id, 1, data, true);
3438 void Server::SendHUDRemove(u16 peer_id, u32 id)
3440 std::ostringstream os(std::ios_base::binary);
3443 writeU16(os, TOCLIENT_HUDRM);
3447 std::string s = os.str();
3448 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3451 m_clients.send(peer_id, 1, data, true);
3454 void Server::SendHUDChange(u16 peer_id, u32 id, HudElementStat stat, void *value)
3456 std::ostringstream os(std::ios_base::binary);
3459 writeU16(os, TOCLIENT_HUDCHANGE);
3461 writeU8(os, (u8)stat);
3464 case HUD_STAT_SCALE:
3465 case HUD_STAT_ALIGN:
3466 case HUD_STAT_OFFSET:
3467 writeV2F1000(os, *(v2f *)value);
3471 os << serializeString(*(std::string *)value);
3473 case HUD_STAT_WORLD_POS:
3474 writeV3F1000(os, *(v3f *)value);
3477 writeV2S32(os,*(v2s32 *)value);
3479 case HUD_STAT_NUMBER:
3483 writeU32(os, *(u32 *)value);
3488 std::string s = os.str();
3489 SharedBuffer<u8> data((u8 *)s.c_str(), s.size());
3491 m_clients.send(peer_id, 0, data, true);
3494 void Server::SendHUDSetFlags(u16 peer_id, u32 flags, u32 mask)
3496 std::ostringstream os(std::ios_base::binary);
3499 writeU16(os, TOCLIENT_HUD_SET_FLAGS);
3501 //////////////////////////// compatibility code to be removed //////////////
3502 flags &= ~(HUD_FLAG_HEALTHBAR_VISIBLE | HUD_FLAG_BREATHBAR_VISIBLE);
3503 ////////////////////////////////////////////////////////////////////////////
3504 writeU32(os, flags);
3508 std::string s = os.str();
3509 SharedBuffer<u8> data((u8 *)s.c_str(), s.size());
3511 m_clients.send(peer_id, 0, data, true);
3514 void Server::SendHUDSetParam(u16 peer_id, u16 param, const std::string &value)
3516 std::ostringstream os(std::ios_base::binary);
3519 writeU16(os, TOCLIENT_HUD_SET_PARAM);
3520 writeU16(os, param);
3521 os<<serializeString(value);
3524 std::string s = os.str();
3525 SharedBuffer<u8> data((u8 *)s.c_str(), s.size());
3527 m_clients.send(peer_id, 0, data, true);
3530 void Server::SendSetSky(u16 peer_id, const video::SColor &bgcolor,
3531 const std::string &type, const std::vector<std::string> ¶ms)
3533 std::ostringstream os(std::ios_base::binary);
3536 writeU16(os, TOCLIENT_SET_SKY);
3537 writeARGB8(os, bgcolor);
3538 os<<serializeString(type);
3539 writeU16(os, params.size());
3540 for(size_t i=0; i<params.size(); i++)
3541 os<<serializeString(params[i]);
3544 std::string s = os.str();
3545 SharedBuffer<u8> data((u8 *)s.c_str(), s.size());
3547 m_clients.send(peer_id, 0, data, true);
3550 void Server::SendOverrideDayNightRatio(u16 peer_id, bool do_override,
3553 std::ostringstream os(std::ios_base::binary);
3556 writeU16(os, TOCLIENT_OVERRIDE_DAY_NIGHT_RATIO);
3557 writeU8(os, do_override);
3558 writeU16(os, ratio*65535);
3561 std::string s = os.str();
3562 SharedBuffer<u8> data((u8 *)s.c_str(), s.size());
3564 m_clients.send(peer_id, 0, data, true);
3567 void Server::SendTimeOfDay(u16 peer_id, u16 time, f32 time_speed)
3569 DSTACK(__FUNCTION_NAME);
3572 SharedBuffer<u8> data(2+2+4);
3573 writeU16(&data[0], TOCLIENT_TIME_OF_DAY);
3574 writeU16(&data[2], time);
3575 writeF1000(&data[4], time_speed);
3577 if (peer_id == PEER_ID_INEXISTENT) {
3578 m_clients.sendToAll(0,data,true);
3582 m_clients.send(peer_id, 0, data, true);
3586 void Server::SendPlayerHP(u16 peer_id)
3588 DSTACK(__FUNCTION_NAME);
3589 PlayerSAO *playersao = getPlayerSAO(peer_id);
3591 playersao->m_hp_not_sent = false;
3592 SendHP(peer_id, playersao->getHP());
3593 m_script->player_event(playersao,"health_changed");
3595 // Send to other clients
3596 std::string str = gob_cmd_punched(playersao->readDamage(), playersao->getHP());
3597 ActiveObjectMessage aom(playersao->getId(), true, str);
3598 playersao->m_messages_out.push_back(aom);
3601 void Server::SendPlayerBreath(u16 peer_id)
3603 DSTACK(__FUNCTION_NAME);
3604 PlayerSAO *playersao = getPlayerSAO(peer_id);
3606 playersao->m_breath_not_sent = false;
3607 m_script->player_event(playersao,"breath_changed");
3608 SendBreath(peer_id, playersao->getBreath());
3611 void Server::SendMovePlayer(u16 peer_id)
3613 DSTACK(__FUNCTION_NAME);
3614 Player *player = m_env->getPlayer(peer_id);
3617 std::ostringstream os(std::ios_base::binary);
3618 writeU16(os, TOCLIENT_MOVE_PLAYER);
3619 writeV3F1000(os, player->getPosition());
3620 writeF1000(os, player->getPitch());
3621 writeF1000(os, player->getYaw());
3624 v3f pos = player->getPosition();
3625 f32 pitch = player->getPitch();
3626 f32 yaw = player->getYaw();
3627 verbosestream<<"Server: Sending TOCLIENT_MOVE_PLAYER"
3628 <<" pos=("<<pos.X<<","<<pos.Y<<","<<pos.Z<<")"
3635 std::string s = os.str();
3636 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3638 m_clients.send(peer_id, 0, data, true);
3641 void Server::SendLocalPlayerAnimations(u16 peer_id, v2s32 animation_frames[4], f32 animation_speed)
3643 std::ostringstream os(std::ios_base::binary);
3645 writeU16(os, TOCLIENT_LOCAL_PLAYER_ANIMATIONS);
3646 writeV2S32(os, animation_frames[0]);
3647 writeV2S32(os, animation_frames[1]);
3648 writeV2S32(os, animation_frames[2]);
3649 writeV2S32(os, animation_frames[3]);
3650 writeF1000(os, animation_speed);
3653 std::string s = os.str();
3654 SharedBuffer<u8> data((u8 *)s.c_str(), s.size());
3656 m_clients.send(peer_id, 0, data, true);
3659 void Server::SendEyeOffset(u16 peer_id, v3f first, v3f third)
3661 std::ostringstream os(std::ios_base::binary);
3663 writeU16(os, TOCLIENT_EYE_OFFSET);
3664 writeV3F1000(os, first);
3665 writeV3F1000(os, third);
3668 std::string s = os.str();
3669 SharedBuffer<u8> data((u8 *)s.c_str(), s.size());
3671 m_clients.send(peer_id, 0, data, true);
3673 void Server::SendPlayerPrivileges(u16 peer_id)
3675 Player *player = m_env->getPlayer(peer_id);
3677 if(player->peer_id == PEER_ID_INEXISTENT)
3680 std::set<std::string> privs;
3681 m_script->getAuth(player->getName(), NULL, &privs);
3683 std::ostringstream os(std::ios_base::binary);
3684 writeU16(os, TOCLIENT_PRIVILEGES);
3685 writeU16(os, privs.size());
3686 for(std::set<std::string>::const_iterator i = privs.begin();
3687 i != privs.end(); i++){
3688 os<<serializeString(*i);
3692 std::string s = os.str();
3693 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3695 m_clients.send(peer_id, 0, data, true);
3698 void Server::SendPlayerInventoryFormspec(u16 peer_id)
3700 Player *player = m_env->getPlayer(peer_id);
3702 if(player->peer_id == PEER_ID_INEXISTENT)
3705 std::ostringstream os(std::ios_base::binary);
3706 writeU16(os, TOCLIENT_INVENTORY_FORMSPEC);
3707 os<<serializeLongString(FORMSPEC_VERSION_STRING + player->inventory_formspec);
3710 std::string s = os.str();
3711 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3713 m_clients.send(peer_id, 0, data, true);
3716 s32 Server::playSound(const SimpleSoundSpec &spec,
3717 const ServerSoundParams ¶ms)
3719 // Find out initial position of sound
3720 bool pos_exists = false;
3721 v3f pos = params.getPos(m_env, &pos_exists);
3722 // If position is not found while it should be, cancel sound
3723 if(pos_exists != (params.type != ServerSoundParams::SSP_LOCAL))
3726 // Filter destination clients
3727 std::list<u16> dst_clients;
3728 if(params.to_player != "")
3730 Player *player = m_env->getPlayer(params.to_player.c_str());
3732 infostream<<"Server::playSound: Player \""<<params.to_player
3733 <<"\" not found"<<std::endl;
3736 if(player->peer_id == PEER_ID_INEXISTENT){
3737 infostream<<"Server::playSound: Player \""<<params.to_player
3738 <<"\" not connected"<<std::endl;
3741 dst_clients.push_back(player->peer_id);
3745 std::list<u16> clients = m_clients.getClientIDs();
3747 for(std::list<u16>::iterator
3748 i = clients.begin(); i != clients.end(); ++i)
3750 Player *player = m_env->getPlayer(*i);
3754 if(player->getPosition().getDistanceFrom(pos) >
3755 params.max_hear_distance)
3758 dst_clients.push_back(*i);
3761 if(dst_clients.empty())
3765 s32 id = m_next_sound_id++;
3766 // The sound will exist as a reference in m_playing_sounds
3767 m_playing_sounds[id] = ServerPlayingSound();
3768 ServerPlayingSound &psound = m_playing_sounds[id];
3769 psound.params = params;
3770 for(std::list<u16>::iterator i = dst_clients.begin();
3771 i != dst_clients.end(); i++)
3772 psound.clients.insert(*i);
3774 std::ostringstream os(std::ios_base::binary);
3775 writeU16(os, TOCLIENT_PLAY_SOUND);
3777 os<<serializeString(spec.name);
3778 writeF1000(os, spec.gain * params.gain);
3779 writeU8(os, params.type);
3780 writeV3F1000(os, pos);
3781 writeU16(os, params.object);
3782 writeU8(os, params.loop);
3784 std::string s = os.str();
3785 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3787 for(std::list<u16>::iterator i = dst_clients.begin();
3788 i != dst_clients.end(); i++){
3790 m_clients.send(*i, 0, data, true);
3794 void Server::stopSound(s32 handle)
3796 // Get sound reference
3797 std::map<s32, ServerPlayingSound>::iterator i =
3798 m_playing_sounds.find(handle);
3799 if(i == m_playing_sounds.end())
3801 ServerPlayingSound &psound = i->second;
3803 std::ostringstream os(std::ios_base::binary);
3804 writeU16(os, TOCLIENT_STOP_SOUND);
3805 writeS32(os, handle);
3807 std::string s = os.str();
3808 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3810 for(std::set<u16>::iterator i = psound.clients.begin();
3811 i != psound.clients.end(); i++){
3813 m_clients.send(*i, 0, data, true);
3815 // Remove sound reference
3816 m_playing_sounds.erase(i);
3819 void Server::sendRemoveNode(v3s16 p, u16 ignore_id,
3820 std::list<u16> *far_players, float far_d_nodes)
3822 float maxd = far_d_nodes*BS;
3823 v3f p_f = intToFloat(p, BS);
3827 SharedBuffer<u8> reply(replysize);
3828 writeU16(&reply[0], TOCLIENT_REMOVENODE);
3829 writeS16(&reply[2], p.X);
3830 writeS16(&reply[4], p.Y);
3831 writeS16(&reply[6], p.Z);
3833 std::list<u16> clients = m_clients.getClientIDs();
3834 for(std::list<u16>::iterator
3835 i = clients.begin();
3836 i != clients.end(); ++i)
3841 Player *player = m_env->getPlayer(*i);
3844 // If player is far away, only set modified blocks not sent
3845 v3f player_pos = player->getPosition();
3846 if(player_pos.getDistanceFrom(p_f) > maxd)
3848 far_players->push_back(*i);
3855 m_clients.send(*i, 0, reply, true);
3859 void Server::sendAddNode(v3s16 p, MapNode n, u16 ignore_id,
3860 std::list<u16> *far_players, float far_d_nodes,
3861 bool remove_metadata)
3863 float maxd = far_d_nodes*BS;
3864 v3f p_f = intToFloat(p, BS);
3866 std::list<u16> clients = m_clients.getClientIDs();
3867 for(std::list<u16>::iterator
3868 i = clients.begin();
3869 i != clients.end(); ++i)
3875 Player *player = m_env->getPlayer(*i);
3878 // If player is far away, only set modified blocks not sent
3879 v3f player_pos = player->getPosition();
3880 if(player_pos.getDistanceFrom(p_f) > maxd)
3882 far_players->push_back(*i);
3887 SharedBuffer<u8> reply(0);
3889 RemoteClient* client = m_clients.lockedGetClientNoEx(*i);
3893 u32 replysize = 9 + MapNode::serializedLength(client->serialization_version);
3894 reply = SharedBuffer<u8>(replysize);
3895 writeU16(&reply[0], TOCLIENT_ADDNODE);
3896 writeS16(&reply[2], p.X);
3897 writeS16(&reply[4], p.Y);
3898 writeS16(&reply[6], p.Z);
3899 n.serialize(&reply[8], client->serialization_version);
3900 u32 index = 8 + MapNode::serializedLength(client->serialization_version);
3901 writeU8(&reply[index], remove_metadata ? 0 : 1);
3903 if (!remove_metadata) {
3904 if (client->net_proto_version <= 21) {
3905 // Old clients always clear metadata; fix it
3906 // by sending the full block again.
3907 client->SetBlockNotSent(p);
3914 if (reply.getSize() > 0)
3915 m_clients.send(*i, 0, reply, true);
3919 void Server::setBlockNotSent(v3s16 p)
3921 std::list<u16> clients = m_clients.getClientIDs();
3923 for(std::list<u16>::iterator
3924 i = clients.begin();
3925 i != clients.end(); ++i)
3927 RemoteClient *client = m_clients.lockedGetClientNoEx(*i);
3928 client->SetBlockNotSent(p);
3933 void Server::SendBlockNoLock(u16 peer_id, MapBlock *block, u8 ver, u16 net_proto_version)
3935 DSTACK(__FUNCTION_NAME);
3937 v3s16 p = block->getPos();
3941 bool completely_air = true;
3942 for(s16 z0=0; z0<MAP_BLOCKSIZE; z0++)
3943 for(s16 x0=0; x0<MAP_BLOCKSIZE; x0++)
3944 for(s16 y0=0; y0<MAP_BLOCKSIZE; y0++)
3946 if(block->getNodeNoEx(v3s16(x0,y0,z0)).d != CONTENT_AIR)
3948 completely_air = false;
3949 x0 = y0 = z0 = MAP_BLOCKSIZE; // Break out
3954 infostream<<"Server: Sending block ("<<p.X<<","<<p.Y<<","<<p.Z<<"): ";
3956 infostream<<"[completely air] ";
3957 infostream<<std::endl;
3961 Create a packet with the block in the right format
3964 std::ostringstream os(std::ios_base::binary);
3965 block->serialize(os, ver, false);
3966 block->serializeNetworkSpecific(os, net_proto_version);
3967 std::string s = os.str();
3968 SharedBuffer<u8> blockdata((u8*)s.c_str(), s.size());
3970 u32 replysize = 8 + blockdata.getSize();
3971 SharedBuffer<u8> reply(replysize);
3972 writeU16(&reply[0], TOCLIENT_BLOCKDATA);
3973 writeS16(&reply[2], p.X);
3974 writeS16(&reply[4], p.Y);
3975 writeS16(&reply[6], p.Z);
3976 memcpy(&reply[8], *blockdata, blockdata.getSize());
3978 /*infostream<<"Server: Sending block ("<<p.X<<","<<p.Y<<","<<p.Z<<")"
3979 <<": \tpacket size: "<<replysize<<std::endl;*/
3984 m_clients.send(peer_id, 2, reply, true);
3987 void Server::SendBlocks(float dtime)
3989 DSTACK(__FUNCTION_NAME);
3991 JMutexAutoLock envlock(m_env_mutex);
3992 //TODO check if one big lock could be faster then multiple small ones
3994 ScopeProfiler sp(g_profiler, "Server: sel and send blocks to clients");
3996 std::vector<PrioritySortedBlockTransfer> queue;
3998 s32 total_sending = 0;
4001 ScopeProfiler sp(g_profiler, "Server: selecting blocks for sending");
4003 std::list<u16> clients = m_clients.getClientIDs();
4006 for(std::list<u16>::iterator
4007 i = clients.begin();
4008 i != clients.end(); ++i)
4010 RemoteClient *client = m_clients.lockedGetClientNoEx(*i, CS_Active);
4015 total_sending += client->SendingCount();
4016 client->GetNextBlocks(m_env,m_emerge, dtime, queue);
4022 // Lowest priority number comes first.
4023 // Lowest is most important.
4024 std::sort(queue.begin(), queue.end());
4027 for(u32 i=0; i<queue.size(); i++)
4029 //TODO: Calculate limit dynamically
4030 if(total_sending >= g_settings->getS32
4031 ("max_simultaneous_block_sends_server_total"))
4034 PrioritySortedBlockTransfer q = queue[i];
4036 MapBlock *block = NULL;
4039 block = m_env->getMap().getBlockNoCreate(q.pos);
4041 catch(InvalidPositionException &e)
4046 RemoteClient *client = m_clients.lockedGetClientNoEx(q.peer_id, CS_Active);
4051 SendBlockNoLock(q.peer_id, block, client->serialization_version, client->net_proto_version);
4053 client->SentBlock(q.pos);
4059 void Server::fillMediaCache()
4061 DSTACK(__FUNCTION_NAME);
4063 infostream<<"Server: Calculating media file checksums"<<std::endl;
4065 // Collect all media file paths
4066 std::list<std::string> paths;
4067 for(std::vector<ModSpec>::iterator i = m_mods.begin();
4068 i != m_mods.end(); i++){
4069 const ModSpec &mod = *i;
4070 paths.push_back(mod.path + DIR_DELIM + "textures");
4071 paths.push_back(mod.path + DIR_DELIM + "sounds");
4072 paths.push_back(mod.path + DIR_DELIM + "media");
4073 paths.push_back(mod.path + DIR_DELIM + "models");
4075 paths.push_back(porting::path_user + DIR_DELIM + "textures" + DIR_DELIM + "server");
4077 // Collect media file information from paths into cache
4078 for(std::list<std::string>::iterator i = paths.begin();
4079 i != paths.end(); i++)
4081 std::string mediapath = *i;
4082 std::vector<fs::DirListNode> dirlist = fs::GetDirListing(mediapath);
4083 for(u32 j=0; j<dirlist.size(); j++){
4084 if(dirlist[j].dir) // Ignode dirs
4086 std::string filename = dirlist[j].name;
4087 // If name contains illegal characters, ignore the file
4088 if(!string_allowed(filename, TEXTURENAME_ALLOWED_CHARS)){
4089 infostream<<"Server: ignoring illegal file name: \""
4090 <<filename<<"\""<<std::endl;
4093 // If name is not in a supported format, ignore it
4094 const char *supported_ext[] = {
4095 ".png", ".jpg", ".bmp", ".tga",
4096 ".pcx", ".ppm", ".psd", ".wal", ".rgb",
4098 ".x", ".b3d", ".md2", ".obj",
4101 if(removeStringEnd(filename, supported_ext) == ""){
4102 infostream<<"Server: ignoring unsupported file extension: \""
4103 <<filename<<"\""<<std::endl;
4106 // Ok, attempt to load the file and add to cache
4107 std::string filepath = mediapath + DIR_DELIM + filename;
4109 std::ifstream fis(filepath.c_str(), std::ios_base::binary);
4110 if(fis.good() == false){
4111 errorstream<<"Server::fillMediaCache(): Could not open \""
4112 <<filename<<"\" for reading"<<std::endl;
4115 std::ostringstream tmp_os(std::ios_base::binary);
4119 fis.read(buf, 1024);
4120 std::streamsize len = fis.gcount();
4121 tmp_os.write(buf, len);
4130 errorstream<<"Server::fillMediaCache(): Failed to read \""
4131 <<filename<<"\""<<std::endl;
4134 if(tmp_os.str().length() == 0){
4135 errorstream<<"Server::fillMediaCache(): Empty file \""
4136 <<filepath<<"\""<<std::endl;
4141 sha1.addBytes(tmp_os.str().c_str(), tmp_os.str().length());
4143 unsigned char *digest = sha1.getDigest();
4144 std::string sha1_base64 = base64_encode(digest, 20);
4145 std::string sha1_hex = hex_encode((char*)digest, 20);
4149 this->m_media[filename] = MediaInfo(filepath, sha1_base64);
4150 verbosestream<<"Server: "<<sha1_hex<<" is "<<filename<<std::endl;
4155 struct SendableMediaAnnouncement
4158 std::string sha1_digest;
4160 SendableMediaAnnouncement(const std::string &name_="",
4161 const std::string &sha1_digest_=""):
4163 sha1_digest(sha1_digest_)
4167 void Server::sendMediaAnnouncement(u16 peer_id)
4169 DSTACK(__FUNCTION_NAME);
4171 verbosestream<<"Server: Announcing files to id("<<peer_id<<")"
4174 std::list<SendableMediaAnnouncement> file_announcements;
4176 for(std::map<std::string, MediaInfo>::iterator i = m_media.begin();
4177 i != m_media.end(); i++){
4179 file_announcements.push_back(
4180 SendableMediaAnnouncement(i->first, i->second.sha1_digest));
4184 std::ostringstream os(std::ios_base::binary);
4192 u16 length of sha1_digest
4197 writeU16(os, TOCLIENT_ANNOUNCE_MEDIA);
4198 writeU16(os, file_announcements.size());
4200 for(std::list<SendableMediaAnnouncement>::iterator
4201 j = file_announcements.begin();
4202 j != file_announcements.end(); ++j){
4203 os<<serializeString(j->name);
4204 os<<serializeString(j->sha1_digest);
4206 os<<serializeString(g_settings->get("remote_media"));
4209 std::string s = os.str();
4210 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
4213 m_clients.send(peer_id, 0, data, true);
4216 struct SendableMedia
4222 SendableMedia(const std::string &name_="", const std::string &path_="",
4223 const std::string &data_=""):
4230 void Server::sendRequestedMedia(u16 peer_id,
4231 const std::list<std::string> &tosend)
4233 DSTACK(__FUNCTION_NAME);
4235 verbosestream<<"Server::sendRequestedMedia(): "
4236 <<"Sending files to client"<<std::endl;
4240 // Put 5kB in one bunch (this is not accurate)
4241 u32 bytes_per_bunch = 5000;
4243 std::vector< std::list<SendableMedia> > file_bunches;
4244 file_bunches.push_back(std::list<SendableMedia>());
4246 u32 file_size_bunch_total = 0;
4248 for(std::list<std::string>::const_iterator i = tosend.begin();
4249 i != tosend.end(); ++i)
4251 const std::string &name = *i;
4253 if(m_media.find(name) == m_media.end()){
4254 errorstream<<"Server::sendRequestedMedia(): Client asked for "
4255 <<"unknown file \""<<(name)<<"\""<<std::endl;
4259 //TODO get path + name
4260 std::string tpath = m_media[name].path;
4263 std::ifstream fis(tpath.c_str(), std::ios_base::binary);
4264 if(fis.good() == false){
4265 errorstream<<"Server::sendRequestedMedia(): Could not open \""
4266 <<tpath<<"\" for reading"<<std::endl;
4269 std::ostringstream tmp_os(std::ios_base::binary);
4273 fis.read(buf, 1024);
4274 std::streamsize len = fis.gcount();
4275 tmp_os.write(buf, len);
4276 file_size_bunch_total += len;
4285 errorstream<<"Server::sendRequestedMedia(): Failed to read \""
4286 <<name<<"\""<<std::endl;
4289 /*infostream<<"Server::sendRequestedMedia(): Loaded \""
4290 <<tname<<"\""<<std::endl;*/
4292 file_bunches[file_bunches.size()-1].push_back(
4293 SendableMedia(name, tpath, tmp_os.str()));
4295 // Start next bunch if got enough data
4296 if(file_size_bunch_total >= bytes_per_bunch){
4297 file_bunches.push_back(std::list<SendableMedia>());
4298 file_size_bunch_total = 0;
4303 /* Create and send packets */
4305 u32 num_bunches = file_bunches.size();
4306 for(u32 i=0; i<num_bunches; i++)
4308 std::ostringstream os(std::ios_base::binary);
4312 u16 total number of texture bunches
4313 u16 index of this bunch
4314 u32 number of files in this bunch
4323 writeU16(os, TOCLIENT_MEDIA);
4324 writeU16(os, num_bunches);
4326 writeU32(os, file_bunches[i].size());
4328 for(std::list<SendableMedia>::iterator
4329 j = file_bunches[i].begin();
4330 j != file_bunches[i].end(); ++j){
4331 os<<serializeString(j->name);
4332 os<<serializeLongString(j->data);
4336 std::string s = os.str();
4337 verbosestream<<"Server::sendRequestedMedia(): bunch "
4338 <<i<<"/"<<num_bunches
4339 <<" files="<<file_bunches[i].size()
4340 <<" size=" <<s.size()<<std::endl;
4341 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
4343 m_clients.send(peer_id, 2, data, true);
4347 void Server::sendDetachedInventory(const std::string &name, u16 peer_id)
4349 if(m_detached_inventories.count(name) == 0){
4350 errorstream<<__FUNCTION_NAME<<": \""<<name<<"\" not found"<<std::endl;
4353 Inventory *inv = m_detached_inventories[name];
4355 std::ostringstream os(std::ios_base::binary);
4356 writeU16(os, TOCLIENT_DETACHED_INVENTORY);
4357 os<<serializeString(name);
4361 std::string s = os.str();
4362 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
4364 if (peer_id != PEER_ID_INEXISTENT)
4367 m_clients.send(peer_id, 0, data, true);
4371 m_clients.sendToAll(0,data,true);
4375 void Server::sendDetachedInventories(u16 peer_id)
4377 DSTACK(__FUNCTION_NAME);
4379 for(std::map<std::string, Inventory*>::iterator
4380 i = m_detached_inventories.begin();
4381 i != m_detached_inventories.end(); i++){
4382 const std::string &name = i->first;
4383 //Inventory *inv = i->second;
4384 sendDetachedInventory(name, peer_id);
4392 void Server::DiePlayer(u16 peer_id)
4394 DSTACK(__FUNCTION_NAME);
4396 PlayerSAO *playersao = getPlayerSAO(peer_id);
4399 infostream<<"Server::DiePlayer(): Player "
4400 <<playersao->getPlayer()->getName()
4401 <<" dies"<<std::endl;
4403 playersao->setHP(0);
4405 // Trigger scripted stuff
4406 m_script->on_dieplayer(playersao);
4408 SendPlayerHP(peer_id);
4409 SendDeathscreen(peer_id, false, v3f(0,0,0));
4412 void Server::RespawnPlayer(u16 peer_id)
4414 DSTACK(__FUNCTION_NAME);
4416 PlayerSAO *playersao = getPlayerSAO(peer_id);
4419 infostream<<"Server::RespawnPlayer(): Player "
4420 <<playersao->getPlayer()->getName()
4421 <<" respawns"<<std::endl;
4423 playersao->setHP(PLAYER_MAX_HP);
4424 playersao->setBreath(PLAYER_MAX_BREATH);
4426 bool repositioned = m_script->on_respawnplayer(playersao);
4428 v3f pos = findSpawnPos(m_env->getServerMap());
4429 playersao->setPos(pos);
4433 void Server::DenyAccess(u16 peer_id, const std::wstring &reason)
4435 DSTACK(__FUNCTION_NAME);
4437 SendAccessDenied(peer_id, reason);
4438 m_clients.event(peer_id, CSE_SetDenied);
4439 m_con.DisconnectPeer(peer_id);
4442 void Server::DeleteClient(u16 peer_id, ClientDeletionReason reason)
4444 DSTACK(__FUNCTION_NAME);
4445 std::wstring message;
4448 Clear references to playing sounds
4450 for(std::map<s32, ServerPlayingSound>::iterator
4451 i = m_playing_sounds.begin();
4452 i != m_playing_sounds.end();)
4454 ServerPlayingSound &psound = i->second;
4455 psound.clients.erase(peer_id);
4456 if(psound.clients.empty())
4457 m_playing_sounds.erase(i++);
4462 Player *player = m_env->getPlayer(peer_id);
4464 // Collect information about leaving in chat
4466 if(player != NULL && reason != CDR_DENY)
4468 std::wstring name = narrow_to_wide(player->getName());
4471 message += L" left the game.";
4472 if(reason == CDR_TIMEOUT)
4473 message += L" (timed out)";
4477 /* Run scripts and remove from environment */
4481 PlayerSAO *playersao = player->getPlayerSAO();
4484 m_script->on_leaveplayer(playersao);
4486 playersao->disconnected();
4494 if(player != NULL && reason != CDR_DENY)
4496 std::ostringstream os(std::ios_base::binary);
4497 std::list<u16> clients = m_clients.getClientIDs();
4499 for(std::list<u16>::iterator
4500 i = clients.begin();
4501 i != clients.end(); ++i)
4504 Player *player = m_env->getPlayer(*i);
4507 // Get name of player
4508 os<<player->getName()<<" ";
4511 actionstream<<player->getName()<<" "
4512 <<(reason==CDR_TIMEOUT?"times out.":"leaves game.")
4513 <<" List of players: "<<os.str()<<std::endl;
4517 JMutexAutoLock env_lock(m_env_mutex);
4518 m_clients.DeleteClient(peer_id);
4522 // Send leave chat message to all remaining clients
4523 if(message.length() != 0)
4524 SendChatMessage(PEER_ID_INEXISTENT,message);
4527 void Server::UpdateCrafting(u16 peer_id)
4529 DSTACK(__FUNCTION_NAME);
4531 Player* player = m_env->getPlayer(peer_id);
4534 // Get a preview for crafting
4536 InventoryLocation loc;
4537 loc.setPlayer(player->getName());
4538 getCraftingResult(&player->inventory, preview, false, this);
4539 m_env->getScriptIface()->item_CraftPredict(preview, player->getPlayerSAO(), (&player->inventory)->getList("craft"), loc);
4541 // Put the new preview in
4542 InventoryList *plist = player->inventory.getList("craftpreview");
4544 assert(plist->getSize() >= 1);
4545 plist->changeItem(0, preview);
4548 RemoteClient* Server::getClient(u16 peer_id, ClientState state_min)
4550 RemoteClient *client = getClientNoEx(peer_id,state_min);
4552 throw ClientNotFoundException("Client not found");
4556 RemoteClient* Server::getClientNoEx(u16 peer_id, ClientState state_min)
4558 return m_clients.getClientNoEx(peer_id, state_min);
4561 std::string Server::getPlayerName(u16 peer_id)
4563 Player *player = m_env->getPlayer(peer_id);
4565 return "[id="+itos(peer_id)+"]";
4566 return player->getName();
4569 PlayerSAO* Server::getPlayerSAO(u16 peer_id)
4571 Player *player = m_env->getPlayer(peer_id);
4574 return player->getPlayerSAO();
4577 std::wstring Server::getStatusString()
4579 std::wostringstream os(std::ios_base::binary);
4582 os<<L"version="<<narrow_to_wide(minetest_version_simple);
4584 os<<L", uptime="<<m_uptime.get();
4586 os<<L", max_lag="<<m_env->getMaxLagEstimate();
4587 // Information about clients
4590 std::list<u16> clients = m_clients.getClientIDs();
4591 for(std::list<u16>::iterator i = clients.begin();
4592 i != clients.end(); ++i)
4595 Player *player = m_env->getPlayer(*i);
4596 // Get name of player
4597 std::wstring name = L"unknown";
4599 name = narrow_to_wide(player->getName());
4600 // Add name to information string
4608 if(((ServerMap*)(&m_env->getMap()))->isSavingEnabled() == false)
4609 os<<std::endl<<L"# Server: "<<" WARNING: Map saving is disabled.";
4610 if(g_settings->get("motd") != "")
4611 os<<std::endl<<L"# Server: "<<narrow_to_wide(g_settings->get("motd"));
4615 std::set<std::string> Server::getPlayerEffectivePrivs(const std::string &name)
4617 std::set<std::string> privs;
4618 m_script->getAuth(name, NULL, &privs);
4622 bool Server::checkPriv(const std::string &name, const std::string &priv)
4624 std::set<std::string> privs = getPlayerEffectivePrivs(name);
4625 return (privs.count(priv) != 0);
4628 void Server::reportPrivsModified(const std::string &name)
4631 std::list<u16> clients = m_clients.getClientIDs();
4632 for(std::list<u16>::iterator
4633 i = clients.begin();
4634 i != clients.end(); ++i){
4635 Player *player = m_env->getPlayer(*i);
4636 reportPrivsModified(player->getName());
4639 Player *player = m_env->getPlayer(name.c_str());
4642 SendPlayerPrivileges(player->peer_id);
4643 PlayerSAO *sao = player->getPlayerSAO();
4646 sao->updatePrivileges(
4647 getPlayerEffectivePrivs(name),
4652 void Server::reportInventoryFormspecModified(const std::string &name)
4654 Player *player = m_env->getPlayer(name.c_str());
4657 SendPlayerInventoryFormspec(player->peer_id);
4660 void Server::setIpBanned(const std::string &ip, const std::string &name)
4662 m_banmanager->add(ip, name);
4665 void Server::unsetIpBanned(const std::string &ip_or_name)
4667 m_banmanager->remove(ip_or_name);
4670 std::string Server::getBanDescription(const std::string &ip_or_name)
4672 return m_banmanager->getBanDescription(ip_or_name);
4675 void Server::notifyPlayer(const char *name, const std::wstring &msg)
4677 Player *player = m_env->getPlayer(name);
4681 if (player->peer_id == PEER_ID_INEXISTENT)
4684 SendChatMessage(player->peer_id, msg);
4687 bool Server::showFormspec(const char *playername, const std::string &formspec, const std::string &formname)
4689 Player *player = m_env->getPlayer(playername);
4693 infostream<<"showFormspec: couldn't find player:"<<playername<<std::endl;
4697 SendShowFormspecMessage(player->peer_id, formspec, formname);
4701 u32 Server::hudAdd(Player *player, HudElement *form) {
4705 u32 id = player->addHud(form);
4707 SendHUDAdd(player->peer_id, id, form);
4712 bool Server::hudRemove(Player *player, u32 id) {
4716 HudElement* todel = player->removeHud(id);
4723 SendHUDRemove(player->peer_id, id);
4727 bool Server::hudChange(Player *player, u32 id, HudElementStat stat, void *data) {
4731 SendHUDChange(player->peer_id, id, stat, data);
4735 bool Server::hudSetFlags(Player *player, u32 flags, u32 mask) {
4739 SendHUDSetFlags(player->peer_id, flags, mask);
4740 player->hud_flags = flags;
4742 PlayerSAO* playersao = player->getPlayerSAO();
4744 if (playersao == NULL)
4747 m_script->player_event(playersao, "hud_changed");
4751 bool Server::hudSetHotbarItemcount(Player *player, s32 hotbar_itemcount) {
4754 if (hotbar_itemcount <= 0 || hotbar_itemcount > HUD_HOTBAR_ITEMCOUNT_MAX)
4757 std::ostringstream os(std::ios::binary);
4758 writeS32(os, hotbar_itemcount);
4759 SendHUDSetParam(player->peer_id, HUD_PARAM_HOTBAR_ITEMCOUNT, os.str());
4763 void Server::hudSetHotbarImage(Player *player, std::string name) {
4767 SendHUDSetParam(player->peer_id, HUD_PARAM_HOTBAR_IMAGE, name);
4770 void Server::hudSetHotbarSelectedImage(Player *player, std::string name) {
4774 SendHUDSetParam(player->peer_id, HUD_PARAM_HOTBAR_SELECTED_IMAGE, name);
4777 bool Server::setLocalPlayerAnimations(Player *player, v2s32 animation_frames[4], f32 frame_speed)
4782 SendLocalPlayerAnimations(player->peer_id, animation_frames, frame_speed);
4786 bool Server::setPlayerEyeOffset(Player *player, v3f first, v3f third)
4791 SendEyeOffset(player->peer_id, first, third);
4795 bool Server::setSky(Player *player, const video::SColor &bgcolor,
4796 const std::string &type, const std::vector<std::string> ¶ms)
4801 SendSetSky(player->peer_id, bgcolor, type, params);
4805 bool Server::overrideDayNightRatio(Player *player, bool do_override,
4811 SendOverrideDayNightRatio(player->peer_id, do_override, ratio);
4815 void Server::notifyPlayers(const std::wstring &msg)
4817 SendChatMessage(PEER_ID_INEXISTENT,msg);
4820 void Server::spawnParticle(const char *playername, v3f pos,
4821 v3f velocity, v3f acceleration,
4822 float expirationtime, float size, bool
4823 collisiondetection, bool vertical, std::string texture)
4825 Player *player = m_env->getPlayer(playername);
4828 SendSpawnParticle(player->peer_id, pos, velocity, acceleration,
4829 expirationtime, size, collisiondetection, vertical, texture);
4832 void Server::spawnParticleAll(v3f pos, v3f velocity, v3f acceleration,
4833 float expirationtime, float size,
4834 bool collisiondetection, bool vertical, std::string texture)
4836 SendSpawnParticle(PEER_ID_INEXISTENT,pos, velocity, acceleration,
4837 expirationtime, size, collisiondetection, vertical, texture);
4840 u32 Server::addParticleSpawner(const char *playername,
4841 u16 amount, float spawntime,
4842 v3f minpos, v3f maxpos,
4843 v3f minvel, v3f maxvel,
4844 v3f minacc, v3f maxacc,
4845 float minexptime, float maxexptime,
4846 float minsize, float maxsize,
4847 bool collisiondetection, bool vertical, std::string texture)
4849 Player *player = m_env->getPlayer(playername);
4854 for(;;) // look for unused particlespawner id
4857 if (std::find(m_particlespawner_ids.begin(),
4858 m_particlespawner_ids.end(), id)
4859 == m_particlespawner_ids.end())
4861 m_particlespawner_ids.push_back(id);
4866 SendAddParticleSpawner(player->peer_id, amount, spawntime,
4867 minpos, maxpos, minvel, maxvel, minacc, maxacc,
4868 minexptime, maxexptime, minsize, maxsize,
4869 collisiondetection, vertical, texture, id);
4874 u32 Server::addParticleSpawnerAll(u16 amount, float spawntime,
4875 v3f minpos, v3f maxpos,
4876 v3f minvel, v3f maxvel,
4877 v3f minacc, v3f maxacc,
4878 float minexptime, float maxexptime,
4879 float minsize, float maxsize,
4880 bool collisiondetection, bool vertical, std::string texture)
4883 for(;;) // look for unused particlespawner id
4886 if (std::find(m_particlespawner_ids.begin(),
4887 m_particlespawner_ids.end(), id)
4888 == m_particlespawner_ids.end())
4890 m_particlespawner_ids.push_back(id);
4895 SendAddParticleSpawner(PEER_ID_INEXISTENT, amount, spawntime,
4896 minpos, maxpos, minvel, maxvel, minacc, maxacc,
4897 minexptime, maxexptime, minsize, maxsize,
4898 collisiondetection, vertical, texture, id);
4903 void Server::deleteParticleSpawner(const char *playername, u32 id)
4905 Player *player = m_env->getPlayer(playername);
4909 m_particlespawner_ids.erase(
4910 std::remove(m_particlespawner_ids.begin(),
4911 m_particlespawner_ids.end(), id),
4912 m_particlespawner_ids.end());
4913 SendDeleteParticleSpawner(player->peer_id, id);
4916 void Server::deleteParticleSpawnerAll(u32 id)
4918 m_particlespawner_ids.erase(
4919 std::remove(m_particlespawner_ids.begin(),
4920 m_particlespawner_ids.end(), id),
4921 m_particlespawner_ids.end());
4922 SendDeleteParticleSpawner(PEER_ID_INEXISTENT, id);
4925 Inventory* Server::createDetachedInventory(const std::string &name)
4927 if(m_detached_inventories.count(name) > 0){
4928 infostream<<"Server clearing detached inventory \""<<name<<"\""<<std::endl;
4929 delete m_detached_inventories[name];
4931 infostream<<"Server creating detached inventory \""<<name<<"\""<<std::endl;
4933 Inventory *inv = new Inventory(m_itemdef);
4935 m_detached_inventories[name] = inv;
4936 //TODO find a better way to do this
4937 sendDetachedInventory(name,PEER_ID_INEXISTENT);
4944 BoolScopeSet(bool *dst, bool val):
4947 m_orig_state = *m_dst;
4952 *m_dst = m_orig_state;
4959 // actions: time-reversed list
4960 // Return value: success/failure
4961 bool Server::rollbackRevertActions(const std::list<RollbackAction> &actions,
4962 std::list<std::string> *log)
4964 infostream<<"Server::rollbackRevertActions(len="<<actions.size()<<")"<<std::endl;
4965 ServerMap *map = (ServerMap*)(&m_env->getMap());
4967 // Fail if no actions to handle
4968 if(actions.empty()){
4969 log->push_back("Nothing to do.");
4976 for(std::list<RollbackAction>::const_iterator
4977 i = actions.begin();
4978 i != actions.end(); i++)
4980 const RollbackAction &action = *i;
4982 bool success = action.applyRevert(map, this, this);
4985 std::ostringstream os;
4986 os<<"Revert of step ("<<num_tried<<") "<<action.toString()<<" failed";
4987 infostream<<"Map::rollbackRevertActions(): "<<os.str()<<std::endl;
4989 log->push_back(os.str());
4991 std::ostringstream os;
4992 os<<"Successfully reverted step ("<<num_tried<<") "<<action.toString();
4993 infostream<<"Map::rollbackRevertActions(): "<<os.str()<<std::endl;
4995 log->push_back(os.str());
4999 infostream<<"Map::rollbackRevertActions(): "<<num_failed<<"/"<<num_tried
5000 <<" failed"<<std::endl;
5002 // Call it done if less than half failed
5003 return num_failed <= num_tried/2;
5006 // IGameDef interface
5008 IItemDefManager* Server::getItemDefManager()
5012 INodeDefManager* Server::getNodeDefManager()
5016 ICraftDefManager* Server::getCraftDefManager()
5020 ITextureSource* Server::getTextureSource()
5024 IShaderSource* Server::getShaderSource()
5028 scene::ISceneManager* Server::getSceneManager()
5033 u16 Server::allocateUnknownNodeId(const std::string &name)
5035 return m_nodedef->allocateDummy(name);
5037 ISoundManager* Server::getSoundManager()
5039 return &dummySoundManager;
5041 MtEventManager* Server::getEventManager()
5046 IWritableItemDefManager* Server::getWritableItemDefManager()
5050 IWritableNodeDefManager* Server::getWritableNodeDefManager()
5054 IWritableCraftDefManager* Server::getWritableCraftDefManager()
5059 const ModSpec* Server::getModSpec(const std::string &modname)
5061 for(std::vector<ModSpec>::iterator i = m_mods.begin();
5062 i != m_mods.end(); i++){
5063 const ModSpec &mod = *i;
5064 if(mod.name == modname)
5069 void Server::getModNames(std::list<std::string> &modlist)
5071 for(std::vector<ModSpec>::iterator i = m_mods.begin(); i != m_mods.end(); i++)
5073 modlist.push_back(i->name);
5076 std::string Server::getBuiltinLuaPath()
5078 return porting::path_share + DIR_DELIM + "builtin";
5081 v3f findSpawnPos(ServerMap &map)
5083 //return v3f(50,50,50)*BS;
5088 nodepos = v2s16(0,0);
5093 s16 water_level = map.getWaterLevel();
5095 // Try to find a good place a few times
5096 for(s32 i=0; i<1000; i++)
5099 // We're going to try to throw the player to this position
5100 v2s16 nodepos2d = v2s16(
5101 -range + (myrand() % (range * 2)),
5102 -range + (myrand() % (range * 2)));
5104 // Get ground height at point
5105 s16 groundheight = map.findGroundLevel(nodepos2d);
5106 if (groundheight <= water_level) // Don't go underwater
5108 if (groundheight > water_level + 6) // Don't go to high places
5111 nodepos = v3s16(nodepos2d.X, groundheight, nodepos2d.Y);
5112 bool is_good = false;
5114 for (s32 i = 0; i < 10; i++) {
5115 v3s16 blockpos = getNodeBlockPos(nodepos);
5116 map.emergeBlock(blockpos, true);
5117 content_t c = map.getNodeNoEx(nodepos).getContent();
5118 if (c == CONTENT_AIR || c == CONTENT_IGNORE) {
5120 if (air_count >= 2){
5128 // Found a good place
5129 //infostream<<"Searched through "<<i<<" places."<<std::endl;
5135 return intToFloat(nodepos, BS);
5138 PlayerSAO* Server::emergePlayer(const char *name, u16 peer_id)
5140 bool newplayer = false;
5143 Try to get an existing player
5145 RemotePlayer *player = static_cast<RemotePlayer*>(m_env->getPlayer(name));
5147 // If player is already connected, cancel
5148 if(player != NULL && player->peer_id != 0)
5150 infostream<<"emergePlayer(): Player already connected"<<std::endl;
5155 If player with the wanted peer_id already exists, cancel.
5157 if(m_env->getPlayer(peer_id) != NULL)
5159 infostream<<"emergePlayer(): Player with wrong name but same"
5160 " peer_id already exists"<<std::endl;
5164 // Load player if it isn't already loaded
5166 player = static_cast<RemotePlayer*>(m_env->loadPlayer(name));
5169 // Create player if it doesn't exist
5172 player = new RemotePlayer(this, name);
5173 // Set player position
5174 infostream<<"Server: Finding spawn place for player \""
5175 <<name<<"\""<<std::endl;
5176 v3f pos = findSpawnPos(m_env->getServerMap());
5177 player->setPosition(pos);
5179 // Make sure the player is saved
5180 player->setModified(true);
5182 // Add player to environment
5183 m_env->addPlayer(player);
5186 // Create a new player active object
5187 PlayerSAO *playersao = new PlayerSAO(m_env, player, peer_id,
5188 getPlayerEffectivePrivs(player->getName()),
5191 /* Clean up old HUD elements from previous sessions */
5194 /* Add object to environment */
5195 m_env->addActiveObject(playersao);
5199 m_script->on_newplayer(playersao);
5205 void dedicated_server_loop(Server &server, bool &kill)
5207 DSTACK(__FUNCTION_NAME);
5209 verbosestream<<"dedicated_server_loop()"<<std::endl;
5211 IntervalLimiter m_profiler_interval;
5215 float steplen = g_settings->getFloat("dedicated_server_step");
5216 // This is kind of a hack but can be done like this
5217 // because server.step() is very light
5219 ScopeProfiler sp(g_profiler, "dedicated server sleep");
5220 sleep_ms((int)(steplen*1000.0));
5222 server.step(steplen);
5224 if(server.getShutdownRequested() || kill)
5226 infostream<<"Dedicated server quitting"<<std::endl;
5228 if(g_settings->getBool("server_announce"))
5229 ServerList::sendAnnounce("delete", server.m_bind_addr.getPort());
5237 float profiler_print_interval =
5238 g_settings->getFloat("profiler_print_interval");
5239 if(profiler_print_interval != 0)
5241 if(m_profiler_interval.step(steplen, profiler_print_interval))
5243 infostream<<"Profiler:"<<std::endl;
5244 g_profiler->print(infostream);
5245 g_profiler->clear();