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(playername.c_str()));
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());
1606 ///// begin compatibility code
1607 PlayerSAO* playersao = NULL;
1608 if (protocol_version <= 22) {
1609 playersao = StageTwoClientInit(pkt->getPeerId());
1611 if (playersao == NULL) {
1613 << "TOSERVER_INIT2 stage 2 client init failed for peer "
1614 << pkt->getPeerId() << std::endl;
1618 ///// end compatibility code
1621 Send some initialization data
1624 infostream << "Server: Sending content to "
1625 << getPlayerName(pkt->getPeerId()) << std::endl;
1627 // Send player movement settings
1628 SendMovement(pkt->getPeerId());
1630 // Send item definitions
1631 SendItemDef(pkt->getPeerId(), m_itemdef, protocol_version);
1633 // Send node definitions
1634 SendNodeDef(pkt->getPeerId(), m_nodedef, protocol_version);
1636 m_clients.event(pkt->getPeerId(), CSE_SetDefinitionsSent);
1638 // Send media announcement
1639 sendMediaAnnouncement(pkt->getPeerId());
1641 // Send detached inventories
1642 sendDetachedInventories(pkt->getPeerId());
1645 u16 time = m_env->getTimeOfDay();
1646 float time_speed = g_settings->getFloat("time_speed");
1647 SendTimeOfDay(pkt->getPeerId(), time, time_speed);
1649 ///// begin compatibility code
1650 if (protocol_version <= 22) {
1651 m_clients.event(pkt->getPeerId(), CSE_SetClientReady);
1652 m_script->on_joinplayer(playersao);
1654 ///// end compatibility code
1656 // Warnings about protocol version can be issued here
1657 if(getClient(pkt->getPeerId())->net_proto_version < LATEST_PROTOCOL_VERSION) {
1658 SendChatMessage(pkt->getPeerId(), L"# Server: WARNING: YOUR CLIENT'S "
1659 L"VERSION MAY NOT BE FULLY COMPATIBLE WITH THIS SERVER!");
1663 void Server::handleCommand_RequestMedia(ToServerPacket* pkt)
1665 std::list<std::string> tosend;
1670 infostream << "Sending " << numfiles << " files to "
1671 << getPlayerName(pkt->getPeerId()) << std::endl;
1672 verbosestream << "TOSERVER_REQUEST_MEDIA: " << std::endl;
1674 for(int i = 0; i < numfiles; i++) {
1679 tosend.push_back(name);
1680 verbosestream << "TOSERVER_REQUEST_MEDIA: requested file "
1681 << name << std::endl;
1684 sendRequestedMedia(pkt->getPeerId(), tosend);
1687 void Server::handleCommand_ReceivedMedia(ToServerPacket* pkt)
1691 void Server::handleCommand_ClientReady(ToServerPacket* pkt)
1693 u16 peer_id = pkt->getPeerId();
1694 u16 peer_proto_ver = getClient(peer_id, CS_InitDone)->net_proto_version;
1696 // clients <= protocol version 22 did not send ready message,
1697 // they're already initialized
1698 if (peer_proto_ver <= 22) {
1699 infostream << "Client sent message not expected by a "
1700 << "client using protocol version <= 22,"
1701 << "disconnecing peer_id: " << peer_id << std::endl;
1702 m_con.DisconnectPeer(peer_id);
1706 PlayerSAO* playersao = StageTwoClientInit(peer_id);
1708 if (playersao == NULL) {
1710 << "TOSERVER_CLIENT_READY stage 2 client init failed for peer_id: "
1711 << peer_id << std::endl;
1712 m_con.DisconnectPeer(peer_id);
1717 if(pkt->getSize() < 8) {
1719 << "TOSERVER_CLIENT_READY client sent inconsistent data, disconnecting peer_id: "
1720 << peer_id << std::endl;
1721 m_con.DisconnectPeer(peer_id);
1725 u8 major_ver, minor_ver, patch_ver;
1726 *pkt >> major_ver >> minor_ver >> patch_ver;
1728 m_clients.setClientVersion(
1729 peer_id, major_ver, minor_ver, patch_ver,
1730 std::string(pkt->getString(6),(u16) pkt->getU8(4)));
1732 m_clients.event(peer_id, CSE_SetClientReady);
1733 m_script->on_joinplayer(playersao);
1736 void Server::handleCommand_GotBlocks(ToServerPacket* pkt)
1738 if(pkt->getSize() < 1)
1752 RemoteClient *client = getClient(pkt->getPeerId());
1754 for(u16 i=0; i<count; i++) {
1755 if((s16)pkt->getSize() < 1 + (i + 1) * 6)
1756 throw con::InvalidIncomingDataException
1757 ("GOTBLOCKS length is too short");
1762 client->GotBlock(p);
1766 void Server::handleCommand_PlayerPos(ToServerPacket* pkt)
1768 if(pkt->getSize() < 12 + 12 + 4 + 4)
1772 s32 f32pitch, f32yaw;
1779 f32 pitch = (f32)f32pitch / 100.0;
1780 f32 yaw = (f32)f32yaw / 100.0;
1783 if(pkt->getSize() >= 12 + 12 + 4 + 4 + 4)
1786 v3f position((f32)ps.X / 100.0, (f32)ps.Y / 100.0, (f32)ps.Z / 100.0);
1787 v3f speed((f32)ss.X / 100.0, (f32)ss.Y / 100.0, (f32)ss.Z / 100.0);
1788 pitch = wrapDegrees(pitch);
1789 yaw = wrapDegrees(yaw);
1791 Player *player = m_env->getPlayer(pkt->getPeerId());
1792 if(player == NULL) {
1793 errorstream << "Server::ProcessData(): Cancelling: "
1794 "No player for peer_id=" << pkt->getPeerId()
1795 << " disconnecting peer!" << std::endl;
1796 m_con.DisconnectPeer(pkt->getPeerId());
1800 PlayerSAO *playersao = player->getPlayerSAO();
1801 if(playersao == NULL) {
1802 errorstream << "Server::ProcessData(): Cancelling: "
1803 "No player object for peer_id=" << pkt->getPeerId()
1804 << " disconnecting peer!" << std::endl;
1805 m_con.DisconnectPeer(pkt->getPeerId());
1809 player->setPosition(position);
1810 player->setSpeed(speed);
1811 player->setPitch(pitch);
1812 player->setYaw(yaw);
1813 player->keyPressed=keyPressed;
1814 player->control.up = (bool)(keyPressed & 1);
1815 player->control.down = (bool)(keyPressed & 2);
1816 player->control.left = (bool)(keyPressed & 4);
1817 player->control.right = (bool)(keyPressed & 8);
1818 player->control.jump = (bool)(keyPressed & 16);
1819 player->control.aux1 = (bool)(keyPressed & 32);
1820 player->control.sneak = (bool)(keyPressed & 64);
1821 player->control.LMB = (bool)(keyPressed & 128);
1822 player->control.RMB = (bool)(keyPressed & 256);
1824 bool cheated = playersao->checkMovementCheat();
1827 m_script->on_cheat(playersao, "moved_too_fast");
1831 void Server::handleCommand_DeletedBlocks(ToServerPacket* pkt)
1833 if(pkt->getSize() < 1)
1847 RemoteClient *client = getClient(pkt->getPeerId());
1849 for(u16 i=0; i<count; i++) {
1850 if((s16)pkt->getSize() < 1 + (i + 1) * 6)
1851 throw con::InvalidIncomingDataException
1852 ("DELETEDBLOCKS length is too short");
1856 client->SetBlockNotSent(p);
1860 void Server::handleCommand_InventoryAction(ToServerPacket* pkt)
1862 Player *player = m_env->getPlayer(pkt->getPeerId());
1863 if(player == NULL) {
1864 errorstream << "Server::ProcessData(): Cancelling: "
1865 "No player for peer_id=" << pkt->getPeerId()
1866 << " disconnecting peer!" << std::endl;
1867 m_con.DisconnectPeer(pkt->getPeerId());
1871 PlayerSAO *playersao = player->getPlayerSAO();
1872 if(playersao == NULL) {
1873 errorstream << "Server::ProcessData(): Cancelling: "
1874 "No player object for peer_id=" << pkt->getPeerId()
1875 << " disconnecting peer!" << std::endl;
1876 m_con.DisconnectPeer(pkt->getPeerId());
1880 // Strip command and create a stream
1881 std::string datastring(pkt->getString(0), pkt->getSize());
1882 verbosestream << "TOSERVER_INVENTORY_ACTION: data=" << datastring
1884 std::istringstream is(datastring, std::ios_base::binary);
1886 InventoryAction *a = InventoryAction::deSerialize(is);
1888 infostream << "TOSERVER_INVENTORY_ACTION: "
1889 << "InventoryAction::deSerialize() returned NULL"
1894 // If something goes wrong, this player is to blame
1895 RollbackScopeActor rollback_scope(m_rollback,
1896 std::string("player:")+player->getName());
1899 Note: Always set inventory not sent, to repair cases
1900 where the client made a bad prediction.
1904 Handle restrictions and special cases of the move action
1906 if(a->getType() == IACTION_MOVE) {
1907 IMoveAction *ma = (IMoveAction*)a;
1909 ma->from_inv.applyCurrentPlayer(player->getName());
1910 ma->to_inv.applyCurrentPlayer(player->getName());
1912 setInventoryModified(ma->from_inv);
1913 setInventoryModified(ma->to_inv);
1915 bool from_inv_is_current_player =
1916 (ma->from_inv.type == InventoryLocation::PLAYER) &&
1917 (ma->from_inv.name == player->getName());
1919 bool to_inv_is_current_player =
1920 (ma->to_inv.type == InventoryLocation::PLAYER) &&
1921 (ma->to_inv.name == player->getName());
1924 Disable moving items out of craftpreview
1926 if(ma->from_list == "craftpreview") {
1927 infostream << "Ignoring IMoveAction from "
1928 << (ma->from_inv.dump()) << ":" << ma->from_list
1929 << " to " << (ma->to_inv.dump()) << ":" << ma->to_list
1930 << " because src is " << ma->from_list << std::endl;
1936 Disable moving items into craftresult and craftpreview
1938 if(ma->to_list == "craftpreview" || ma->to_list == "craftresult") {
1939 infostream << "Ignoring IMoveAction from "
1940 << (ma->from_inv.dump()) << ":" << ma->from_list
1941 << " to " << (ma->to_inv.dump()) << ":" << ma->to_list
1942 << " because dst is " << ma->to_list << std::endl;
1947 // Disallow moving items in elsewhere than player's inventory
1948 // if not allowed to interact
1949 if(!checkPriv(player->getName(), "interact") &&
1950 (!from_inv_is_current_player ||
1951 !to_inv_is_current_player)) {
1952 infostream << "Cannot move outside of player's inventory: "
1953 << "No interact privilege" << std::endl;
1959 Handle restrictions and special cases of the drop action
1961 else if(a->getType() == IACTION_DROP) {
1962 IDropAction *da = (IDropAction*)a;
1964 da->from_inv.applyCurrentPlayer(player->getName());
1966 setInventoryModified(da->from_inv);
1969 Disable dropping items out of craftpreview
1971 if(da->from_list == "craftpreview") {
1972 infostream << "Ignoring IDropAction from "
1973 << (da->from_inv.dump()) << ":" << da->from_list
1974 << " because src is " << da->from_list << std::endl;
1979 // Disallow dropping items if not allowed to interact
1980 if(!checkPriv(player->getName(), "interact")) {
1986 Handle restrictions and special cases of the craft action
1988 else if(a->getType() == IACTION_CRAFT) {
1989 ICraftAction *ca = (ICraftAction*)a;
1991 ca->craft_inv.applyCurrentPlayer(player->getName());
1993 setInventoryModified(ca->craft_inv);
1995 //bool craft_inv_is_current_player =
1996 // (ca->craft_inv.type == InventoryLocation::PLAYER) &&
1997 // (ca->craft_inv.name == player->getName());
1999 // Disallow crafting if not allowed to interact
2000 if(!checkPriv(player->getName(), "interact")) {
2001 infostream << "Cannot craft: "
2002 << "No interact privilege" << std::endl;
2009 a->apply(this, playersao, this);
2014 void Server::handleCommand_ChatMessage(ToServerPacket* pkt)
2024 std::wstring message;
2025 for(u16 i=0; i<len; i++) {
2029 message += (wchar_t)tmp_wchar;
2032 Player *player = m_env->getPlayer(pkt->getPeerId());
2033 if(player == NULL) {
2034 errorstream << "Server::ProcessData(): Cancelling: "
2035 "No player for peer_id=" << pkt->getPeerId()
2036 << " disconnecting peer!" << std::endl;
2037 m_con.DisconnectPeer(pkt->getPeerId());
2041 // If something goes wrong, this player is to blame
2042 RollbackScopeActor rollback_scope(m_rollback,
2043 std::string("player:")+player->getName());
2045 // Get player name of this client
2046 std::wstring name = narrow_to_wide(player->getName());
2049 bool ate = m_script->on_chat_message(player->getName(),
2050 wide_to_narrow(message));
2051 // If script ate the message, don't proceed
2055 // Line to send to players
2057 // Whether to send to the player that sent the line
2058 bool send_to_sender_only = false;
2060 // Commands are implemented in Lua, so only catch invalid
2061 // commands that were not "eaten" and send an error back
2062 if(message[0] == L'/') {
2063 message = message.substr(1);
2064 send_to_sender_only = true;
2065 if(message.length() == 0)
2066 line += L"-!- Empty command";
2068 line += L"-!- Invalid command: " + str_split(message, L' ')[0];
2071 if(checkPriv(player->getName(), "shout")) {
2077 line += L"-!- You don't have permission to shout.";
2078 send_to_sender_only = true;
2085 Send the message to sender
2087 if (send_to_sender_only) {
2088 SendChatMessage(pkt->getPeerId(), line);
2091 Send the message to others
2094 actionstream << "CHAT: " << wide_to_narrow(line)<<std::endl;
2096 std::list<u16> clients = m_clients.getClientIDs();
2098 for(std::list<u16>::iterator
2099 i = clients.begin();
2100 i != clients.end(); ++i) {
2101 if (*i != pkt->getPeerId())
2102 SendChatMessage(*i, line);
2108 void Server::handleCommand_Damage(ToServerPacket* pkt)
2114 Player *player = m_env->getPlayer(pkt->getPeerId());
2115 if(player == NULL) {
2116 errorstream << "Server::ProcessData(): Cancelling: "
2117 "No player for peer_id=" << pkt->getPeerId()
2118 << " disconnecting peer!" << std::endl;
2119 m_con.DisconnectPeer(pkt->getPeerId());
2123 PlayerSAO *playersao = player->getPlayerSAO();
2124 if(playersao == NULL) {
2125 errorstream << "Server::ProcessData(): Cancelling: "
2126 "No player object for peer_id=" << pkt->getPeerId()
2127 << " disconnecting peer!" << std::endl;
2128 m_con.DisconnectPeer(pkt->getPeerId());
2132 if(g_settings->getBool("enable_damage")) {
2133 actionstream << player->getName() << " damaged by "
2134 << (int)damage << " hp at " << PP(player->getPosition() / BS)
2137 playersao->setHP(playersao->getHP() - damage);
2139 if(playersao->getHP() == 0 && playersao->m_hp_not_sent)
2140 DiePlayer(pkt->getPeerId());
2142 if(playersao->m_hp_not_sent)
2143 SendPlayerHP(pkt->getPeerId());
2147 void Server::handleCommand_Breath(ToServerPacket* pkt)
2153 Player *player = m_env->getPlayer(pkt->getPeerId());
2154 if(player == NULL) {
2155 errorstream << "Server::ProcessData(): Cancelling: "
2156 "No player for peer_id=" << pkt->getPeerId()
2157 << " disconnecting peer!" << std::endl;
2158 m_con.DisconnectPeer(pkt->getPeerId());
2162 PlayerSAO *playersao = player->getPlayerSAO();
2163 if(playersao == NULL) {
2164 errorstream << "Server::ProcessData(): Cancelling: "
2165 "No player object for peer_id=" << pkt->getPeerId()
2166 << " disconnecting peer!" << std::endl;
2167 m_con.DisconnectPeer(pkt->getPeerId());
2171 playersao->setBreath(breath);
2172 m_script->player_event(playersao,"breath_changed");
2175 void Server::handleCommand_Password(ToServerPacket* pkt)
2178 [0] u16 TOSERVER_PASSWORD
2179 [2] u8[28] old password
2180 [30] u8[28] new password
2183 if(pkt->getSize() != PASSWORD_SIZE * 2)
2189 for(u32 i=0; i<PASSWORD_SIZE - 1; i++) {
2190 char c = pkt->getChar(i);
2196 for(u32 i=0; i<PASSWORD_SIZE - 1; i++) {
2197 char c = pkt->getChar(PASSWORD_SIZE + i);
2203 Player *player = m_env->getPlayer(pkt->getPeerId());
2204 if(player == NULL) {
2205 errorstream << "Server::ProcessData(): Cancelling: "
2206 "No player for peer_id=" << pkt->getPeerId()
2207 << " disconnecting peer!" << std::endl;
2208 m_con.DisconnectPeer(pkt->getPeerId());
2212 if(!base64_is_valid(newpwd)) {
2213 infostream<<"Server: " << player->getName() <<
2214 " supplied invalid password hash" << std::endl;
2215 // Wrong old password supplied!!
2216 SendChatMessage(pkt->getPeerId(), L"Invalid new password hash supplied. Password NOT changed.");
2220 infostream << "Server: Client requests a password change from "
2221 << "'" << oldpwd << "' to '" << newpwd << "'" << std::endl;
2223 std::string playername = player->getName();
2225 std::string checkpwd;
2226 m_script->getAuth(playername, &checkpwd, NULL);
2228 if(oldpwd != checkpwd) {
2229 infostream << "Server: invalid old password" << std::endl;
2230 // Wrong old password supplied!!
2231 SendChatMessage(pkt->getPeerId(), L"Invalid old password supplied. Password NOT changed.");
2235 bool success = m_script->setPassword(playername, newpwd);
2237 actionstream << player->getName() << " changes password" << std::endl;
2238 SendChatMessage(pkt->getPeerId(), L"Password change successful.");
2240 actionstream << player->getName() << " tries to change password but "
2241 << "it fails" << std::endl;
2242 SendChatMessage(pkt->getPeerId(), L"Password change failed or inavailable.");
2246 void Server::handleCommand_PlayerItem(ToServerPacket* pkt)
2248 if (pkt->getSize() < 2)
2251 Player *player = m_env->getPlayer(pkt->getPeerId());
2252 if(player == NULL) {
2253 errorstream << "Server::ProcessData(): Cancelling: "
2254 "No player for peer_id=" << pkt->getPeerId()
2255 << " disconnecting peer!" << std::endl;
2256 m_con.DisconnectPeer(pkt->getPeerId());
2260 PlayerSAO *playersao = player->getPlayerSAO();
2261 if(playersao == NULL) {
2262 errorstream << "Server::ProcessData(): Cancelling: "
2263 "No player object for peer_id=" << pkt->getPeerId()
2264 << " disconnecting peer!" << std::endl;
2265 m_con.DisconnectPeer(pkt->getPeerId());
2273 playersao->setWieldIndex(item);
2276 void Server::handleCommand_Respawn(ToServerPacket* pkt)
2278 Player *player = m_env->getPlayer(pkt->getPeerId());
2279 if(player == NULL) {
2280 errorstream << "Server::ProcessData(): Cancelling: "
2281 "No player for peer_id=" << pkt->getPeerId()
2282 << " disconnecting peer!" << std::endl;
2283 m_con.DisconnectPeer(pkt->getPeerId());
2287 if(player->hp != 0 || !g_settings->getBool("enable_damage"))
2290 RespawnPlayer(pkt->getPeerId());
2292 actionstream<<player->getName()<<" respawns at "
2293 <<PP(player->getPosition()/BS)<<std::endl;
2295 // ActiveObject is added to environment in AsyncRunStep after
2296 // the previous addition has been succesfully removed
2299 void Server::handleCommand_Interact(ToServerPacket* pkt)
2301 std::string datastring(pkt->getString(0), pkt->getSize());
2302 std::istringstream is(datastring, std::ios_base::binary);
2308 [5] u32 length of the next item
2309 [9] serialized PointedThing
2311 0: start digging (from undersurface) or use
2312 1: stop digging (all parameters ignored)
2313 2: digging completed
2314 3: place block or item (to abovesurface)
2317 u8 action = readU8(is);
2318 u16 item_i = readU16(is);
2319 std::istringstream tmp_is(deSerializeLongString(is), std::ios::binary);
2320 PointedThing pointed;
2321 pointed.deSerialize(tmp_is);
2323 verbosestream << "TOSERVER_INTERACT: action=" << (int)action << ", item="
2324 << item_i << ", pointed=" << pointed.dump() << std::endl;
2326 Player *player = m_env->getPlayer(pkt->getPeerId());
2327 if(player == NULL) {
2328 errorstream << "Server::ProcessData(): Cancelling: "
2329 "No player for peer_id=" << pkt->getPeerId()
2330 << " disconnecting peer!" << std::endl;
2331 m_con.DisconnectPeer(pkt->getPeerId());
2335 PlayerSAO *playersao = player->getPlayerSAO();
2336 if(playersao == NULL) {
2337 errorstream << "Server::ProcessData(): Cancelling: "
2338 "No player object for peer_id=" << pkt->getPeerId()
2339 << " disconnecting peer!" << std::endl;
2340 m_con.DisconnectPeer(pkt->getPeerId());
2344 if(player->hp == 0) {
2345 verbosestream << "TOSERVER_INTERACT: " << player->getName()
2346 << " tried to interact, but is dead!" << std::endl;
2350 v3f player_pos = playersao->getLastGoodPosition();
2352 // Update wielded item
2353 playersao->setWieldIndex(item_i);
2355 // Get pointed to node (undefined if not POINTEDTYPE_NODE)
2356 v3s16 p_under = pointed.node_undersurface;
2357 v3s16 p_above = pointed.node_abovesurface;
2359 // Get pointed to object (NULL if not POINTEDTYPE_OBJECT)
2360 ServerActiveObject *pointed_object = NULL;
2361 if(pointed.type == POINTEDTHING_OBJECT) {
2362 pointed_object = m_env->getActiveObject(pointed.object_id);
2363 if(pointed_object == NULL) {
2364 verbosestream << "TOSERVER_INTERACT: "
2365 "pointed object is NULL" << std::endl;
2371 v3f pointed_pos_under = player_pos;
2372 v3f pointed_pos_above = player_pos;
2373 if(pointed.type == POINTEDTHING_NODE) {
2374 pointed_pos_under = intToFloat(p_under, BS);
2375 pointed_pos_above = intToFloat(p_above, BS);
2377 else if(pointed.type == POINTEDTHING_OBJECT) {
2378 pointed_pos_under = pointed_object->getBasePosition();
2379 pointed_pos_above = pointed_pos_under;
2383 Check that target is reasonably close
2384 (only when digging or placing things)
2386 if(action == 0 || action == 2 || action == 3) {
2387 float d = player_pos.getDistanceFrom(pointed_pos_under);
2388 float max_d = BS * 14; // Just some large enough value
2390 actionstream << "Player " << player->getName()
2391 << " tried to access " << pointed.dump()
2392 << " from too far: "
2393 << "d=" << d <<", max_d=" << max_d
2394 << ". ignoring." << std::endl;
2395 // Re-send block to revert change on client-side
2396 RemoteClient *client = getClient(pkt->getPeerId());
2397 v3s16 blockpos = getNodeBlockPos(floatToInt(pointed_pos_under, BS));
2398 client->SetBlockNotSent(blockpos);
2400 m_script->on_cheat(playersao, "interacted_too_far");
2407 Make sure the player is allowed to do it
2409 if(!checkPriv(player->getName(), "interact")) {
2410 actionstream<<player->getName()<<" attempted to interact with "
2411 <<pointed.dump()<<" without 'interact' privilege"
2413 // Re-send block to revert change on client-side
2414 RemoteClient *client = getClient(pkt->getPeerId());
2415 // Digging completed -> under
2417 v3s16 blockpos = getNodeBlockPos(floatToInt(pointed_pos_under, BS));
2418 client->SetBlockNotSent(blockpos);
2420 // Placement -> above
2422 v3s16 blockpos = getNodeBlockPos(floatToInt(pointed_pos_above, BS));
2423 client->SetBlockNotSent(blockpos);
2429 If something goes wrong, this player is to blame
2431 RollbackScopeActor rollback_scope(m_rollback,
2432 std::string("player:")+player->getName());
2435 0: start digging or punch object
2438 if(pointed.type == POINTEDTHING_NODE) {
2440 NOTE: This can be used in the future to check if
2441 somebody is cheating, by checking the timing.
2443 MapNode n(CONTENT_IGNORE);
2445 n = m_env->getMap().getNodeNoEx(p_under, &pos_ok);
2447 n = m_env->getMap().getNodeNoEx(p_under, &pos_ok);
2450 infostream << "Server: Not punching: Node not found."
2451 << " Adding block to emerge queue."
2453 m_emerge->enqueueBlockEmerge(pkt->getPeerId(), getNodeBlockPos(p_above), false);
2456 if(n.getContent() != CONTENT_IGNORE)
2457 m_script->node_on_punch(p_under, n, playersao, pointed);
2459 playersao->noCheatDigStart(p_under);
2461 else if(pointed.type == POINTEDTHING_OBJECT) {
2462 // Skip if object has been removed
2463 if(pointed_object->m_removed)
2466 actionstream<<player->getName()<<" punches object "
2467 <<pointed.object_id<<": "
2468 <<pointed_object->getDescription()<<std::endl;
2470 ItemStack punchitem = playersao->getWieldedItem();
2471 ToolCapabilities toolcap =
2472 punchitem.getToolCapabilities(m_itemdef);
2473 v3f dir = (pointed_object->getBasePosition() -
2474 (player->getPosition() + player->getEyeOffset())
2476 float time_from_last_punch =
2477 playersao->resetTimeFromLastPunch();
2478 pointed_object->punch(dir, &toolcap, playersao,
2479 time_from_last_punch);
2487 else if(action == 1) {
2491 2: Digging completed
2493 else if(action == 2) {
2494 // Only digging of nodes
2495 if(pointed.type == POINTEDTHING_NODE) {
2497 MapNode n = m_env->getMap().getNodeNoEx(p_under, &pos_ok);
2499 infostream << "Server: Not finishing digging: Node not found."
2500 << " Adding block to emerge queue."
2502 m_emerge->enqueueBlockEmerge(pkt->getPeerId(), getNodeBlockPos(p_above), false);
2505 /* Cheat prevention */
2506 bool is_valid_dig = true;
2507 if(!isSingleplayer() && !g_settings->getBool("disable_anticheat")) {
2508 v3s16 nocheat_p = playersao->getNoCheatDigPos();
2509 float nocheat_t = playersao->getNoCheatDigTime();
2510 playersao->noCheatDigEnd();
2511 // If player didn't start digging this, ignore dig
2512 if(nocheat_p != p_under) {
2513 infostream << "Server: NoCheat: " << player->getName()
2514 << " started digging "
2515 << PP(nocheat_p) << " and completed digging "
2516 << PP(p_under) << "; not digging." << std::endl;
2517 is_valid_dig = false;
2519 m_script->on_cheat(playersao, "finished_unknown_dig");
2521 // Get player's wielded item
2522 ItemStack playeritem;
2523 InventoryList *mlist = playersao->getInventory()->getList("main");
2525 playeritem = mlist->getItem(playersao->getWieldIndex());
2526 ToolCapabilities playeritem_toolcap =
2527 playeritem.getToolCapabilities(m_itemdef);
2528 // Get diggability and expected digging time
2529 DigParams params = getDigParams(m_nodedef->get(n).groups,
2530 &playeritem_toolcap);
2531 // If can't dig, try hand
2532 if(!params.diggable) {
2533 const ItemDefinition &hand = m_itemdef->get("");
2534 const ToolCapabilities *tp = hand.tool_capabilities;
2536 params = getDigParams(m_nodedef->get(n).groups, tp);
2538 // If can't dig, ignore dig
2539 if(!params.diggable) {
2540 infostream << "Server: NoCheat: " << player->getName()
2541 << " completed digging " << PP(p_under)
2542 << ", which is not diggable with tool. not digging."
2544 is_valid_dig = false;
2546 m_script->on_cheat(playersao, "dug_unbreakable");
2548 // Check digging time
2549 // If already invalidated, we don't have to
2551 // Well not our problem then
2553 // Clean and long dig
2554 else if(params.time > 2.0 && nocheat_t * 1.2 > params.time) {
2555 // All is good, but grab time from pool; don't care if
2556 // it's actually available
2557 playersao->getDigPool().grab(params.time);
2559 // Short or laggy dig
2560 // Try getting the time from pool
2561 else if(playersao->getDigPool().grab(params.time)) {
2566 infostream << "Server: NoCheat: " << player->getName()
2567 << " completed digging " << PP(p_under)
2568 << "too fast; not digging." << std::endl;
2569 is_valid_dig = false;
2571 m_script->on_cheat(playersao, "dug_too_fast");
2575 /* Actually dig node */
2577 if(is_valid_dig && n.getContent() != CONTENT_IGNORE)
2578 m_script->node_on_dig(p_under, n, playersao);
2580 v3s16 blockpos = getNodeBlockPos(floatToInt(pointed_pos_under, BS));
2581 RemoteClient *client = getClient(pkt->getPeerId());
2582 // Send unusual result (that is, node not being removed)
2583 if(m_env->getMap().getNodeNoEx(p_under).getContent() != CONTENT_AIR) {
2584 // Re-send block to revert change on client-side
2585 client->SetBlockNotSent(blockpos);
2588 client->ResendBlockIfOnWire(blockpos);
2594 3: place block or right-click object
2596 else if(action == 3) {
2597 ItemStack item = playersao->getWieldedItem();
2599 // Reset build time counter
2600 if(pointed.type == POINTEDTHING_NODE &&
2601 item.getDefinition(m_itemdef).type == ITEM_NODE)
2602 getClient(pkt->getPeerId())->m_time_from_building = 0.0;
2604 if(pointed.type == POINTEDTHING_OBJECT) {
2605 // Right click object
2607 // Skip if object has been removed
2608 if(pointed_object->m_removed)
2611 actionstream << player->getName() << " right-clicks object "
2612 << pointed.object_id << ": "
2613 << pointed_object->getDescription() << std::endl;
2616 pointed_object->rightClick(playersao);
2618 else if(m_script->item_OnPlace(
2619 item, playersao, pointed)) {
2620 // Placement was handled in lua
2622 // Apply returned ItemStack
2623 playersao->setWieldedItem(item);
2626 // If item has node placement prediction, always send the
2627 // blocks to make sure the client knows what exactly happened
2628 RemoteClient *client = getClient(pkt->getPeerId());
2629 v3s16 blockpos = getNodeBlockPos(floatToInt(pointed_pos_above, BS));
2630 v3s16 blockpos2 = getNodeBlockPos(floatToInt(pointed_pos_under, BS));
2631 if(item.getDefinition(m_itemdef).node_placement_prediction != "") {
2632 client->SetBlockNotSent(blockpos);
2633 if(blockpos2 != blockpos) {
2634 client->SetBlockNotSent(blockpos2);
2638 client->ResendBlockIfOnWire(blockpos);
2639 if(blockpos2 != blockpos) {
2640 client->ResendBlockIfOnWire(blockpos2);
2648 else if(action == 4) {
2649 ItemStack item = playersao->getWieldedItem();
2651 actionstream << player->getName() << " uses " << item.name
2652 << ", pointing at " << pointed.dump() << std::endl;
2654 if(m_script->item_OnUse(
2655 item, playersao, pointed)) {
2656 // Apply returned ItemStack
2657 playersao->setWieldedItem(item);
2664 Catch invalid actions
2667 infostream << "WARNING: Server: Invalid action "
2668 << action << std::endl;
2672 void Server::handleCommand_RemovedSounds(ToServerPacket* pkt)
2676 for(int k=0; k<num; k++) {
2681 std::map<s32, ServerPlayingSound>::iterator i =
2682 m_playing_sounds.find(id);
2684 if(i == m_playing_sounds.end())
2687 ServerPlayingSound &psound = i->second;
2688 psound.clients.erase(pkt->getPeerId());
2689 if(psound.clients.empty())
2690 m_playing_sounds.erase(i++);
2694 void Server::handleCommand_NodeMetaFields(ToServerPacket* pkt)
2697 std::string formname;
2700 *pkt >> p >> formname >> num;
2702 std::map<std::string, std::string> fields;
2703 for(int k=0; k<num; k++) {
2704 std::string fieldname;
2706 fields[fieldname] = pkt->readLongString();
2709 Player *player = m_env->getPlayer(pkt->getPeerId());
2710 if(player == NULL) {
2711 errorstream << "Server::ProcessData(): Cancelling: "
2712 "No player for peer_id=" << pkt->getPeerId()
2713 << " disconnecting peer!" << std::endl;
2714 m_con.DisconnectPeer(pkt->getPeerId());
2718 PlayerSAO *playersao = player->getPlayerSAO();
2719 if(playersao == NULL) {
2720 errorstream << "Server::ProcessData(): Cancelling: "
2721 "No player object for peer_id=" << pkt->getPeerId()
2722 << " disconnecting peer!" << std::endl;
2723 m_con.DisconnectPeer(pkt->getPeerId());
2727 // If something goes wrong, this player is to blame
2728 RollbackScopeActor rollback_scope(m_rollback,
2729 std::string("player:")+player->getName());
2731 // Check the target node for rollback data; leave others unnoticed
2732 RollbackNode rn_old(&m_env->getMap(), p, this);
2734 m_script->node_on_receive_fields(p, formname, fields, playersao);
2736 // Report rollback data
2737 RollbackNode rn_new(&m_env->getMap(), p, this);
2738 if(rollback() && rn_new != rn_old){
2739 RollbackAction action;
2740 action.setSetNode(p, rn_old, rn_new);
2741 rollback()->reportAction(action);
2745 void Server::handleCommand_InventoryFields(ToServerPacket* pkt)
2747 std::string formname;
2750 *pkt >> formname >> num;
2752 std::map<std::string, std::string> fields;
2753 for(int k=0; k<num; k++) {
2754 std::string fieldname;
2756 fields[fieldname] = pkt->readLongString();
2759 Player *player = m_env->getPlayer(pkt->getPeerId());
2760 if(player == NULL) {
2761 errorstream << "Server::ProcessData(): Cancelling: "
2762 "No player for peer_id=" << pkt->getPeerId()
2763 << " disconnecting peer!" << std::endl;
2764 m_con.DisconnectPeer(pkt->getPeerId());
2768 PlayerSAO *playersao = player->getPlayerSAO();
2769 if(playersao == NULL) {
2770 errorstream << "Server::ProcessData(): Cancelling: "
2771 "No player object for peer_id=" << pkt->getPeerId()
2772 << " disconnecting peer!" << std::endl;
2773 m_con.DisconnectPeer(pkt->getPeerId());
2777 m_script->on_playerReceiveFields(playersao, formname, fields);
2780 inline void Server::handleCommand(ToServerPacket* pkt)
2782 const ToServerCommandHandler& opHandle = toServerCommandTable[pkt->getCommand()];
2783 (this->*opHandle.handler)(pkt);
2786 void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
2788 DSTACK(__FUNCTION_NAME);
2789 // Environment is locked first.
2790 JMutexAutoLock envlock(m_env_mutex);
2792 ScopeProfiler sp(g_profiler, "Server::ProcessData");
2795 Address address = getPeerAddress(peer_id);
2796 std::string addr_s = address.serializeString();
2798 if(m_banmanager->isIpBanned(addr_s)) {
2799 std::string ban_name = m_banmanager->getBanName(addr_s);
2800 infostream << "Server: A banned client tried to connect from "
2801 << addr_s << "; banned name was "
2802 << ban_name << std::endl;
2803 // This actually doesn't seem to transfer to the client
2804 DenyAccess(peer_id, L"Your ip is banned. Banned name was "
2805 + narrow_to_wide(ban_name));
2809 catch(con::PeerNotFoundException &e) {
2811 * no peer for this packet found
2812 * most common reason is peer timeout, e.g. peer didn't
2813 * respond for some time, your server was overloaded or
2816 infostream << "Server::ProcessData(): Cancelling: peer "
2817 << peer_id << " not found" << std::endl;
2825 ToServerPacket* pkt = new ToServerPacket(data, datasize, peer_id);
2827 ToServerCommand command = pkt->getCommand();
2829 // Command must be handled into ToServerCommandHandler
2830 if (command >= TOSERVER_NUM_MSG_TYPES) {
2831 infostream << "Server: Ignoring unknown command "
2832 << command << std::endl;
2835 if (toServerCommandTable[command].state == TOSERVER_STATE_NOT_CONNECTED) {
2841 u8 peer_ser_ver = getClient(peer_id, CS_InitDone)->serialization_version;
2843 if(peer_ser_ver == SER_FMT_VER_INVALID) {
2844 errorstream << "Server::ProcessData(): Cancelling: Peer"
2845 " serialization format invalid or not initialized."
2846 " Skipping incoming command=" << command << std::endl;
2852 /* Handle commands related to client startup */
2853 if (toServerCommandTable[command].state == TOSERVER_STATE_STARTUP) {
2859 if (m_clients.getClientState(peer_id) < CS_Active) {
2860 if (command == TOSERVER_PLAYERPOS) return;
2862 errorstream << "Got packet command: " << command << " for peer id "
2863 << peer_id << " but client isn't active yet. Dropping packet "
2874 catch(SendFailedException &e) {
2875 errorstream << "Server::ProcessData(): SendFailedException: "
2876 << "what=" << e.what()
2881 void Server::setTimeOfDay(u32 time)
2883 m_env->setTimeOfDay(time);
2884 m_time_of_day_send_timer = 0;
2887 void Server::onMapEditEvent(MapEditEvent *event)
2889 if(m_ignore_map_edit_events)
2891 if(m_ignore_map_edit_events_area.contains(event->getArea()))
2893 MapEditEvent *e = event->clone();
2894 m_unsent_map_edit_queue.push_back(e);
2897 Inventory* Server::getInventory(const InventoryLocation &loc)
2900 case InventoryLocation::UNDEFINED:
2901 case InventoryLocation::CURRENT_PLAYER:
2903 case InventoryLocation::PLAYER:
2905 Player *player = m_env->getPlayer(loc.name.c_str());
2908 PlayerSAO *playersao = player->getPlayerSAO();
2911 return playersao->getInventory();
2914 case InventoryLocation::NODEMETA:
2916 NodeMetadata *meta = m_env->getMap().getNodeMetadata(loc.p);
2919 return meta->getInventory();
2922 case InventoryLocation::DETACHED:
2924 if(m_detached_inventories.count(loc.name) == 0)
2926 return m_detached_inventories[loc.name];
2934 void Server::setInventoryModified(const InventoryLocation &loc)
2937 case InventoryLocation::UNDEFINED:
2939 case InventoryLocation::PLAYER:
2941 Player *player = m_env->getPlayer(loc.name.c_str());
2944 PlayerSAO *playersao = player->getPlayerSAO();
2947 playersao->m_inventory_not_sent = true;
2948 playersao->m_wielded_item_not_sent = true;
2951 case InventoryLocation::NODEMETA:
2953 v3s16 blockpos = getNodeBlockPos(loc.p);
2955 MapBlock *block = m_env->getMap().getBlockNoCreateNoEx(blockpos);
2957 block->raiseModified(MOD_STATE_WRITE_NEEDED);
2959 setBlockNotSent(blockpos);
2962 case InventoryLocation::DETACHED:
2964 sendDetachedInventory(loc.name,PEER_ID_INEXISTENT);
2972 void Server::SetBlocksNotSent(std::map<v3s16, MapBlock *>& block)
2974 std::list<u16> clients = m_clients.getClientIDs();
2976 // Set the modified blocks unsent for all the clients
2977 for (std::list<u16>::iterator
2978 i = clients.begin();
2979 i != clients.end(); ++i) {
2980 RemoteClient *client = m_clients.lockedGetClientNoEx(*i);
2982 client->SetBlocksNotSent(block);
2987 void Server::peerAdded(con::Peer *peer)
2989 DSTACK(__FUNCTION_NAME);
2990 verbosestream<<"Server::peerAdded(): peer->id="
2991 <<peer->id<<std::endl;
2994 c.type = con::PEER_ADDED;
2995 c.peer_id = peer->id;
2997 m_peer_change_queue.push_back(c);
3000 void Server::deletingPeer(con::Peer *peer, bool timeout)
3002 DSTACK(__FUNCTION_NAME);
3003 verbosestream<<"Server::deletingPeer(): peer->id="
3004 <<peer->id<<", timeout="<<timeout<<std::endl;
3006 m_clients.event(peer->id, CSE_Disconnect);
3008 c.type = con::PEER_REMOVED;
3009 c.peer_id = peer->id;
3010 c.timeout = timeout;
3011 m_peer_change_queue.push_back(c);
3014 bool Server::getClientConInfo(u16 peer_id, con::rtt_stat_type type, float* retval)
3016 *retval = m_con.getPeerStat(peer_id,type);
3017 if (*retval == -1) return false;
3021 bool Server::getClientInfo(
3030 std::string* vers_string
3033 *state = m_clients.getClientState(peer_id);
3035 RemoteClient* client = m_clients.lockedGetClientNoEx(peer_id, CS_Invalid);
3037 if (client == NULL) {
3042 *uptime = client->uptime();
3043 *ser_vers = client->serialization_version;
3044 *prot_vers = client->net_proto_version;
3046 *major = client->getMajor();
3047 *minor = client->getMinor();
3048 *patch = client->getPatch();
3049 *vers_string = client->getPatch();
3056 void Server::handlePeerChanges()
3058 while(m_peer_change_queue.size() > 0)
3060 con::PeerChange c = m_peer_change_queue.pop_front();
3062 verbosestream<<"Server: Handling peer change: "
3063 <<"id="<<c.peer_id<<", timeout="<<c.timeout
3068 case con::PEER_ADDED:
3069 m_clients.CreateClient(c.peer_id);
3072 case con::PEER_REMOVED:
3073 DeleteClient(c.peer_id, c.timeout?CDR_TIMEOUT:CDR_LEAVE);
3077 assert("Invalid peer change event received!" == 0);
3083 void Server::SendMovement(u16 peer_id)
3085 DSTACK(__FUNCTION_NAME);
3086 std::ostringstream os(std::ios_base::binary);
3088 writeU16(os, TOCLIENT_MOVEMENT);
3089 writeF1000(os, g_settings->getFloat("movement_acceleration_default"));
3090 writeF1000(os, g_settings->getFloat("movement_acceleration_air"));
3091 writeF1000(os, g_settings->getFloat("movement_acceleration_fast"));
3092 writeF1000(os, g_settings->getFloat("movement_speed_walk"));
3093 writeF1000(os, g_settings->getFloat("movement_speed_crouch"));
3094 writeF1000(os, g_settings->getFloat("movement_speed_fast"));
3095 writeF1000(os, g_settings->getFloat("movement_speed_climb"));
3096 writeF1000(os, g_settings->getFloat("movement_speed_jump"));
3097 writeF1000(os, g_settings->getFloat("movement_liquid_fluidity"));
3098 writeF1000(os, g_settings->getFloat("movement_liquid_fluidity_smooth"));
3099 writeF1000(os, g_settings->getFloat("movement_liquid_sink"));
3100 writeF1000(os, g_settings->getFloat("movement_gravity"));
3103 std::string s = os.str();
3104 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3106 m_clients.send(peer_id, 0, data, true);
3109 void Server::SendHP(u16 peer_id, u8 hp)
3111 DSTACK(__FUNCTION_NAME);
3112 std::ostringstream os(std::ios_base::binary);
3114 writeU16(os, TOCLIENT_HP);
3118 std::string s = os.str();
3119 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3121 m_clients.send(peer_id, 0, data, true);
3124 void Server::SendBreath(u16 peer_id, u16 breath)
3126 DSTACK(__FUNCTION_NAME);
3127 std::ostringstream os(std::ios_base::binary);
3129 writeU16(os, TOCLIENT_BREATH);
3130 writeU16(os, breath);
3133 std::string s = os.str();
3134 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3136 m_clients.send(peer_id, 0, data, true);
3139 void Server::SendAccessDenied(u16 peer_id,const std::wstring &reason)
3141 DSTACK(__FUNCTION_NAME);
3142 std::ostringstream os(std::ios_base::binary);
3144 writeU16(os, TOCLIENT_ACCESS_DENIED);
3145 os<<serializeWideString(reason);
3148 std::string s = os.str();
3149 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3151 m_clients.send(peer_id, 0, data, true);
3154 void Server::SendDeathscreen(u16 peer_id,bool set_camera_point_target,
3155 v3f camera_point_target)
3157 DSTACK(__FUNCTION_NAME);
3158 std::ostringstream os(std::ios_base::binary);
3160 writeU16(os, TOCLIENT_DEATHSCREEN);
3161 writeU8(os, set_camera_point_target);
3162 writeV3F1000(os, camera_point_target);
3165 std::string s = os.str();
3166 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3168 m_clients.send(peer_id, 0, data, true);
3171 void Server::SendItemDef(u16 peer_id,
3172 IItemDefManager *itemdef, u16 protocol_version)
3174 DSTACK(__FUNCTION_NAME);
3175 std::ostringstream os(std::ios_base::binary);
3179 u32 length of the next item
3180 zlib-compressed serialized ItemDefManager
3182 writeU16(os, TOCLIENT_ITEMDEF);
3183 std::ostringstream tmp_os(std::ios::binary);
3184 itemdef->serialize(tmp_os, protocol_version);
3185 std::ostringstream tmp_os2(std::ios::binary);
3186 compressZlib(tmp_os.str(), tmp_os2);
3187 os<<serializeLongString(tmp_os2.str());
3190 std::string s = os.str();
3191 verbosestream<<"Server: Sending item definitions to id("<<peer_id
3192 <<"): size="<<s.size()<<std::endl;
3193 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3195 m_clients.send(peer_id, 0, data, true);
3198 void Server::SendNodeDef(u16 peer_id,
3199 INodeDefManager *nodedef, u16 protocol_version)
3201 DSTACK(__FUNCTION_NAME);
3202 std::ostringstream os(std::ios_base::binary);
3206 u32 length of the next item
3207 zlib-compressed serialized NodeDefManager
3209 writeU16(os, TOCLIENT_NODEDEF);
3210 std::ostringstream tmp_os(std::ios::binary);
3211 nodedef->serialize(tmp_os, protocol_version);
3212 std::ostringstream tmp_os2(std::ios::binary);
3213 compressZlib(tmp_os.str(), tmp_os2);
3214 os<<serializeLongString(tmp_os2.str());
3217 std::string s = os.str();
3218 verbosestream<<"Server: Sending node definitions to id("<<peer_id
3219 <<"): size="<<s.size()<<std::endl;
3220 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3222 m_clients.send(peer_id, 0, data, true);
3226 Non-static send methods
3229 void Server::SendInventory(u16 peer_id)
3231 DSTACK(__FUNCTION_NAME);
3233 PlayerSAO *playersao = getPlayerSAO(peer_id);
3236 playersao->m_inventory_not_sent = false;
3242 std::ostringstream os;
3243 playersao->getInventory()->serialize(os);
3245 std::string s = os.str();
3247 SharedBuffer<u8> data(s.size()+2);
3248 writeU16(&data[0], TOCLIENT_INVENTORY);
3249 memcpy(&data[2], s.c_str(), s.size());
3252 m_clients.send(peer_id, 0, data, true);
3255 void Server::SendChatMessage(u16 peer_id, const std::wstring &message)
3257 DSTACK(__FUNCTION_NAME);
3259 std::ostringstream os(std::ios_base::binary);
3263 writeU16(buf, TOCLIENT_CHAT_MESSAGE);
3264 os.write((char*)buf, 2);
3267 writeU16(buf, message.size());
3268 os.write((char*)buf, 2);
3271 for(u32 i=0; i<message.size(); i++)
3275 os.write((char*)buf, 2);
3279 std::string s = os.str();
3280 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3282 if (peer_id != PEER_ID_INEXISTENT)
3285 m_clients.send(peer_id, 0, data, true);
3289 m_clients.sendToAll(0,data,true);
3293 void Server::SendShowFormspecMessage(u16 peer_id, const std::string &formspec,
3294 const std::string &formname)
3296 DSTACK(__FUNCTION_NAME);
3298 std::ostringstream os(std::ios_base::binary);
3303 writeU16(buf, TOCLIENT_SHOW_FORMSPEC);
3304 os.write((char*)buf, 2);
3305 os<<serializeLongString(FORMSPEC_VERSION_STRING + formspec);
3306 os<<serializeString(formname);
3309 std::string s = os.str();
3310 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3312 m_clients.send(peer_id, 0, data, true);
3315 // Spawns a particle on peer with peer_id
3316 void Server::SendSpawnParticle(u16 peer_id, v3f pos, v3f velocity, v3f acceleration,
3317 float expirationtime, float size, bool collisiondetection,
3318 bool vertical, std::string texture)
3320 DSTACK(__FUNCTION_NAME);
3322 std::ostringstream os(std::ios_base::binary);
3323 writeU16(os, TOCLIENT_SPAWN_PARTICLE);
3324 writeV3F1000(os, pos);
3325 writeV3F1000(os, velocity);
3326 writeV3F1000(os, acceleration);
3327 writeF1000(os, expirationtime);
3328 writeF1000(os, size);
3329 writeU8(os, collisiondetection);
3330 os<<serializeLongString(texture);
3331 writeU8(os, vertical);
3334 std::string s = os.str();
3335 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3337 if (peer_id != PEER_ID_INEXISTENT)
3340 m_clients.send(peer_id, 0, data, true);
3344 m_clients.sendToAll(0,data,true);
3348 // Adds a ParticleSpawner on peer with peer_id
3349 void Server::SendAddParticleSpawner(u16 peer_id, u16 amount, float spawntime, v3f minpos, v3f maxpos,
3350 v3f minvel, v3f maxvel, v3f minacc, v3f maxacc, float minexptime, float maxexptime,
3351 float minsize, float maxsize, bool collisiondetection, bool vertical, std::string texture, u32 id)
3353 DSTACK(__FUNCTION_NAME);
3355 std::ostringstream os(std::ios_base::binary);
3356 writeU16(os, TOCLIENT_ADD_PARTICLESPAWNER);
3358 writeU16(os, amount);
3359 writeF1000(os, spawntime);
3360 writeV3F1000(os, minpos);
3361 writeV3F1000(os, maxpos);
3362 writeV3F1000(os, minvel);
3363 writeV3F1000(os, maxvel);
3364 writeV3F1000(os, minacc);
3365 writeV3F1000(os, maxacc);
3366 writeF1000(os, minexptime);
3367 writeF1000(os, maxexptime);
3368 writeF1000(os, minsize);
3369 writeF1000(os, maxsize);
3370 writeU8(os, collisiondetection);
3371 os<<serializeLongString(texture);
3373 writeU8(os, vertical);
3376 std::string s = os.str();
3377 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3379 if (peer_id != PEER_ID_INEXISTENT)
3382 m_clients.send(peer_id, 0, data, true);
3385 m_clients.sendToAll(0,data,true);
3389 void Server::SendDeleteParticleSpawner(u16 peer_id, u32 id)
3391 DSTACK(__FUNCTION_NAME);
3393 std::ostringstream os(std::ios_base::binary);
3394 writeU16(os, TOCLIENT_DELETE_PARTICLESPAWNER);
3399 std::string s = os.str();
3400 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3402 if (peer_id != PEER_ID_INEXISTENT) {
3404 m_clients.send(peer_id, 0, data, true);
3407 m_clients.sendToAll(0,data,true);
3412 void Server::SendHUDAdd(u16 peer_id, u32 id, HudElement *form)
3414 std::ostringstream os(std::ios_base::binary);
3417 writeU16(os, TOCLIENT_HUDADD);
3419 writeU8(os, (u8)form->type);
3420 writeV2F1000(os, form->pos);
3421 os << serializeString(form->name);
3422 writeV2F1000(os, form->scale);
3423 os << serializeString(form->text);
3424 writeU32(os, form->number);
3425 writeU32(os, form->item);
3426 writeU32(os, form->dir);
3427 writeV2F1000(os, form->align);
3428 writeV2F1000(os, form->offset);
3429 writeV3F1000(os, form->world_pos);
3430 writeV2S32(os,form->size);
3433 std::string s = os.str();
3434 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3436 m_clients.send(peer_id, 1, data, true);
3439 void Server::SendHUDRemove(u16 peer_id, u32 id)
3441 std::ostringstream os(std::ios_base::binary);
3444 writeU16(os, TOCLIENT_HUDRM);
3448 std::string s = os.str();
3449 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3452 m_clients.send(peer_id, 1, data, true);
3455 void Server::SendHUDChange(u16 peer_id, u32 id, HudElementStat stat, void *value)
3457 std::ostringstream os(std::ios_base::binary);
3460 writeU16(os, TOCLIENT_HUDCHANGE);
3462 writeU8(os, (u8)stat);
3465 case HUD_STAT_SCALE:
3466 case HUD_STAT_ALIGN:
3467 case HUD_STAT_OFFSET:
3468 writeV2F1000(os, *(v2f *)value);
3472 os << serializeString(*(std::string *)value);
3474 case HUD_STAT_WORLD_POS:
3475 writeV3F1000(os, *(v3f *)value);
3478 writeV2S32(os,*(v2s32 *)value);
3480 case HUD_STAT_NUMBER:
3484 writeU32(os, *(u32 *)value);
3489 std::string s = os.str();
3490 SharedBuffer<u8> data((u8 *)s.c_str(), s.size());
3492 m_clients.send(peer_id, 0, data, true);
3495 void Server::SendHUDSetFlags(u16 peer_id, u32 flags, u32 mask)
3497 std::ostringstream os(std::ios_base::binary);
3500 writeU16(os, TOCLIENT_HUD_SET_FLAGS);
3502 //////////////////////////// compatibility code to be removed //////////////
3503 flags &= ~(HUD_FLAG_HEALTHBAR_VISIBLE | HUD_FLAG_BREATHBAR_VISIBLE);
3504 ////////////////////////////////////////////////////////////////////////////
3505 writeU32(os, flags);
3509 std::string s = os.str();
3510 SharedBuffer<u8> data((u8 *)s.c_str(), s.size());
3512 m_clients.send(peer_id, 0, data, true);
3515 void Server::SendHUDSetParam(u16 peer_id, u16 param, const std::string &value)
3517 std::ostringstream os(std::ios_base::binary);
3520 writeU16(os, TOCLIENT_HUD_SET_PARAM);
3521 writeU16(os, param);
3522 os<<serializeString(value);
3525 std::string s = os.str();
3526 SharedBuffer<u8> data((u8 *)s.c_str(), s.size());
3528 m_clients.send(peer_id, 0, data, true);
3531 void Server::SendSetSky(u16 peer_id, const video::SColor &bgcolor,
3532 const std::string &type, const std::vector<std::string> ¶ms)
3534 std::ostringstream os(std::ios_base::binary);
3537 writeU16(os, TOCLIENT_SET_SKY);
3538 writeARGB8(os, bgcolor);
3539 os<<serializeString(type);
3540 writeU16(os, params.size());
3541 for(size_t i=0; i<params.size(); i++)
3542 os<<serializeString(params[i]);
3545 std::string s = os.str();
3546 SharedBuffer<u8> data((u8 *)s.c_str(), s.size());
3548 m_clients.send(peer_id, 0, data, true);
3551 void Server::SendOverrideDayNightRatio(u16 peer_id, bool do_override,
3554 std::ostringstream os(std::ios_base::binary);
3557 writeU16(os, TOCLIENT_OVERRIDE_DAY_NIGHT_RATIO);
3558 writeU8(os, do_override);
3559 writeU16(os, ratio*65535);
3562 std::string s = os.str();
3563 SharedBuffer<u8> data((u8 *)s.c_str(), s.size());
3565 m_clients.send(peer_id, 0, data, true);
3568 void Server::SendTimeOfDay(u16 peer_id, u16 time, f32 time_speed)
3570 DSTACK(__FUNCTION_NAME);
3573 SharedBuffer<u8> data(2+2+4);
3574 writeU16(&data[0], TOCLIENT_TIME_OF_DAY);
3575 writeU16(&data[2], time);
3576 writeF1000(&data[4], time_speed);
3578 if (peer_id == PEER_ID_INEXISTENT) {
3579 m_clients.sendToAll(0,data,true);
3583 m_clients.send(peer_id, 0, data, true);
3587 void Server::SendPlayerHP(u16 peer_id)
3589 DSTACK(__FUNCTION_NAME);
3590 PlayerSAO *playersao = getPlayerSAO(peer_id);
3592 playersao->m_hp_not_sent = false;
3593 SendHP(peer_id, playersao->getHP());
3594 m_script->player_event(playersao,"health_changed");
3596 // Send to other clients
3597 std::string str = gob_cmd_punched(playersao->readDamage(), playersao->getHP());
3598 ActiveObjectMessage aom(playersao->getId(), true, str);
3599 playersao->m_messages_out.push_back(aom);
3602 void Server::SendPlayerBreath(u16 peer_id)
3604 DSTACK(__FUNCTION_NAME);
3605 PlayerSAO *playersao = getPlayerSAO(peer_id);
3607 playersao->m_breath_not_sent = false;
3608 m_script->player_event(playersao,"breath_changed");
3609 SendBreath(peer_id, playersao->getBreath());
3612 void Server::SendMovePlayer(u16 peer_id)
3614 DSTACK(__FUNCTION_NAME);
3615 Player *player = m_env->getPlayer(peer_id);
3618 std::ostringstream os(std::ios_base::binary);
3619 writeU16(os, TOCLIENT_MOVE_PLAYER);
3620 writeV3F1000(os, player->getPosition());
3621 writeF1000(os, player->getPitch());
3622 writeF1000(os, player->getYaw());
3625 v3f pos = player->getPosition();
3626 f32 pitch = player->getPitch();
3627 f32 yaw = player->getYaw();
3628 verbosestream<<"Server: Sending TOCLIENT_MOVE_PLAYER"
3629 <<" pos=("<<pos.X<<","<<pos.Y<<","<<pos.Z<<")"
3636 std::string s = os.str();
3637 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3639 m_clients.send(peer_id, 0, data, true);
3642 void Server::SendLocalPlayerAnimations(u16 peer_id, v2s32 animation_frames[4], f32 animation_speed)
3644 std::ostringstream os(std::ios_base::binary);
3646 writeU16(os, TOCLIENT_LOCAL_PLAYER_ANIMATIONS);
3647 writeV2S32(os, animation_frames[0]);
3648 writeV2S32(os, animation_frames[1]);
3649 writeV2S32(os, animation_frames[2]);
3650 writeV2S32(os, animation_frames[3]);
3651 writeF1000(os, animation_speed);
3654 std::string s = os.str();
3655 SharedBuffer<u8> data((u8 *)s.c_str(), s.size());
3657 m_clients.send(peer_id, 0, data, true);
3660 void Server::SendEyeOffset(u16 peer_id, v3f first, v3f third)
3662 std::ostringstream os(std::ios_base::binary);
3664 writeU16(os, TOCLIENT_EYE_OFFSET);
3665 writeV3F1000(os, first);
3666 writeV3F1000(os, third);
3669 std::string s = os.str();
3670 SharedBuffer<u8> data((u8 *)s.c_str(), s.size());
3672 m_clients.send(peer_id, 0, data, true);
3674 void Server::SendPlayerPrivileges(u16 peer_id)
3676 Player *player = m_env->getPlayer(peer_id);
3678 if(player->peer_id == PEER_ID_INEXISTENT)
3681 std::set<std::string> privs;
3682 m_script->getAuth(player->getName(), NULL, &privs);
3684 std::ostringstream os(std::ios_base::binary);
3685 writeU16(os, TOCLIENT_PRIVILEGES);
3686 writeU16(os, privs.size());
3687 for(std::set<std::string>::const_iterator i = privs.begin();
3688 i != privs.end(); i++){
3689 os<<serializeString(*i);
3693 std::string s = os.str();
3694 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3696 m_clients.send(peer_id, 0, data, true);
3699 void Server::SendPlayerInventoryFormspec(u16 peer_id)
3701 Player *player = m_env->getPlayer(peer_id);
3703 if(player->peer_id == PEER_ID_INEXISTENT)
3706 std::ostringstream os(std::ios_base::binary);
3707 writeU16(os, TOCLIENT_INVENTORY_FORMSPEC);
3708 os<<serializeLongString(FORMSPEC_VERSION_STRING + player->inventory_formspec);
3711 std::string s = os.str();
3712 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3714 m_clients.send(peer_id, 0, data, true);
3717 s32 Server::playSound(const SimpleSoundSpec &spec,
3718 const ServerSoundParams ¶ms)
3720 // Find out initial position of sound
3721 bool pos_exists = false;
3722 v3f pos = params.getPos(m_env, &pos_exists);
3723 // If position is not found while it should be, cancel sound
3724 if(pos_exists != (params.type != ServerSoundParams::SSP_LOCAL))
3727 // Filter destination clients
3728 std::list<u16> dst_clients;
3729 if(params.to_player != "")
3731 Player *player = m_env->getPlayer(params.to_player.c_str());
3733 infostream<<"Server::playSound: Player \""<<params.to_player
3734 <<"\" not found"<<std::endl;
3737 if(player->peer_id == PEER_ID_INEXISTENT){
3738 infostream<<"Server::playSound: Player \""<<params.to_player
3739 <<"\" not connected"<<std::endl;
3742 dst_clients.push_back(player->peer_id);
3746 std::list<u16> clients = m_clients.getClientIDs();
3748 for(std::list<u16>::iterator
3749 i = clients.begin(); i != clients.end(); ++i)
3751 Player *player = m_env->getPlayer(*i);
3755 if(player->getPosition().getDistanceFrom(pos) >
3756 params.max_hear_distance)
3759 dst_clients.push_back(*i);
3762 if(dst_clients.empty())
3766 s32 id = m_next_sound_id++;
3767 // The sound will exist as a reference in m_playing_sounds
3768 m_playing_sounds[id] = ServerPlayingSound();
3769 ServerPlayingSound &psound = m_playing_sounds[id];
3770 psound.params = params;
3771 for(std::list<u16>::iterator i = dst_clients.begin();
3772 i != dst_clients.end(); i++)
3773 psound.clients.insert(*i);
3775 std::ostringstream os(std::ios_base::binary);
3776 writeU16(os, TOCLIENT_PLAY_SOUND);
3778 os<<serializeString(spec.name);
3779 writeF1000(os, spec.gain * params.gain);
3780 writeU8(os, params.type);
3781 writeV3F1000(os, pos);
3782 writeU16(os, params.object);
3783 writeU8(os, params.loop);
3785 std::string s = os.str();
3786 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3788 for(std::list<u16>::iterator i = dst_clients.begin();
3789 i != dst_clients.end(); i++){
3791 m_clients.send(*i, 0, data, true);
3795 void Server::stopSound(s32 handle)
3797 // Get sound reference
3798 std::map<s32, ServerPlayingSound>::iterator i =
3799 m_playing_sounds.find(handle);
3800 if(i == m_playing_sounds.end())
3802 ServerPlayingSound &psound = i->second;
3804 std::ostringstream os(std::ios_base::binary);
3805 writeU16(os, TOCLIENT_STOP_SOUND);
3806 writeS32(os, handle);
3808 std::string s = os.str();
3809 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3811 for(std::set<u16>::iterator i = psound.clients.begin();
3812 i != psound.clients.end(); i++){
3814 m_clients.send(*i, 0, data, true);
3816 // Remove sound reference
3817 m_playing_sounds.erase(i);
3820 void Server::sendRemoveNode(v3s16 p, u16 ignore_id,
3821 std::list<u16> *far_players, float far_d_nodes)
3823 float maxd = far_d_nodes*BS;
3824 v3f p_f = intToFloat(p, BS);
3828 SharedBuffer<u8> reply(replysize);
3829 writeU16(&reply[0], TOCLIENT_REMOVENODE);
3830 writeS16(&reply[2], p.X);
3831 writeS16(&reply[4], p.Y);
3832 writeS16(&reply[6], p.Z);
3834 std::list<u16> clients = m_clients.getClientIDs();
3835 for(std::list<u16>::iterator
3836 i = clients.begin();
3837 i != clients.end(); ++i)
3842 Player *player = m_env->getPlayer(*i);
3845 // If player is far away, only set modified blocks not sent
3846 v3f player_pos = player->getPosition();
3847 if(player_pos.getDistanceFrom(p_f) > maxd)
3849 far_players->push_back(*i);
3856 m_clients.send(*i, 0, reply, true);
3860 void Server::sendAddNode(v3s16 p, MapNode n, u16 ignore_id,
3861 std::list<u16> *far_players, float far_d_nodes,
3862 bool remove_metadata)
3864 float maxd = far_d_nodes*BS;
3865 v3f p_f = intToFloat(p, BS);
3867 std::list<u16> clients = m_clients.getClientIDs();
3868 for(std::list<u16>::iterator
3869 i = clients.begin();
3870 i != clients.end(); ++i)
3876 Player *player = m_env->getPlayer(*i);
3879 // If player is far away, only set modified blocks not sent
3880 v3f player_pos = player->getPosition();
3881 if(player_pos.getDistanceFrom(p_f) > maxd)
3883 far_players->push_back(*i);
3888 SharedBuffer<u8> reply(0);
3890 RemoteClient* client = m_clients.lockedGetClientNoEx(*i);
3894 u32 replysize = 9 + MapNode::serializedLength(client->serialization_version);
3895 reply = SharedBuffer<u8>(replysize);
3896 writeU16(&reply[0], TOCLIENT_ADDNODE);
3897 writeS16(&reply[2], p.X);
3898 writeS16(&reply[4], p.Y);
3899 writeS16(&reply[6], p.Z);
3900 n.serialize(&reply[8], client->serialization_version);
3901 u32 index = 8 + MapNode::serializedLength(client->serialization_version);
3902 writeU8(&reply[index], remove_metadata ? 0 : 1);
3904 if (!remove_metadata) {
3905 if (client->net_proto_version <= 21) {
3906 // Old clients always clear metadata; fix it
3907 // by sending the full block again.
3908 client->SetBlockNotSent(p);
3915 if (reply.getSize() > 0)
3916 m_clients.send(*i, 0, reply, true);
3920 void Server::setBlockNotSent(v3s16 p)
3922 std::list<u16> clients = m_clients.getClientIDs();
3924 for(std::list<u16>::iterator
3925 i = clients.begin();
3926 i != clients.end(); ++i)
3928 RemoteClient *client = m_clients.lockedGetClientNoEx(*i);
3929 client->SetBlockNotSent(p);
3934 void Server::SendBlockNoLock(u16 peer_id, MapBlock *block, u8 ver, u16 net_proto_version)
3936 DSTACK(__FUNCTION_NAME);
3938 v3s16 p = block->getPos();
3942 bool completely_air = true;
3943 for(s16 z0=0; z0<MAP_BLOCKSIZE; z0++)
3944 for(s16 x0=0; x0<MAP_BLOCKSIZE; x0++)
3945 for(s16 y0=0; y0<MAP_BLOCKSIZE; y0++)
3947 if(block->getNodeNoEx(v3s16(x0,y0,z0)).d != CONTENT_AIR)
3949 completely_air = false;
3950 x0 = y0 = z0 = MAP_BLOCKSIZE; // Break out
3955 infostream<<"Server: Sending block ("<<p.X<<","<<p.Y<<","<<p.Z<<"): ";
3957 infostream<<"[completely air] ";
3958 infostream<<std::endl;
3962 Create a packet with the block in the right format
3965 std::ostringstream os(std::ios_base::binary);
3966 block->serialize(os, ver, false);
3967 block->serializeNetworkSpecific(os, net_proto_version);
3968 std::string s = os.str();
3969 SharedBuffer<u8> blockdata((u8*)s.c_str(), s.size());
3971 u32 replysize = 8 + blockdata.getSize();
3972 SharedBuffer<u8> reply(replysize);
3973 writeU16(&reply[0], TOCLIENT_BLOCKDATA);
3974 writeS16(&reply[2], p.X);
3975 writeS16(&reply[4], p.Y);
3976 writeS16(&reply[6], p.Z);
3977 memcpy(&reply[8], *blockdata, blockdata.getSize());
3979 /*infostream<<"Server: Sending block ("<<p.X<<","<<p.Y<<","<<p.Z<<")"
3980 <<": \tpacket size: "<<replysize<<std::endl;*/
3985 m_clients.send(peer_id, 2, reply, true);
3988 void Server::SendBlocks(float dtime)
3990 DSTACK(__FUNCTION_NAME);
3992 JMutexAutoLock envlock(m_env_mutex);
3993 //TODO check if one big lock could be faster then multiple small ones
3995 ScopeProfiler sp(g_profiler, "Server: sel and send blocks to clients");
3997 std::vector<PrioritySortedBlockTransfer> queue;
3999 s32 total_sending = 0;
4002 ScopeProfiler sp(g_profiler, "Server: selecting blocks for sending");
4004 std::list<u16> clients = m_clients.getClientIDs();
4007 for(std::list<u16>::iterator
4008 i = clients.begin();
4009 i != clients.end(); ++i)
4011 RemoteClient *client = m_clients.lockedGetClientNoEx(*i, CS_Active);
4016 total_sending += client->SendingCount();
4017 client->GetNextBlocks(m_env,m_emerge, dtime, queue);
4023 // Lowest priority number comes first.
4024 // Lowest is most important.
4025 std::sort(queue.begin(), queue.end());
4028 for(u32 i=0; i<queue.size(); i++)
4030 //TODO: Calculate limit dynamically
4031 if(total_sending >= g_settings->getS32
4032 ("max_simultaneous_block_sends_server_total"))
4035 PrioritySortedBlockTransfer q = queue[i];
4037 MapBlock *block = NULL;
4040 block = m_env->getMap().getBlockNoCreate(q.pos);
4042 catch(InvalidPositionException &e)
4047 RemoteClient *client = m_clients.lockedGetClientNoEx(q.peer_id, CS_Active);
4052 SendBlockNoLock(q.peer_id, block, client->serialization_version, client->net_proto_version);
4054 client->SentBlock(q.pos);
4060 void Server::fillMediaCache()
4062 DSTACK(__FUNCTION_NAME);
4064 infostream<<"Server: Calculating media file checksums"<<std::endl;
4066 // Collect all media file paths
4067 std::list<std::string> paths;
4068 for(std::vector<ModSpec>::iterator i = m_mods.begin();
4069 i != m_mods.end(); i++){
4070 const ModSpec &mod = *i;
4071 paths.push_back(mod.path + DIR_DELIM + "textures");
4072 paths.push_back(mod.path + DIR_DELIM + "sounds");
4073 paths.push_back(mod.path + DIR_DELIM + "media");
4074 paths.push_back(mod.path + DIR_DELIM + "models");
4076 paths.push_back(porting::path_user + DIR_DELIM + "textures" + DIR_DELIM + "server");
4078 // Collect media file information from paths into cache
4079 for(std::list<std::string>::iterator i = paths.begin();
4080 i != paths.end(); i++)
4082 std::string mediapath = *i;
4083 std::vector<fs::DirListNode> dirlist = fs::GetDirListing(mediapath);
4084 for(u32 j=0; j<dirlist.size(); j++){
4085 if(dirlist[j].dir) // Ignode dirs
4087 std::string filename = dirlist[j].name;
4088 // If name contains illegal characters, ignore the file
4089 if(!string_allowed(filename, TEXTURENAME_ALLOWED_CHARS)){
4090 infostream<<"Server: ignoring illegal file name: \""
4091 <<filename<<"\""<<std::endl;
4094 // If name is not in a supported format, ignore it
4095 const char *supported_ext[] = {
4096 ".png", ".jpg", ".bmp", ".tga",
4097 ".pcx", ".ppm", ".psd", ".wal", ".rgb",
4099 ".x", ".b3d", ".md2", ".obj",
4102 if(removeStringEnd(filename, supported_ext) == ""){
4103 infostream<<"Server: ignoring unsupported file extension: \""
4104 <<filename<<"\""<<std::endl;
4107 // Ok, attempt to load the file and add to cache
4108 std::string filepath = mediapath + DIR_DELIM + filename;
4110 std::ifstream fis(filepath.c_str(), std::ios_base::binary);
4111 if(fis.good() == false){
4112 errorstream<<"Server::fillMediaCache(): Could not open \""
4113 <<filename<<"\" for reading"<<std::endl;
4116 std::ostringstream tmp_os(std::ios_base::binary);
4120 fis.read(buf, 1024);
4121 std::streamsize len = fis.gcount();
4122 tmp_os.write(buf, len);
4131 errorstream<<"Server::fillMediaCache(): Failed to read \""
4132 <<filename<<"\""<<std::endl;
4135 if(tmp_os.str().length() == 0){
4136 errorstream<<"Server::fillMediaCache(): Empty file \""
4137 <<filepath<<"\""<<std::endl;
4142 sha1.addBytes(tmp_os.str().c_str(), tmp_os.str().length());
4144 unsigned char *digest = sha1.getDigest();
4145 std::string sha1_base64 = base64_encode(digest, 20);
4146 std::string sha1_hex = hex_encode((char*)digest, 20);
4150 this->m_media[filename] = MediaInfo(filepath, sha1_base64);
4151 verbosestream<<"Server: "<<sha1_hex<<" is "<<filename<<std::endl;
4156 struct SendableMediaAnnouncement
4159 std::string sha1_digest;
4161 SendableMediaAnnouncement(const std::string &name_="",
4162 const std::string &sha1_digest_=""):
4164 sha1_digest(sha1_digest_)
4168 void Server::sendMediaAnnouncement(u16 peer_id)
4170 DSTACK(__FUNCTION_NAME);
4172 verbosestream<<"Server: Announcing files to id("<<peer_id<<")"
4175 std::list<SendableMediaAnnouncement> file_announcements;
4177 for(std::map<std::string, MediaInfo>::iterator i = m_media.begin();
4178 i != m_media.end(); i++){
4180 file_announcements.push_back(
4181 SendableMediaAnnouncement(i->first, i->second.sha1_digest));
4185 std::ostringstream os(std::ios_base::binary);
4193 u16 length of sha1_digest
4198 writeU16(os, TOCLIENT_ANNOUNCE_MEDIA);
4199 writeU16(os, file_announcements.size());
4201 for(std::list<SendableMediaAnnouncement>::iterator
4202 j = file_announcements.begin();
4203 j != file_announcements.end(); ++j){
4204 os<<serializeString(j->name);
4205 os<<serializeString(j->sha1_digest);
4207 os<<serializeString(g_settings->get("remote_media"));
4210 std::string s = os.str();
4211 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
4214 m_clients.send(peer_id, 0, data, true);
4217 struct SendableMedia
4223 SendableMedia(const std::string &name_="", const std::string &path_="",
4224 const std::string &data_=""):
4231 void Server::sendRequestedMedia(u16 peer_id,
4232 const std::list<std::string> &tosend)
4234 DSTACK(__FUNCTION_NAME);
4236 verbosestream<<"Server::sendRequestedMedia(): "
4237 <<"Sending files to client"<<std::endl;
4241 // Put 5kB in one bunch (this is not accurate)
4242 u32 bytes_per_bunch = 5000;
4244 std::vector< std::list<SendableMedia> > file_bunches;
4245 file_bunches.push_back(std::list<SendableMedia>());
4247 u32 file_size_bunch_total = 0;
4249 for(std::list<std::string>::const_iterator i = tosend.begin();
4250 i != tosend.end(); ++i)
4252 const std::string &name = *i;
4254 if(m_media.find(name) == m_media.end()){
4255 errorstream<<"Server::sendRequestedMedia(): Client asked for "
4256 <<"unknown file \""<<(name)<<"\""<<std::endl;
4260 //TODO get path + name
4261 std::string tpath = m_media[name].path;
4264 std::ifstream fis(tpath.c_str(), std::ios_base::binary);
4265 if(fis.good() == false){
4266 errorstream<<"Server::sendRequestedMedia(): Could not open \""
4267 <<tpath<<"\" for reading"<<std::endl;
4270 std::ostringstream tmp_os(std::ios_base::binary);
4274 fis.read(buf, 1024);
4275 std::streamsize len = fis.gcount();
4276 tmp_os.write(buf, len);
4277 file_size_bunch_total += len;
4286 errorstream<<"Server::sendRequestedMedia(): Failed to read \""
4287 <<name<<"\""<<std::endl;
4290 /*infostream<<"Server::sendRequestedMedia(): Loaded \""
4291 <<tname<<"\""<<std::endl;*/
4293 file_bunches[file_bunches.size()-1].push_back(
4294 SendableMedia(name, tpath, tmp_os.str()));
4296 // Start next bunch if got enough data
4297 if(file_size_bunch_total >= bytes_per_bunch){
4298 file_bunches.push_back(std::list<SendableMedia>());
4299 file_size_bunch_total = 0;
4304 /* Create and send packets */
4306 u32 num_bunches = file_bunches.size();
4307 for(u32 i=0; i<num_bunches; i++)
4309 std::ostringstream os(std::ios_base::binary);
4313 u16 total number of texture bunches
4314 u16 index of this bunch
4315 u32 number of files in this bunch
4324 writeU16(os, TOCLIENT_MEDIA);
4325 writeU16(os, num_bunches);
4327 writeU32(os, file_bunches[i].size());
4329 for(std::list<SendableMedia>::iterator
4330 j = file_bunches[i].begin();
4331 j != file_bunches[i].end(); ++j){
4332 os<<serializeString(j->name);
4333 os<<serializeLongString(j->data);
4337 std::string s = os.str();
4338 verbosestream<<"Server::sendRequestedMedia(): bunch "
4339 <<i<<"/"<<num_bunches
4340 <<" files="<<file_bunches[i].size()
4341 <<" size=" <<s.size()<<std::endl;
4342 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
4344 m_clients.send(peer_id, 2, data, true);
4348 void Server::sendDetachedInventory(const std::string &name, u16 peer_id)
4350 if(m_detached_inventories.count(name) == 0){
4351 errorstream<<__FUNCTION_NAME<<": \""<<name<<"\" not found"<<std::endl;
4354 Inventory *inv = m_detached_inventories[name];
4356 std::ostringstream os(std::ios_base::binary);
4357 writeU16(os, TOCLIENT_DETACHED_INVENTORY);
4358 os<<serializeString(name);
4362 std::string s = os.str();
4363 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
4365 if (peer_id != PEER_ID_INEXISTENT)
4368 m_clients.send(peer_id, 0, data, true);
4372 m_clients.sendToAll(0,data,true);
4376 void Server::sendDetachedInventories(u16 peer_id)
4378 DSTACK(__FUNCTION_NAME);
4380 for(std::map<std::string, Inventory*>::iterator
4381 i = m_detached_inventories.begin();
4382 i != m_detached_inventories.end(); i++){
4383 const std::string &name = i->first;
4384 //Inventory *inv = i->second;
4385 sendDetachedInventory(name, peer_id);
4393 void Server::DiePlayer(u16 peer_id)
4395 DSTACK(__FUNCTION_NAME);
4397 PlayerSAO *playersao = getPlayerSAO(peer_id);
4400 infostream<<"Server::DiePlayer(): Player "
4401 <<playersao->getPlayer()->getName()
4402 <<" dies"<<std::endl;
4404 playersao->setHP(0);
4406 // Trigger scripted stuff
4407 m_script->on_dieplayer(playersao);
4409 SendPlayerHP(peer_id);
4410 SendDeathscreen(peer_id, false, v3f(0,0,0));
4413 void Server::RespawnPlayer(u16 peer_id)
4415 DSTACK(__FUNCTION_NAME);
4417 PlayerSAO *playersao = getPlayerSAO(peer_id);
4420 infostream<<"Server::RespawnPlayer(): Player "
4421 <<playersao->getPlayer()->getName()
4422 <<" respawns"<<std::endl;
4424 playersao->setHP(PLAYER_MAX_HP);
4425 playersao->setBreath(PLAYER_MAX_BREATH);
4427 bool repositioned = m_script->on_respawnplayer(playersao);
4429 v3f pos = findSpawnPos(m_env->getServerMap());
4430 playersao->setPos(pos);
4434 void Server::DenyAccess(u16 peer_id, const std::wstring &reason)
4436 DSTACK(__FUNCTION_NAME);
4438 SendAccessDenied(peer_id, reason);
4439 m_clients.event(peer_id, CSE_SetDenied);
4440 m_con.DisconnectPeer(peer_id);
4443 void Server::DeleteClient(u16 peer_id, ClientDeletionReason reason)
4445 DSTACK(__FUNCTION_NAME);
4446 std::wstring message;
4449 Clear references to playing sounds
4451 for(std::map<s32, ServerPlayingSound>::iterator
4452 i = m_playing_sounds.begin();
4453 i != m_playing_sounds.end();)
4455 ServerPlayingSound &psound = i->second;
4456 psound.clients.erase(peer_id);
4457 if(psound.clients.empty())
4458 m_playing_sounds.erase(i++);
4463 Player *player = m_env->getPlayer(peer_id);
4465 // Collect information about leaving in chat
4467 if(player != NULL && reason != CDR_DENY)
4469 std::wstring name = narrow_to_wide(player->getName());
4472 message += L" left the game.";
4473 if(reason == CDR_TIMEOUT)
4474 message += L" (timed out)";
4478 /* Run scripts and remove from environment */
4482 PlayerSAO *playersao = player->getPlayerSAO();
4485 m_script->on_leaveplayer(playersao);
4487 playersao->disconnected();
4495 if(player != NULL && reason != CDR_DENY)
4497 std::ostringstream os(std::ios_base::binary);
4498 std::list<u16> clients = m_clients.getClientIDs();
4500 for(std::list<u16>::iterator
4501 i = clients.begin();
4502 i != clients.end(); ++i)
4505 Player *player = m_env->getPlayer(*i);
4508 // Get name of player
4509 os<<player->getName()<<" ";
4512 actionstream<<player->getName()<<" "
4513 <<(reason==CDR_TIMEOUT?"times out.":"leaves game.")
4514 <<" List of players: "<<os.str()<<std::endl;
4518 JMutexAutoLock env_lock(m_env_mutex);
4519 m_clients.DeleteClient(peer_id);
4523 // Send leave chat message to all remaining clients
4524 if(message.length() != 0)
4525 SendChatMessage(PEER_ID_INEXISTENT,message);
4528 void Server::UpdateCrafting(u16 peer_id)
4530 DSTACK(__FUNCTION_NAME);
4532 Player* player = m_env->getPlayer(peer_id);
4535 // Get a preview for crafting
4537 InventoryLocation loc;
4538 loc.setPlayer(player->getName());
4539 getCraftingResult(&player->inventory, preview, false, this);
4540 m_env->getScriptIface()->item_CraftPredict(preview, player->getPlayerSAO(), (&player->inventory)->getList("craft"), loc);
4542 // Put the new preview in
4543 InventoryList *plist = player->inventory.getList("craftpreview");
4545 assert(plist->getSize() >= 1);
4546 plist->changeItem(0, preview);
4549 RemoteClient* Server::getClient(u16 peer_id, ClientState state_min)
4551 RemoteClient *client = getClientNoEx(peer_id,state_min);
4553 throw ClientNotFoundException("Client not found");
4557 RemoteClient* Server::getClientNoEx(u16 peer_id, ClientState state_min)
4559 return m_clients.getClientNoEx(peer_id, state_min);
4562 std::string Server::getPlayerName(u16 peer_id)
4564 Player *player = m_env->getPlayer(peer_id);
4566 return "[id="+itos(peer_id)+"]";
4567 return player->getName();
4570 PlayerSAO* Server::getPlayerSAO(u16 peer_id)
4572 Player *player = m_env->getPlayer(peer_id);
4575 return player->getPlayerSAO();
4578 std::wstring Server::getStatusString()
4580 std::wostringstream os(std::ios_base::binary);
4583 os<<L"version="<<narrow_to_wide(minetest_version_simple);
4585 os<<L", uptime="<<m_uptime.get();
4587 os<<L", max_lag="<<m_env->getMaxLagEstimate();
4588 // Information about clients
4591 std::list<u16> clients = m_clients.getClientIDs();
4592 for(std::list<u16>::iterator i = clients.begin();
4593 i != clients.end(); ++i)
4596 Player *player = m_env->getPlayer(*i);
4597 // Get name of player
4598 std::wstring name = L"unknown";
4600 name = narrow_to_wide(player->getName());
4601 // Add name to information string
4609 if(((ServerMap*)(&m_env->getMap()))->isSavingEnabled() == false)
4610 os<<std::endl<<L"# Server: "<<" WARNING: Map saving is disabled.";
4611 if(g_settings->get("motd") != "")
4612 os<<std::endl<<L"# Server: "<<narrow_to_wide(g_settings->get("motd"));
4616 std::set<std::string> Server::getPlayerEffectivePrivs(const std::string &name)
4618 std::set<std::string> privs;
4619 m_script->getAuth(name, NULL, &privs);
4623 bool Server::checkPriv(const std::string &name, const std::string &priv)
4625 std::set<std::string> privs = getPlayerEffectivePrivs(name);
4626 return (privs.count(priv) != 0);
4629 void Server::reportPrivsModified(const std::string &name)
4632 std::list<u16> clients = m_clients.getClientIDs();
4633 for(std::list<u16>::iterator
4634 i = clients.begin();
4635 i != clients.end(); ++i){
4636 Player *player = m_env->getPlayer(*i);
4637 reportPrivsModified(player->getName());
4640 Player *player = m_env->getPlayer(name.c_str());
4643 SendPlayerPrivileges(player->peer_id);
4644 PlayerSAO *sao = player->getPlayerSAO();
4647 sao->updatePrivileges(
4648 getPlayerEffectivePrivs(name),
4653 void Server::reportInventoryFormspecModified(const std::string &name)
4655 Player *player = m_env->getPlayer(name.c_str());
4658 SendPlayerInventoryFormspec(player->peer_id);
4661 void Server::setIpBanned(const std::string &ip, const std::string &name)
4663 m_banmanager->add(ip, name);
4666 void Server::unsetIpBanned(const std::string &ip_or_name)
4668 m_banmanager->remove(ip_or_name);
4671 std::string Server::getBanDescription(const std::string &ip_or_name)
4673 return m_banmanager->getBanDescription(ip_or_name);
4676 void Server::notifyPlayer(const char *name, const std::wstring &msg)
4678 Player *player = m_env->getPlayer(name);
4682 if (player->peer_id == PEER_ID_INEXISTENT)
4685 SendChatMessage(player->peer_id, msg);
4688 bool Server::showFormspec(const char *playername, const std::string &formspec, const std::string &formname)
4690 Player *player = m_env->getPlayer(playername);
4694 infostream<<"showFormspec: couldn't find player:"<<playername<<std::endl;
4698 SendShowFormspecMessage(player->peer_id, formspec, formname);
4702 u32 Server::hudAdd(Player *player, HudElement *form) {
4706 u32 id = player->addHud(form);
4708 SendHUDAdd(player->peer_id, id, form);
4713 bool Server::hudRemove(Player *player, u32 id) {
4717 HudElement* todel = player->removeHud(id);
4724 SendHUDRemove(player->peer_id, id);
4728 bool Server::hudChange(Player *player, u32 id, HudElementStat stat, void *data) {
4732 SendHUDChange(player->peer_id, id, stat, data);
4736 bool Server::hudSetFlags(Player *player, u32 flags, u32 mask) {
4740 SendHUDSetFlags(player->peer_id, flags, mask);
4741 player->hud_flags = flags;
4743 PlayerSAO* playersao = player->getPlayerSAO();
4745 if (playersao == NULL)
4748 m_script->player_event(playersao, "hud_changed");
4752 bool Server::hudSetHotbarItemcount(Player *player, s32 hotbar_itemcount) {
4755 if (hotbar_itemcount <= 0 || hotbar_itemcount > HUD_HOTBAR_ITEMCOUNT_MAX)
4758 std::ostringstream os(std::ios::binary);
4759 writeS32(os, hotbar_itemcount);
4760 SendHUDSetParam(player->peer_id, HUD_PARAM_HOTBAR_ITEMCOUNT, os.str());
4764 void Server::hudSetHotbarImage(Player *player, std::string name) {
4768 SendHUDSetParam(player->peer_id, HUD_PARAM_HOTBAR_IMAGE, name);
4771 void Server::hudSetHotbarSelectedImage(Player *player, std::string name) {
4775 SendHUDSetParam(player->peer_id, HUD_PARAM_HOTBAR_SELECTED_IMAGE, name);
4778 bool Server::setLocalPlayerAnimations(Player *player, v2s32 animation_frames[4], f32 frame_speed)
4783 SendLocalPlayerAnimations(player->peer_id, animation_frames, frame_speed);
4787 bool Server::setPlayerEyeOffset(Player *player, v3f first, v3f third)
4792 SendEyeOffset(player->peer_id, first, third);
4796 bool Server::setSky(Player *player, const video::SColor &bgcolor,
4797 const std::string &type, const std::vector<std::string> ¶ms)
4802 SendSetSky(player->peer_id, bgcolor, type, params);
4806 bool Server::overrideDayNightRatio(Player *player, bool do_override,
4812 SendOverrideDayNightRatio(player->peer_id, do_override, ratio);
4816 void Server::notifyPlayers(const std::wstring &msg)
4818 SendChatMessage(PEER_ID_INEXISTENT,msg);
4821 void Server::spawnParticle(const char *playername, v3f pos,
4822 v3f velocity, v3f acceleration,
4823 float expirationtime, float size, bool
4824 collisiondetection, bool vertical, std::string texture)
4826 Player *player = m_env->getPlayer(playername);
4829 SendSpawnParticle(player->peer_id, pos, velocity, acceleration,
4830 expirationtime, size, collisiondetection, vertical, texture);
4833 void Server::spawnParticleAll(v3f pos, v3f velocity, v3f acceleration,
4834 float expirationtime, float size,
4835 bool collisiondetection, bool vertical, std::string texture)
4837 SendSpawnParticle(PEER_ID_INEXISTENT,pos, velocity, acceleration,
4838 expirationtime, size, collisiondetection, vertical, texture);
4841 u32 Server::addParticleSpawner(const char *playername,
4842 u16 amount, float spawntime,
4843 v3f minpos, v3f maxpos,
4844 v3f minvel, v3f maxvel,
4845 v3f minacc, v3f maxacc,
4846 float minexptime, float maxexptime,
4847 float minsize, float maxsize,
4848 bool collisiondetection, bool vertical, std::string texture)
4850 Player *player = m_env->getPlayer(playername);
4855 for(;;) // look for unused particlespawner id
4858 if (std::find(m_particlespawner_ids.begin(),
4859 m_particlespawner_ids.end(), id)
4860 == m_particlespawner_ids.end())
4862 m_particlespawner_ids.push_back(id);
4867 SendAddParticleSpawner(player->peer_id, amount, spawntime,
4868 minpos, maxpos, minvel, maxvel, minacc, maxacc,
4869 minexptime, maxexptime, minsize, maxsize,
4870 collisiondetection, vertical, texture, id);
4875 u32 Server::addParticleSpawnerAll(u16 amount, float spawntime,
4876 v3f minpos, v3f maxpos,
4877 v3f minvel, v3f maxvel,
4878 v3f minacc, v3f maxacc,
4879 float minexptime, float maxexptime,
4880 float minsize, float maxsize,
4881 bool collisiondetection, bool vertical, std::string texture)
4884 for(;;) // look for unused particlespawner id
4887 if (std::find(m_particlespawner_ids.begin(),
4888 m_particlespawner_ids.end(), id)
4889 == m_particlespawner_ids.end())
4891 m_particlespawner_ids.push_back(id);
4896 SendAddParticleSpawner(PEER_ID_INEXISTENT, amount, spawntime,
4897 minpos, maxpos, minvel, maxvel, minacc, maxacc,
4898 minexptime, maxexptime, minsize, maxsize,
4899 collisiondetection, vertical, texture, id);
4904 void Server::deleteParticleSpawner(const char *playername, u32 id)
4906 Player *player = m_env->getPlayer(playername);
4910 m_particlespawner_ids.erase(
4911 std::remove(m_particlespawner_ids.begin(),
4912 m_particlespawner_ids.end(), id),
4913 m_particlespawner_ids.end());
4914 SendDeleteParticleSpawner(player->peer_id, id);
4917 void Server::deleteParticleSpawnerAll(u32 id)
4919 m_particlespawner_ids.erase(
4920 std::remove(m_particlespawner_ids.begin(),
4921 m_particlespawner_ids.end(), id),
4922 m_particlespawner_ids.end());
4923 SendDeleteParticleSpawner(PEER_ID_INEXISTENT, id);
4926 Inventory* Server::createDetachedInventory(const std::string &name)
4928 if(m_detached_inventories.count(name) > 0){
4929 infostream<<"Server clearing detached inventory \""<<name<<"\""<<std::endl;
4930 delete m_detached_inventories[name];
4932 infostream<<"Server creating detached inventory \""<<name<<"\""<<std::endl;
4934 Inventory *inv = new Inventory(m_itemdef);
4936 m_detached_inventories[name] = inv;
4937 //TODO find a better way to do this
4938 sendDetachedInventory(name,PEER_ID_INEXISTENT);
4945 BoolScopeSet(bool *dst, bool val):
4948 m_orig_state = *m_dst;
4953 *m_dst = m_orig_state;
4960 // actions: time-reversed list
4961 // Return value: success/failure
4962 bool Server::rollbackRevertActions(const std::list<RollbackAction> &actions,
4963 std::list<std::string> *log)
4965 infostream<<"Server::rollbackRevertActions(len="<<actions.size()<<")"<<std::endl;
4966 ServerMap *map = (ServerMap*)(&m_env->getMap());
4968 // Fail if no actions to handle
4969 if(actions.empty()){
4970 log->push_back("Nothing to do.");
4977 for(std::list<RollbackAction>::const_iterator
4978 i = actions.begin();
4979 i != actions.end(); i++)
4981 const RollbackAction &action = *i;
4983 bool success = action.applyRevert(map, this, this);
4986 std::ostringstream os;
4987 os<<"Revert of step ("<<num_tried<<") "<<action.toString()<<" failed";
4988 infostream<<"Map::rollbackRevertActions(): "<<os.str()<<std::endl;
4990 log->push_back(os.str());
4992 std::ostringstream os;
4993 os<<"Successfully reverted step ("<<num_tried<<") "<<action.toString();
4994 infostream<<"Map::rollbackRevertActions(): "<<os.str()<<std::endl;
4996 log->push_back(os.str());
5000 infostream<<"Map::rollbackRevertActions(): "<<num_failed<<"/"<<num_tried
5001 <<" failed"<<std::endl;
5003 // Call it done if less than half failed
5004 return num_failed <= num_tried/2;
5007 // IGameDef interface
5009 IItemDefManager* Server::getItemDefManager()
5013 INodeDefManager* Server::getNodeDefManager()
5017 ICraftDefManager* Server::getCraftDefManager()
5021 ITextureSource* Server::getTextureSource()
5025 IShaderSource* Server::getShaderSource()
5029 scene::ISceneManager* Server::getSceneManager()
5034 u16 Server::allocateUnknownNodeId(const std::string &name)
5036 return m_nodedef->allocateDummy(name);
5038 ISoundManager* Server::getSoundManager()
5040 return &dummySoundManager;
5042 MtEventManager* Server::getEventManager()
5047 IWritableItemDefManager* Server::getWritableItemDefManager()
5051 IWritableNodeDefManager* Server::getWritableNodeDefManager()
5055 IWritableCraftDefManager* Server::getWritableCraftDefManager()
5060 const ModSpec* Server::getModSpec(const std::string &modname)
5062 for(std::vector<ModSpec>::iterator i = m_mods.begin();
5063 i != m_mods.end(); i++){
5064 const ModSpec &mod = *i;
5065 if(mod.name == modname)
5070 void Server::getModNames(std::list<std::string> &modlist)
5072 for(std::vector<ModSpec>::iterator i = m_mods.begin(); i != m_mods.end(); i++)
5074 modlist.push_back(i->name);
5077 std::string Server::getBuiltinLuaPath()
5079 return porting::path_share + DIR_DELIM + "builtin";
5082 v3f findSpawnPos(ServerMap &map)
5084 //return v3f(50,50,50)*BS;
5089 nodepos = v2s16(0,0);
5094 s16 water_level = map.getWaterLevel();
5096 // Try to find a good place a few times
5097 for(s32 i=0; i<1000; i++)
5100 // We're going to try to throw the player to this position
5101 v2s16 nodepos2d = v2s16(
5102 -range + (myrand() % (range * 2)),
5103 -range + (myrand() % (range * 2)));
5105 // Get ground height at point
5106 s16 groundheight = map.findGroundLevel(nodepos2d);
5107 if (groundheight <= water_level) // Don't go underwater
5109 if (groundheight > water_level + 6) // Don't go to high places
5112 nodepos = v3s16(nodepos2d.X, groundheight, nodepos2d.Y);
5113 bool is_good = false;
5115 for (s32 i = 0; i < 10; i++) {
5116 v3s16 blockpos = getNodeBlockPos(nodepos);
5117 map.emergeBlock(blockpos, true);
5118 content_t c = map.getNodeNoEx(nodepos).getContent();
5119 if (c == CONTENT_AIR || c == CONTENT_IGNORE) {
5121 if (air_count >= 2){
5129 // Found a good place
5130 //infostream<<"Searched through "<<i<<" places."<<std::endl;
5136 return intToFloat(nodepos, BS);
5139 PlayerSAO* Server::emergePlayer(const char *name, u16 peer_id)
5141 RemotePlayer *player = NULL;
5142 bool newplayer = false;
5145 Try to get an existing player
5147 player = static_cast<RemotePlayer*>(m_env->getPlayer(name));
5149 // If player is already connected, cancel
5150 if(player != NULL && player->peer_id != 0)
5152 infostream<<"emergePlayer(): Player already connected"<<std::endl;
5157 If player with the wanted peer_id already exists, cancel.
5159 if(m_env->getPlayer(peer_id) != NULL)
5161 infostream<<"emergePlayer(): Player with wrong name but same"
5162 " peer_id already exists"<<std::endl;
5166 // Load player if it isn't already loaded
5168 player = static_cast<RemotePlayer*>(m_env->loadPlayer(name));
5171 // Create player if it doesn't exist
5174 player = new RemotePlayer(this, name);
5175 // Set player position
5176 infostream<<"Server: Finding spawn place for player \""
5177 <<name<<"\""<<std::endl;
5178 v3f pos = findSpawnPos(m_env->getServerMap());
5179 player->setPosition(pos);
5181 // Make sure the player is saved
5182 player->setModified(true);
5184 // Add player to environment
5185 m_env->addPlayer(player);
5188 // Create a new player active object
5189 PlayerSAO *playersao = new PlayerSAO(m_env, player, peer_id,
5190 getPlayerEffectivePrivs(player->getName()),
5193 /* Clean up old HUD elements from previous sessions */
5196 /* Add object to environment */
5197 m_env->addActiveObject(playersao);
5201 m_script->on_newplayer(playersao);
5207 void dedicated_server_loop(Server &server, bool &kill)
5209 DSTACK(__FUNCTION_NAME);
5211 verbosestream<<"dedicated_server_loop()"<<std::endl;
5213 IntervalLimiter m_profiler_interval;
5217 float steplen = g_settings->getFloat("dedicated_server_step");
5218 // This is kind of a hack but can be done like this
5219 // because server.step() is very light
5221 ScopeProfiler sp(g_profiler, "dedicated server sleep");
5222 sleep_ms((int)(steplen*1000.0));
5224 server.step(steplen);
5226 if(server.getShutdownRequested() || kill)
5228 infostream<<"Dedicated server quitting"<<std::endl;
5230 if(g_settings->getBool("server_announce"))
5231 ServerList::sendAnnounce("delete", server.m_bind_addr.getPort());
5239 float profiler_print_interval =
5240 g_settings->getFloat("profiler_print_interval");
5241 if(profiler_print_interval != 0)
5243 if(m_profiler_interval.step(steplen, profiler_print_interval))
5245 infostream<<"Profiler:"<<std::endl;
5246 g_profiler->print(infostream);
5247 g_profiler->clear();