3 Copyright (C) 2010-2013 celeron55, Perttu Ahola <celeron55@gmail.com>
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU Lesser General Public License as published by
7 the Free Software Foundation; either version 2.1 of the License, or
8 (at your option) any later version.
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU Lesser General Public License for more details.
15 You should have received a copy of the GNU Lesser General Public License along
16 with this program; if not, write to the Free Software Foundation, Inc.,
17 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
24 #include "clientserver.h"
26 #include "environment.h"
28 #include "jthread/jmutexautolock.h"
30 #include "constants.h"
36 #include "serverobject.h"
37 #include "genericobject.h"
41 #include "scripting_game.h"
48 #include "content_mapnode.h"
49 #include "content_nodemeta.h"
50 #include "content_abm.h"
51 #include "content_sao.h"
56 #include "sound.h" // dummySoundManager
57 #include "event_manager.h"
59 #include "serverlist.h"
60 #include "util/string.h"
61 #include "util/pointedthing.h"
62 #include "util/mathconstants.h"
64 #include "util/serialize.h"
65 #include "util/thread.h"
66 #include "defaultsettings.h"
68 class ClientNotFoundException : public BaseException
71 ClientNotFoundException(const char *s):
76 class ServerThread : public JThread
82 ServerThread(Server *server):
91 void * ServerThread::Thread()
93 log_register_thread("ServerThread");
95 DSTACK(__FUNCTION_NAME);
96 BEGIN_DEBUG_EXCEPTION_HANDLER
98 m_server->AsyncRunStep(true);
102 while(!StopRequested())
105 //TimeTaker timer("AsyncRunStep() + Receive()");
107 m_server->AsyncRunStep();
112 catch(con::NoIncomingDataException &e)
115 catch(con::PeerNotFoundException &e)
117 infostream<<"Server: PeerNotFoundException"<<std::endl;
119 catch(ClientNotFoundException &e)
122 catch(con::ConnectionBindFailed &e)
124 m_server->setAsyncFatalError(e.what());
128 m_server->setAsyncFatalError(e.what());
132 END_DEBUG_EXCEPTION_HANDLER(errorstream)
137 v3f ServerSoundParams::getPos(ServerEnvironment *env, bool *pos_exists) const
139 if(pos_exists) *pos_exists = false;
144 if(pos_exists) *pos_exists = true;
149 ServerActiveObject *sao = env->getActiveObject(object);
152 if(pos_exists) *pos_exists = true;
153 return sao->getBasePosition(); }
165 const std::string &path_world,
166 const SubgameSpec &gamespec,
167 bool simple_singleplayer_mode
169 m_path_world(path_world),
170 m_gamespec(gamespec),
171 m_simple_singleplayer_mode(simple_singleplayer_mode),
172 m_async_fatal_error(""),
177 g_settings->getBool("enable_ipv6") && g_settings->getBool("ipv6_server"),
181 m_rollback_sink_enabled(true),
182 m_enable_rollback_recording(false),
185 m_itemdef(createItemDefManager()),
186 m_nodedef(createNodeDefManager()),
187 m_craftdef(createCraftDefManager()),
188 m_event(new EventManager()),
190 m_time_of_day_send_timer(0),
193 m_shutdown_requested(false),
194 m_ignore_map_edit_events(false),
195 m_ignore_map_edit_events_peer_id(0)
198 m_liquid_transform_timer = 0.0;
199 m_liquid_transform_every = 1.0;
200 m_print_info_timer = 0.0;
201 m_masterserver_timer = 0.0;
202 m_objectdata_timer = 0.0;
203 m_emergethread_trigger_timer = 0.0;
204 m_savemap_timer = 0.0;
207 m_lag = g_settings->getFloat("dedicated_server_step");
210 throw ServerError("Supplied empty world path");
212 if(!gamespec.isValid())
213 throw ServerError("Supplied invalid gamespec");
215 infostream<<"Server created for gameid \""<<m_gamespec.id<<"\"";
216 if(m_simple_singleplayer_mode)
217 infostream<<" in simple singleplayer mode"<<std::endl;
219 infostream<<std::endl;
220 infostream<<"- world: "<<m_path_world<<std::endl;
221 infostream<<"- game: "<<m_gamespec.path<<std::endl;
223 // Initialize default settings and override defaults with those provided
225 set_default_settings(g_settings);
226 Settings gamedefaults;
227 getGameMinetestConfig(gamespec.path, gamedefaults);
228 override_default_settings(g_settings, &gamedefaults);
230 // Create server thread
231 m_thread = new ServerThread(this);
233 // Create emerge manager
234 m_emerge = new EmergeManager(this);
236 // Create world if it doesn't exist
237 if(!initializeWorld(m_path_world, m_gamespec.id))
238 throw ServerError("Failed to initialize world");
240 // Create ban manager
241 std::string ban_path = m_path_world+DIR_DELIM+"ipban.txt";
242 m_banmanager = new BanManager(ban_path);
244 // Create rollback manager
245 std::string rollback_path = m_path_world+DIR_DELIM+"rollback.txt";
246 m_rollback = createRollbackManager(rollback_path, this);
248 ModConfiguration modconf(m_path_world);
249 m_mods = modconf.getMods();
250 std::vector<ModSpec> unsatisfied_mods = modconf.getUnsatisfiedMods();
251 // complain about mods with unsatisfied dependencies
252 if(!modconf.isConsistent())
254 for(std::vector<ModSpec>::iterator it = unsatisfied_mods.begin();
255 it != unsatisfied_mods.end(); ++it)
258 errorstream << "mod \"" << mod.name << "\" has unsatisfied dependencies: ";
259 for(std::set<std::string>::iterator dep_it = mod.unsatisfied_depends.begin();
260 dep_it != mod.unsatisfied_depends.end(); ++dep_it)
261 errorstream << " \"" << *dep_it << "\"";
262 errorstream << std::endl;
266 Settings worldmt_settings;
267 std::string worldmt = m_path_world + DIR_DELIM + "world.mt";
268 worldmt_settings.readConfigFile(worldmt.c_str());
269 std::vector<std::string> names = worldmt_settings.getNames();
270 std::set<std::string> load_mod_names;
271 for(std::vector<std::string>::iterator it = names.begin();
272 it != names.end(); ++it)
274 std::string name = *it;
275 if(name.compare(0,9,"load_mod_")==0 && worldmt_settings.getBool(name))
276 load_mod_names.insert(name.substr(9));
278 // complain about mods declared to be loaded, but not found
279 for(std::vector<ModSpec>::iterator it = m_mods.begin();
280 it != m_mods.end(); ++it)
281 load_mod_names.erase((*it).name);
282 for(std::vector<ModSpec>::iterator it = unsatisfied_mods.begin();
283 it != unsatisfied_mods.end(); ++it)
284 load_mod_names.erase((*it).name);
285 if(!load_mod_names.empty())
287 errorstream << "The following mods could not be found:";
288 for(std::set<std::string>::iterator it = load_mod_names.begin();
289 it != load_mod_names.end(); ++it)
290 errorstream << " \"" << (*it) << "\"";
291 errorstream << std::endl;
294 // Path to builtin.lua
295 std::string builtinpath = getBuiltinLuaPath() + DIR_DELIM + "builtin.lua";
298 JMutexAutoLock envlock(m_env_mutex);
300 // Initialize scripting
301 infostream<<"Server: Initializing Lua"<<std::endl;
303 m_script = new GameScripting(this);
306 // Load and run builtin.lua
307 infostream<<"Server: Loading builtin.lua [\""
308 <<builtinpath<<"\"]"<<std::endl;
309 bool success = m_script->loadMod(builtinpath, "__builtin");
311 errorstream<<"Server: Failed to load and run "
312 <<builtinpath<<std::endl;
313 throw ModError("Failed to load and run "+builtinpath);
316 infostream<<"Server: Loading mods: ";
317 for(std::vector<ModSpec>::iterator i = m_mods.begin();
318 i != m_mods.end(); i++){
319 const ModSpec &mod = *i;
320 infostream<<mod.name<<" ";
322 infostream<<std::endl;
323 // Load and run "mod" scripts
324 for(std::vector<ModSpec>::iterator i = m_mods.begin();
325 i != m_mods.end(); i++){
326 const ModSpec &mod = *i;
327 std::string scriptpath = mod.path + DIR_DELIM + "init.lua";
328 infostream<<" ["<<padStringRight(mod.name, 12)<<"] [\""
329 <<scriptpath<<"\"]"<<std::endl;
330 bool success = m_script->loadMod(scriptpath, mod.name);
332 errorstream<<"Server: Failed to load and run "
333 <<scriptpath<<std::endl;
334 throw ModError("Failed to load and run "+scriptpath);
338 // Read Textures and calculate sha1 sums
341 // Apply item aliases in the node definition manager
342 m_nodedef->updateAliases(m_itemdef);
344 // Initialize Environment
345 ServerMap *servermap = new ServerMap(path_world, this, m_emerge);
346 m_env = new ServerEnvironment(servermap, m_script, this);
348 m_clients.setEnv(m_env);
350 // Run some callbacks after the MG params have been set up but before activation
351 m_script->environment_OnMapgenInit(&m_emerge->params);
353 // Initialize mapgens
354 m_emerge->initMapgens();
356 // Give environment reference to scripting api
357 m_script->initializeEnvironment(m_env);
359 // Register us to receive map edit events
360 servermap->addEventReceiver(this);
362 // If file exists, load environment metadata
363 if(fs::PathExists(m_path_world+DIR_DELIM+"env_meta.txt"))
365 infostream<<"Server: Loading environment metadata"<<std::endl;
366 m_env->loadMeta(m_path_world);
370 infostream<<"Server: Loading players"<<std::endl;
371 m_env->deSerializePlayers(m_path_world);
374 Add some test ActiveBlockModifiers to environment
376 add_legacy_abms(m_env, m_nodedef);
378 m_liquid_transform_every = g_settings->getFloat("liquid_update");
383 infostream<<"Server destructing"<<std::endl;
386 Send shutdown message
389 std::wstring line = L"*** Server shutting down";
390 SendChatMessage(PEER_ID_INEXISTENT, line);
394 JMutexAutoLock envlock(m_env_mutex);
397 Execute script shutdown hooks
399 m_script->on_shutdown();
403 JMutexAutoLock envlock(m_env_mutex);
408 infostream<<"Server: Saving players"<<std::endl;
409 m_env->serializePlayers(m_path_world);
412 Save environment metadata
414 infostream<<"Server: Saving environment metadata"<<std::endl;
415 m_env->saveMeta(m_path_world);
424 // stop all emerge threads before deleting players that may have
425 // requested blocks to be emerged
426 m_emerge->stopThreads();
428 // Delete things in the reverse order of creation
431 // N.B. the EmergeManager should be deleted after the Environment since Map
432 // depends on EmergeManager to write its current params to the map meta
441 // Deinitialize scripting
442 infostream<<"Server: Deinitializing scripting"<<std::endl;
445 // Delete detached inventories
447 for(std::map<std::string, Inventory*>::iterator
448 i = m_detached_inventories.begin();
449 i != m_detached_inventories.end(); i++){
455 void Server::start(Address bind_addr)
457 DSTACK(__FUNCTION_NAME);
458 infostream<<"Starting server on "
459 << bind_addr.serializeString() <<"..."<<std::endl;
461 // Stop thread if already running
464 // Initialize connection
465 m_con.SetTimeoutMs(30);
466 m_con.Serve(bind_addr);
471 // ASCII art for the win!
473 <<" .__ __ __ "<<std::endl
474 <<" _____ |__| ____ _____/ |_ ____ _______/ |_ "<<std::endl
475 <<" / \\| |/ \\_/ __ \\ __\\/ __ \\ / ___/\\ __\\"<<std::endl
476 <<"| Y Y \\ | | \\ ___/| | \\ ___/ \\___ \\ | | "<<std::endl
477 <<"|__|_| /__|___| /\\___ >__| \\___ >____ > |__| "<<std::endl
478 <<" \\/ \\/ \\/ \\/ \\/ "<<std::endl;
479 actionstream<<"World at ["<<m_path_world<<"]"<<std::endl;
480 actionstream<<"Server for gameid=\""<<m_gamespec.id
481 <<"\" listening on "<<bind_addr.serializeString()<<":"
482 <<bind_addr.getPort() << "."<<std::endl;
487 DSTACK(__FUNCTION_NAME);
489 infostream<<"Server: Stopping and waiting threads"<<std::endl;
491 // Stop threads (set run=false first so both start stopping)
493 //m_emergethread.setRun(false);
495 //m_emergethread.stop();
497 infostream<<"Server: Threads stopped"<<std::endl;
500 void Server::step(float dtime)
502 DSTACK(__FUNCTION_NAME);
507 JMutexAutoLock lock(m_step_dtime_mutex);
508 m_step_dtime += dtime;
510 // Throw if fatal error occurred in thread
511 std::string async_err = m_async_fatal_error.get();
513 throw ServerError(async_err);
517 void Server::AsyncRunStep(bool initial_step)
519 DSTACK(__FUNCTION_NAME);
521 g_profiler->add("Server::AsyncRunStep (num)", 1);
525 JMutexAutoLock lock1(m_step_dtime_mutex);
526 dtime = m_step_dtime;
530 // Send blocks to clients
534 if((dtime < 0.001) && (initial_step == false))
537 g_profiler->add("Server::AsyncRunStep with dtime (num)", 1);
539 //infostream<<"Server steps "<<dtime<<std::endl;
540 //infostream<<"Server::AsyncRunStep(): dtime="<<dtime<<std::endl;
543 JMutexAutoLock lock1(m_step_dtime_mutex);
544 m_step_dtime -= dtime;
551 m_uptime.set(m_uptime.get() + dtime);
557 Update time of day and overall game time
560 JMutexAutoLock envlock(m_env_mutex);
562 m_env->setTimeOfDaySpeed(g_settings->getFloat("time_speed"));
565 Send to clients at constant intervals
568 m_time_of_day_send_timer -= dtime;
569 if(m_time_of_day_send_timer < 0.0)
571 m_time_of_day_send_timer = g_settings->getFloat("time_send_interval");
572 u16 time = m_env->getTimeOfDay();
573 float time_speed = g_settings->getFloat("time_speed");
574 SendTimeOfDay(PEER_ID_INEXISTENT, time, time_speed);
579 JMutexAutoLock lock(m_env_mutex);
580 // Figure out and report maximum lag to environment
581 float max_lag = m_env->getMaxLagEstimate();
582 max_lag *= 0.9998; // Decrease slowly (about half per 5 minutes)
584 if(dtime > 0.1 && dtime > max_lag * 2.0)
585 infostream<<"Server: Maximum lag peaked to "<<dtime
589 m_env->reportMaxLagEstimate(max_lag);
591 ScopeProfiler sp(g_profiler, "SEnv step");
592 ScopeProfiler sp2(g_profiler, "SEnv step avg", SPT_AVG);
596 const float map_timer_and_unload_dtime = 2.92;
597 if(m_map_timer_and_unload_interval.step(dtime, map_timer_and_unload_dtime))
599 JMutexAutoLock lock(m_env_mutex);
600 // Run Map's timers and unload unused data
601 ScopeProfiler sp(g_profiler, "Server: map timer and unload");
602 m_env->getMap().timerUpdate(map_timer_and_unload_dtime,
603 g_settings->getFloat("server_unload_unused_data_timeout"));
614 JMutexAutoLock lock(m_env_mutex);
616 std::list<u16> clientids = m_clients.getClientIDs();
618 ScopeProfiler sp(g_profiler, "Server: handle players");
620 for(std::list<u16>::iterator
621 i = clientids.begin();
622 i != clientids.end(); ++i)
624 PlayerSAO *playersao = getPlayerSAO(*i);
625 if(playersao == NULL)
629 Handle player HPs (die if hp=0)
631 if(playersao->m_hp_not_sent && g_settings->getBool("enable_damage"))
633 if(playersao->getHP() == 0)
640 Send player breath if changed
642 if(playersao->m_breath_not_sent){
643 SendPlayerBreath(*i);
647 Send player inventories if necessary
649 if(playersao->m_moved){
651 playersao->m_moved = false;
653 if(playersao->m_inventory_not_sent){
660 /* Transform liquids */
661 m_liquid_transform_timer += dtime;
662 if(m_liquid_transform_timer >= m_liquid_transform_every)
664 m_liquid_transform_timer -= m_liquid_transform_every;
666 JMutexAutoLock lock(m_env_mutex);
668 ScopeProfiler sp(g_profiler, "Server: liquid transform");
670 std::map<v3s16, MapBlock*> modified_blocks;
671 m_env->getMap().transformLiquids(modified_blocks);
676 core::map<v3s16, MapBlock*> lighting_modified_blocks;
677 ServerMap &map = ((ServerMap&)m_env->getMap());
678 map.updateLighting(modified_blocks, lighting_modified_blocks);
680 // Add blocks modified by lighting to modified_blocks
681 for(core::map<v3s16, MapBlock*>::Iterator
682 i = lighting_modified_blocks.getIterator();
683 i.atEnd() == false; i++)
685 MapBlock *block = i.getNode()->getValue();
686 modified_blocks.insert(block->getPos(), block);
690 Set the modified blocks unsent for all the clients
692 if(modified_blocks.size() > 0)
694 SetBlocksNotSent(modified_blocks);
697 m_clients.step(dtime);
699 m_lag += (m_lag > dtime ? -1 : 1) * dtime/100;
701 // send masterserver announce
703 float &counter = m_masterserver_timer;
704 if(!isSingleplayer() && (!counter || counter >= 300.0) &&
705 g_settings->getBool("server_announce") == true)
707 ServerList::sendAnnounce(!counter ? "start" : "update",
708 m_clients.getPlayerNames(),
710 m_env->getGameTime(),
721 Check added and deleted active objects
724 //infostream<<"Server: Checking added and deleted active objects"<<std::endl;
725 JMutexAutoLock envlock(m_env_mutex);
728 std::map<u16, RemoteClient*> clients = m_clients.getClientList();
729 ScopeProfiler sp(g_profiler, "Server: checking added and deleted objs");
731 // Radius inside which objects are active
732 s16 radius = g_settings->getS16("active_object_send_range_blocks");
733 radius *= MAP_BLOCKSIZE;
735 for(std::map<u16, RemoteClient*>::iterator
737 i != clients.end(); ++i)
739 RemoteClient *client = i->second;
741 // If definitions and textures have not been sent, don't
742 // send objects either
743 if (client->getState() < DefinitionsSent)
746 Player *player = m_env->getPlayer(client->peer_id);
749 // This can happen if the client timeouts somehow
750 /*infostream<<"WARNING: "<<__FUNCTION_NAME<<": Client "
752 <<" has no associated player"<<std::endl;*/
755 v3s16 pos = floatToInt(player->getPosition(), BS);
757 std::set<u16> removed_objects;
758 std::set<u16> added_objects;
759 m_env->getRemovedActiveObjects(pos, radius,
760 client->m_known_objects, removed_objects);
761 m_env->getAddedActiveObjects(pos, radius,
762 client->m_known_objects, added_objects);
764 // Ignore if nothing happened
765 if(removed_objects.size() == 0 && added_objects.size() == 0)
767 //infostream<<"active objects: none changed"<<std::endl;
771 std::string data_buffer;
775 // Handle removed objects
776 writeU16((u8*)buf, removed_objects.size());
777 data_buffer.append(buf, 2);
778 for(std::set<u16>::iterator
779 i = removed_objects.begin();
780 i != removed_objects.end(); ++i)
784 ServerActiveObject* obj = m_env->getActiveObject(id);
786 // Add to data buffer for sending
787 writeU16((u8*)buf, id);
788 data_buffer.append(buf, 2);
790 // Remove from known objects
791 client->m_known_objects.erase(id);
793 if(obj && obj->m_known_by_count > 0)
794 obj->m_known_by_count--;
797 // Handle added objects
798 writeU16((u8*)buf, added_objects.size());
799 data_buffer.append(buf, 2);
800 for(std::set<u16>::iterator
801 i = added_objects.begin();
802 i != added_objects.end(); ++i)
806 ServerActiveObject* obj = m_env->getActiveObject(id);
809 u8 type = ACTIVEOBJECT_TYPE_INVALID;
811 infostream<<"WARNING: "<<__FUNCTION_NAME
812 <<": NULL object"<<std::endl;
814 type = obj->getSendType();
816 // Add to data buffer for sending
817 writeU16((u8*)buf, id);
818 data_buffer.append(buf, 2);
819 writeU8((u8*)buf, type);
820 data_buffer.append(buf, 1);
823 data_buffer.append(serializeLongString(
824 obj->getClientInitializationData(client->net_proto_version)));
826 data_buffer.append(serializeLongString(""));
828 // Add to known objects
829 client->m_known_objects.insert(id);
832 obj->m_known_by_count++;
836 SharedBuffer<u8> reply(2 + data_buffer.size());
837 writeU16(&reply[0], TOCLIENT_ACTIVE_OBJECT_REMOVE_ADD);
838 memcpy((char*)&reply[2], data_buffer.c_str(),
841 m_clients.send(client->peer_id, 0, reply, true);
843 verbosestream<<"Server: Sent object remove/add: "
844 <<removed_objects.size()<<" removed, "
845 <<added_objects.size()<<" added, "
846 <<"packet size is "<<reply.getSize()<<std::endl;
851 Collect a list of all the objects known by the clients
852 and report it back to the environment.
855 core::map<u16, bool> all_known_objects;
857 for(core::map<u16, RemoteClient*>::Iterator
858 i = m_clients.getIterator();
859 i.atEnd() == false; i++)
861 RemoteClient *client = i.getNode()->getValue();
862 // Go through all known objects of client
863 for(core::map<u16, bool>::Iterator
864 i = client->m_known_objects.getIterator();
865 i.atEnd()==false; i++)
867 u16 id = i.getNode()->getKey();
868 all_known_objects[id] = true;
872 m_env->setKnownActiveObjects(whatever);
881 JMutexAutoLock envlock(m_env_mutex);
882 ScopeProfiler sp(g_profiler, "Server: sending object messages");
885 // Value = data sent by object
886 std::map<u16, std::list<ActiveObjectMessage>* > buffered_messages;
888 // Get active object messages from environment
891 ActiveObjectMessage aom = m_env->getActiveObjectMessage();
895 std::list<ActiveObjectMessage>* message_list = NULL;
896 std::map<u16, std::list<ActiveObjectMessage>* >::iterator n;
897 n = buffered_messages.find(aom.id);
898 if(n == buffered_messages.end())
900 message_list = new std::list<ActiveObjectMessage>;
901 buffered_messages[aom.id] = message_list;
905 message_list = n->second;
907 message_list->push_back(aom);
911 std::map<u16, RemoteClient*> clients = m_clients.getClientList();
912 // Route data to every client
913 for(std::map<u16, RemoteClient*>::iterator
915 i != clients.end(); ++i)
917 RemoteClient *client = i->second;
918 std::string reliable_data;
919 std::string unreliable_data;
920 // Go through all objects in message buffer
921 for(std::map<u16, std::list<ActiveObjectMessage>* >::iterator
922 j = buffered_messages.begin();
923 j != buffered_messages.end(); ++j)
925 // If object is not known by client, skip it
927 if(client->m_known_objects.find(id) == client->m_known_objects.end())
929 // Get message list of object
930 std::list<ActiveObjectMessage>* list = j->second;
931 // Go through every message
932 for(std::list<ActiveObjectMessage>::iterator
933 k = list->begin(); k != list->end(); ++k)
935 // Compose the full new data with header
936 ActiveObjectMessage aom = *k;
937 std::string new_data;
940 writeU16((u8*)&buf[0], aom.id);
941 new_data.append(buf, 2);
943 new_data += serializeString(aom.datastring);
944 // Add data to buffer
946 reliable_data += new_data;
948 unreliable_data += new_data;
952 reliable_data and unreliable_data are now ready.
955 if(reliable_data.size() > 0)
957 SharedBuffer<u8> reply(2 + reliable_data.size());
958 writeU16(&reply[0], TOCLIENT_ACTIVE_OBJECT_MESSAGES);
959 memcpy((char*)&reply[2], reliable_data.c_str(),
960 reliable_data.size());
962 m_clients.send(client->peer_id, 0, reply, true);
964 if(unreliable_data.size() > 0)
966 SharedBuffer<u8> reply(2 + unreliable_data.size());
967 writeU16(&reply[0], TOCLIENT_ACTIVE_OBJECT_MESSAGES);
968 memcpy((char*)&reply[2], unreliable_data.c_str(),
969 unreliable_data.size());
970 // Send as unreliable
971 m_clients.send(client->peer_id, 1, reply, false);
974 /*if(reliable_data.size() > 0 || unreliable_data.size() > 0)
976 infostream<<"Server: Size of object message data: "
977 <<"reliable: "<<reliable_data.size()
978 <<", unreliable: "<<unreliable_data.size()
984 // Clear buffered_messages
985 for(std::map<u16, std::list<ActiveObjectMessage>* >::iterator
986 i = buffered_messages.begin();
987 i != buffered_messages.end(); ++i)
994 Send queued-for-sending map edit events.
997 // We will be accessing the environment
998 JMutexAutoLock lock(m_env_mutex);
1000 // Don't send too many at a time
1003 // Single change sending is disabled if queue size is not small
1004 bool disable_single_change_sending = false;
1005 if(m_unsent_map_edit_queue.size() >= 4)
1006 disable_single_change_sending = true;
1008 int event_count = m_unsent_map_edit_queue.size();
1010 // We'll log the amount of each
1013 while(m_unsent_map_edit_queue.size() != 0)
1015 MapEditEvent* event = m_unsent_map_edit_queue.pop_front();
1017 // Players far away from the change are stored here.
1018 // Instead of sending the changes, MapBlocks are set not sent
1020 std::list<u16> far_players;
1022 if(event->type == MEET_ADDNODE || event->type == MEET_SWAPNODE)
1024 //infostream<<"Server: MEET_ADDNODE"<<std::endl;
1025 prof.add("MEET_ADDNODE", 1);
1026 if(disable_single_change_sending)
1027 sendAddNode(event->p, event->n, event->already_known_by_peer,
1028 &far_players, 5, event->type == MEET_ADDNODE);
1030 sendAddNode(event->p, event->n, event->already_known_by_peer,
1031 &far_players, 30, event->type == MEET_ADDNODE);
1033 else if(event->type == MEET_REMOVENODE)
1035 //infostream<<"Server: MEET_REMOVENODE"<<std::endl;
1036 prof.add("MEET_REMOVENODE", 1);
1037 if(disable_single_change_sending)
1038 sendRemoveNode(event->p, event->already_known_by_peer,
1041 sendRemoveNode(event->p, event->already_known_by_peer,
1044 else if(event->type == MEET_BLOCK_NODE_METADATA_CHANGED)
1046 infostream<<"Server: MEET_BLOCK_NODE_METADATA_CHANGED"<<std::endl;
1047 prof.add("MEET_BLOCK_NODE_METADATA_CHANGED", 1);
1048 setBlockNotSent(event->p);
1050 else if(event->type == MEET_OTHER)
1052 infostream<<"Server: MEET_OTHER"<<std::endl;
1053 prof.add("MEET_OTHER", 1);
1054 for(std::set<v3s16>::iterator
1055 i = event->modified_blocks.begin();
1056 i != event->modified_blocks.end(); ++i)
1058 setBlockNotSent(*i);
1063 prof.add("unknown", 1);
1064 infostream<<"WARNING: Server: Unknown MapEditEvent "
1065 <<((u32)event->type)<<std::endl;
1069 Set blocks not sent to far players
1071 if(far_players.size() > 0)
1073 // Convert list format to that wanted by SetBlocksNotSent
1074 std::map<v3s16, MapBlock*> modified_blocks2;
1075 for(std::set<v3s16>::iterator
1076 i = event->modified_blocks.begin();
1077 i != event->modified_blocks.end(); ++i)
1079 modified_blocks2[*i] =
1080 m_env->getMap().getBlockNoCreateNoEx(*i);
1082 // Set blocks not sent
1083 for(std::list<u16>::iterator
1084 i = far_players.begin();
1085 i != far_players.end(); ++i)
1088 RemoteClient *client = getClient(peer_id);
1091 client->SetBlocksNotSent(modified_blocks2);
1097 /*// Don't send too many at a time
1099 if(count >= 1 && m_unsent_map_edit_queue.size() < 100)
1103 if(event_count >= 5){
1104 infostream<<"Server: MapEditEvents:"<<std::endl;
1105 prof.print(infostream);
1106 } else if(event_count != 0){
1107 verbosestream<<"Server: MapEditEvents:"<<std::endl;
1108 prof.print(verbosestream);
1114 Trigger emergethread (it somehow gets to a non-triggered but
1115 bysy state sometimes)
1118 float &counter = m_emergethread_trigger_timer;
1124 m_emerge->startThreads();
1126 // Update m_enable_rollback_recording here too
1127 m_enable_rollback_recording =
1128 g_settings->getBool("enable_rollback_recording");
1132 // Save map, players and auth stuff
1134 float &counter = m_savemap_timer;
1136 if(counter >= g_settings->getFloat("server_map_save_interval"))
1139 JMutexAutoLock lock(m_env_mutex);
1141 ScopeProfiler sp(g_profiler, "Server: saving stuff");
1144 if(m_banmanager->isModified())
1145 m_banmanager->save();
1147 // Save changed parts of map
1148 m_env->getMap().save(MOD_STATE_WRITE_NEEDED);
1151 m_env->serializePlayers(m_path_world);
1153 // Save environment metadata
1154 m_env->saveMeta(m_path_world);
1159 void Server::Receive()
1161 DSTACK(__FUNCTION_NAME);
1162 SharedBuffer<u8> data;
1166 datasize = m_con.Receive(peer_id,data);
1167 ProcessData(*data, datasize, peer_id);
1169 catch(con::InvalidIncomingDataException &e)
1171 infostream<<"Server::Receive(): "
1172 "InvalidIncomingDataException: what()="
1173 <<e.what()<<std::endl;
1175 catch(con::PeerNotFoundException &e)
1177 //NOTE: This is not needed anymore
1179 // The peer has been disconnected.
1180 // Find the associated player and remove it.
1182 /*JMutexAutoLock envlock(m_env_mutex);
1184 infostream<<"ServerThread: peer_id="<<peer_id
1185 <<" has apparently closed connection. "
1186 <<"Removing player."<<std::endl;
1188 m_env->removePlayer(peer_id);*/
1192 void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
1194 DSTACK(__FUNCTION_NAME);
1195 // Environment is locked first.
1196 JMutexAutoLock envlock(m_env_mutex);
1198 ScopeProfiler sp(g_profiler, "Server::ProcessData");
1202 Address address = getPeerAddress(peer_id);
1203 addr_s = address.serializeString();
1205 // drop player if is ip is banned
1206 if(m_banmanager->isIpBanned(addr_s)){
1207 std::string ban_name = m_banmanager->getBanName(addr_s);
1208 infostream<<"Server: A banned client tried to connect from "
1209 <<addr_s<<"; banned name was "
1210 <<ban_name<<std::endl;
1211 // This actually doesn't seem to transfer to the client
1212 DenyAccess(peer_id, L"Your ip is banned. Banned name was "
1213 +narrow_to_wide(ban_name));
1217 catch(con::PeerNotFoundException &e)
1219 errorstream<<"Server::ProcessData(): Cancelling: peer "
1220 <<peer_id<<" not found"<<std::endl;
1230 ToServerCommand command = (ToServerCommand)readU16(&data[0]);
1232 if(command == TOSERVER_INIT)
1234 // [0] u16 TOSERVER_INIT
1235 // [2] u8 SER_FMT_VER_HIGHEST_READ
1236 // [3] u8[20] player_name
1237 // [23] u8[28] password <--- can be sent without this, from old versions
1239 if(datasize < 2+1+PLAYERNAME_SIZE)
1242 RemoteClient* client = getClient(peer_id,Created);
1244 // If net_proto_version is set, this client has already been handled
1245 if(client->getState() > Created)
1247 verbosestream<<"Server: Ignoring multiple TOSERVER_INITs from "
1248 <<addr_s<<" (peer_id="<<peer_id<<")"<<std::endl;
1252 verbosestream<<"Server: Got TOSERVER_INIT from "<<addr_s<<" (peer_id="
1253 <<peer_id<<")"<<std::endl;
1255 // Do not allow multiple players in simple singleplayer mode.
1256 // This isn't a perfect way to do it, but will suffice for now
1257 if(m_simple_singleplayer_mode && m_clients.getClientIDs().size() > 1){
1258 infostream<<"Server: Not allowing another client ("<<addr_s
1259 <<") to connect in simple singleplayer mode"<<std::endl;
1260 DenyAccess(peer_id, L"Running in simple singleplayer mode.");
1264 // First byte after command is maximum supported
1265 // serialization version
1266 u8 client_max = data[2];
1267 u8 our_max = SER_FMT_VER_HIGHEST_READ;
1268 // Use the highest version supported by both
1269 u8 deployed = std::min(client_max, our_max);
1270 // If it's lower than the lowest supported, give up.
1271 if(deployed < SER_FMT_VER_LOWEST)
1272 deployed = SER_FMT_VER_INVALID;
1274 if(deployed == SER_FMT_VER_INVALID)
1276 actionstream<<"Server: A mismatched client tried to connect from "
1277 <<addr_s<<std::endl;
1278 infostream<<"Server: Cannot negotiate serialization version with "
1279 <<addr_s<<std::endl;
1280 DenyAccess(peer_id, std::wstring(
1281 L"Your client's version is not supported.\n"
1282 L"Server version is ")
1283 + narrow_to_wide(minetest_version_simple) + L"."
1288 client->setPendingSerializationVersion(deployed);
1291 Read and check network protocol version
1294 u16 min_net_proto_version = 0;
1295 if(datasize >= 2+1+PLAYERNAME_SIZE+PASSWORD_SIZE+2)
1296 min_net_proto_version = readU16(&data[2+1+PLAYERNAME_SIZE+PASSWORD_SIZE]);
1298 // Use same version as minimum and maximum if maximum version field
1299 // doesn't exist (backwards compatibility)
1300 u16 max_net_proto_version = min_net_proto_version;
1301 if(datasize >= 2+1+PLAYERNAME_SIZE+PASSWORD_SIZE+2+2)
1302 max_net_proto_version = readU16(&data[2+1+PLAYERNAME_SIZE+PASSWORD_SIZE+2]);
1304 // Start with client's maximum version
1305 u16 net_proto_version = max_net_proto_version;
1307 // Figure out a working version if it is possible at all
1308 if(max_net_proto_version >= SERVER_PROTOCOL_VERSION_MIN ||
1309 min_net_proto_version <= SERVER_PROTOCOL_VERSION_MAX)
1311 // If maximum is larger than our maximum, go with our maximum
1312 if(max_net_proto_version > SERVER_PROTOCOL_VERSION_MAX)
1313 net_proto_version = SERVER_PROTOCOL_VERSION_MAX;
1314 // Else go with client's maximum
1316 net_proto_version = max_net_proto_version;
1319 verbosestream<<"Server: "<<addr_s<<": Protocol version: min: "
1320 <<min_net_proto_version<<", max: "<<max_net_proto_version
1321 <<", chosen: "<<net_proto_version<<std::endl;
1323 client->net_proto_version = net_proto_version;
1325 if(net_proto_version < SERVER_PROTOCOL_VERSION_MIN ||
1326 net_proto_version > SERVER_PROTOCOL_VERSION_MAX)
1328 actionstream<<"Server: A mismatched client tried to connect from "
1329 <<addr_s<<std::endl;
1330 DenyAccess(peer_id, std::wstring(
1331 L"Your client's version is not supported.\n"
1332 L"Server version is ")
1333 + narrow_to_wide(minetest_version_simple) + L",\n"
1334 + L"server's PROTOCOL_VERSION is "
1335 + narrow_to_wide(itos(SERVER_PROTOCOL_VERSION_MIN))
1337 + narrow_to_wide(itos(SERVER_PROTOCOL_VERSION_MAX))
1338 + L", client's PROTOCOL_VERSION is "
1339 + narrow_to_wide(itos(min_net_proto_version))
1341 + narrow_to_wide(itos(max_net_proto_version))
1346 if(g_settings->getBool("strict_protocol_version_checking"))
1348 if(net_proto_version != LATEST_PROTOCOL_VERSION)
1350 actionstream<<"Server: A mismatched (strict) client tried to "
1351 <<"connect from "<<addr_s<<std::endl;
1352 DenyAccess(peer_id, std::wstring(
1353 L"Your client's version is not supported.\n"
1354 L"Server version is ")
1355 + narrow_to_wide(minetest_version_simple) + L",\n"
1356 + L"server's PROTOCOL_VERSION (strict) is "
1357 + narrow_to_wide(itos(LATEST_PROTOCOL_VERSION))
1358 + L", client's PROTOCOL_VERSION is "
1359 + narrow_to_wide(itos(min_net_proto_version))
1361 + narrow_to_wide(itos(max_net_proto_version))
1372 char playername[PLAYERNAME_SIZE];
1373 for(u32 i=0; i<PLAYERNAME_SIZE-1; i++)
1375 playername[i] = data[3+i];
1377 playername[PLAYERNAME_SIZE-1] = 0;
1379 if(playername[0]=='\0')
1381 actionstream<<"Server: Player with an empty name "
1382 <<"tried to connect from "<<addr_s<<std::endl;
1383 DenyAccess(peer_id, L"Empty name");
1387 if(string_allowed(playername, PLAYERNAME_ALLOWED_CHARS)==false)
1389 actionstream<<"Server: Player with an invalid name "
1390 <<"tried to connect from "<<addr_s<<std::endl;
1391 DenyAccess(peer_id, L"Name contains unallowed characters");
1395 if(!isSingleplayer() && strcasecmp(playername, "singleplayer") == 0)
1397 actionstream<<"Server: Player with the name \"singleplayer\" "
1398 <<"tried to connect from "<<addr_s<<std::endl;
1399 DenyAccess(peer_id, L"Name is not allowed");
1405 if(m_script->on_prejoinplayer(playername, addr_s, reason))
1407 actionstream<<"Server: Player with the name \""<<playername<<"\" "
1408 <<"tried to connect from "<<addr_s<<" "
1409 <<"but it was disallowed for the following reason: "
1410 <<reason<<std::endl;
1411 DenyAccess(peer_id, narrow_to_wide(reason.c_str()));
1416 infostream<<"Server: New connection: \""<<playername<<"\" from "
1417 <<addr_s<<" (peer_id="<<peer_id<<")"<<std::endl;
1420 char given_password[PASSWORD_SIZE];
1421 if(datasize < 2+1+PLAYERNAME_SIZE+PASSWORD_SIZE)
1423 // old version - assume blank password
1424 given_password[0] = 0;
1428 for(u32 i=0; i<PASSWORD_SIZE-1; i++)
1430 given_password[i] = data[23+i];
1432 given_password[PASSWORD_SIZE-1] = 0;
1435 if(!base64_is_valid(given_password)){
1436 actionstream<<"Server: "<<playername
1437 <<" supplied invalid password hash"<<std::endl;
1438 DenyAccess(peer_id, L"Invalid password hash");
1442 // Enforce user limit.
1443 // Don't enforce for users that have some admin right
1444 if(m_clients.getClientIDs(Created).size() >= g_settings->getU16("max_users") &&
1445 !checkPriv(playername, "server") &&
1446 !checkPriv(playername, "ban") &&
1447 !checkPriv(playername, "privs") &&
1448 !checkPriv(playername, "password") &&
1449 playername != g_settings->get("name"))
1451 actionstream<<"Server: "<<playername<<" tried to join, but there"
1452 <<" are already max_users="
1453 <<g_settings->getU16("max_users")<<" players."<<std::endl;
1454 DenyAccess(peer_id, L"Too many users.");
1458 std::string checkpwd; // Password hash to check against
1459 bool has_auth = m_script->getAuth(playername, &checkpwd, NULL);
1461 // If no authentication info exists for user, create it
1463 if(!isSingleplayer() &&
1464 g_settings->getBool("disallow_empty_password") &&
1465 std::string(given_password) == ""){
1466 actionstream<<"Server: "<<playername
1467 <<" supplied empty password"<<std::endl;
1468 DenyAccess(peer_id, L"Empty passwords are "
1469 L"disallowed. Set a password and try again.");
1472 std::wstring raw_default_password =
1473 narrow_to_wide(g_settings->get("default_password"));
1474 std::string initial_password =
1475 translatePassword(playername, raw_default_password);
1477 // If default_password is empty, allow any initial password
1478 if (raw_default_password.length() == 0)
1479 initial_password = given_password;
1481 m_script->createAuth(playername, initial_password);
1484 has_auth = m_script->getAuth(playername, &checkpwd, NULL);
1487 actionstream<<"Server: "<<playername<<" cannot be authenticated"
1488 <<" (auth handler does not work?)"<<std::endl;
1489 DenyAccess(peer_id, L"Not allowed to login");
1493 if(given_password != checkpwd){
1494 actionstream<<"Server: "<<playername<<" supplied wrong password"
1496 DenyAccess(peer_id, L"Wrong password");
1500 RemotePlayer *player =
1501 static_cast<RemotePlayer*>(m_env->getPlayer(playername));
1503 if(player && player->peer_id != 0){
1504 errorstream<<"Server: "<<playername<<": Failed to emerge player"
1505 <<" (player allocated to an another client)"<<std::endl;
1506 DenyAccess(peer_id, L"Another client is connected with this "
1507 L"name. If your client closed unexpectedly, try again in "
1511 m_clients.setPlayerName(peer_id,playername);
1514 Answer with a TOCLIENT_INIT
1517 SharedBuffer<u8> reply(2+1+6+8+4);
1518 writeU16(&reply[0], TOCLIENT_INIT);
1519 writeU8(&reply[2], deployed);
1520 //send dummy pos for legacy reasons only
1521 writeV3S16(&reply[2+1], floatToInt(v3f(0,0,0), BS));
1522 writeU64(&reply[2+1+6], m_env->getServerMap().getSeed());
1523 writeF1000(&reply[2+1+6+8], g_settings->getFloat("dedicated_server_step"));
1526 m_clients.send(peer_id, 0, reply, true);
1527 m_clients.event(peer_id, Init);
1533 if(command == TOSERVER_INIT2)
1536 verbosestream<<"Server: Got TOSERVER_INIT2 from "
1537 <<peer_id<<std::endl;
1539 m_clients.event(peer_id, GotInit2);
1540 u16 protocol_version = m_clients.getProtocolVersion(peer_id);
1543 Send some initialization data
1546 infostream<<"Server: Sending content to "
1547 <<getPlayerName(peer_id)<<std::endl;
1549 // Send player movement settings
1550 SendMovement(peer_id);
1552 // Send item definitions
1553 SendItemDef(peer_id, m_itemdef, protocol_version);
1555 // Send node definitions
1556 SendNodeDef(peer_id, m_nodedef, protocol_version);
1558 m_clients.event(peer_id, SetDefinitionsSent);
1560 // Send media announcement
1561 sendMediaAnnouncement(peer_id);
1563 // Send detached inventories
1564 sendDetachedInventories(peer_id);
1567 u16 time = m_env->getTimeOfDay();
1568 float time_speed = g_settings->getFloat("time_speed");
1569 SendTimeOfDay(peer_id, time, time_speed);
1571 // Warnings about protocol version can be issued here
1572 if(getClient(peer_id)->net_proto_version < LATEST_PROTOCOL_VERSION)
1574 SendChatMessage(peer_id, L"# Server: WARNING: YOUR CLIENT'S "
1575 L"VERSION MAY NOT BE FULLY COMPATIBLE WITH THIS SERVER!");
1581 u8 peer_ser_ver = getClient(peer_id,InitDone)->serialization_version;
1583 if(peer_ser_ver == SER_FMT_VER_INVALID)
1585 errorstream<<"Server::ProcessData(): Cancelling: Peer"
1586 " serialization format invalid or not initialized."
1587 " Skipping incoming command="<<command<<std::endl;
1591 /* Handle commands relate to client startup */
1592 if(command == TOSERVER_REQUEST_MEDIA) {
1593 std::string datastring((char*)&data[2], datasize-2);
1594 std::istringstream is(datastring, std::ios_base::binary);
1596 std::list<std::string> tosend;
1597 u16 numfiles = readU16(is);
1599 infostream<<"Sending "<<numfiles<<" files to "
1600 <<getPlayerName(peer_id)<<std::endl;
1601 verbosestream<<"TOSERVER_REQUEST_MEDIA: "<<std::endl;
1603 for(int i = 0; i < numfiles; i++) {
1604 std::string name = deSerializeString(is);
1605 tosend.push_back(name);
1606 verbosestream<<"TOSERVER_REQUEST_MEDIA: requested file "
1610 sendRequestedMedia(peer_id, tosend);
1613 else if(command == TOSERVER_RECEIVED_MEDIA) {
1614 std::string playername = "";
1615 PlayerSAO *playersao = NULL;
1617 RemoteClient* client = m_clients.lockedGetClientNoEx(peer_id,DefinitionsSent);
1618 if (client != NULL) {
1619 playername = client->getName();
1620 playersao = emergePlayer(playername.c_str(), peer_id);
1624 RemotePlayer *player =
1625 static_cast<RemotePlayer*>(m_env->getPlayer(playername.c_str()));
1627 // If failed, cancel
1628 if((playersao == NULL) || (player == NULL))
1630 if(player && player->peer_id != 0){
1631 errorstream<<"Server: "<<playername<<": Failed to emerge player"
1632 <<" (player allocated to an another client)"<<std::endl;
1633 DenyAccess(peer_id, L"Another client is connected with this "
1634 L"name. If your client closed unexpectedly, try again in "
1637 errorstream<<"Server: "<<playername<<": Failed to emerge player"
1639 DenyAccess(peer_id, L"Could not allocate player.");
1645 Send complete position information
1647 SendMovePlayer(peer_id);
1650 SendPlayerPrivileges(peer_id);
1652 // Send inventory formspec
1653 SendPlayerInventoryFormspec(peer_id);
1656 UpdateCrafting(peer_id);
1657 SendInventory(peer_id);
1660 if(g_settings->getBool("enable_damage"))
1661 SendPlayerHP(peer_id);
1664 SendPlayerBreath(peer_id);
1666 // Show death screen if necessary
1668 SendDeathscreen(peer_id, false, v3f(0,0,0));
1670 // Note things in chat if not in simple singleplayer mode
1671 if(!m_simple_singleplayer_mode)
1673 // Send information about server to player in chat
1674 SendChatMessage(peer_id, getStatusString());
1676 // Send information about joining in chat
1678 std::wstring name = L"unknown";
1679 Player *player = m_env->getPlayer(peer_id);
1681 name = narrow_to_wide(player->getName());
1683 std::wstring message;
1686 message += L" joined the game.";
1687 SendChatMessage(PEER_ID_INEXISTENT,message);
1691 actionstream<<player->getName()<<" ["<<addr_s<<"] "<<"joins game. " << std::endl;
1696 std::vector<std::string> names = m_clients.getPlayerNames();
1698 actionstream<<player->getName()<<" ["<<addr_s<<"] "
1699 <<"joins game. List of players: ";
1701 for (std::vector<std::string>::iterator i = names.begin();
1702 i != names.end(); i++)
1704 actionstream << *i << " ";
1707 actionstream<<std::endl;
1710 m_clients.event(peer_id,SetMediaSent);
1711 m_script->on_joinplayer(playersao);
1714 else if(command == TOSERVER_GOTBLOCKS)
1727 u16 count = data[2];
1728 for(u16 i=0; i<count; i++)
1730 if((s16)datasize < 2+1+(i+1)*6)
1731 throw con::InvalidIncomingDataException
1732 ("GOTBLOCKS length is too short");
1733 v3s16 p = readV3S16(&data[2+1+i*6]);
1734 /*infostream<<"Server: GOTBLOCKS ("
1735 <<p.X<<","<<p.Y<<","<<p.Z<<")"<<std::endl;*/
1736 RemoteClient *client = getClient(peer_id);
1737 client->GotBlock(p);
1742 if (m_clients.getClientState(peer_id) < Active)
1744 if (command == TOSERVER_PLAYERPOS) return;
1746 errorstream<<"Got packet command: " << command << " for peer id "
1747 << peer_id << " but client isn't active yet. Dropping packet "
1752 Player *player = m_env->getPlayer(peer_id);
1754 errorstream<<"Server::ProcessData(): Cancelling: "
1755 "No player for peer_id="<<peer_id
1760 PlayerSAO *playersao = player->getPlayerSAO();
1761 if(playersao == NULL){
1762 errorstream<<"Server::ProcessData(): Cancelling: "
1763 "No player object for peer_id="<<peer_id
1768 if(command == TOSERVER_PLAYERPOS)
1770 if(datasize < 2+12+12+4+4)
1774 v3s32 ps = readV3S32(&data[start+2]);
1775 v3s32 ss = readV3S32(&data[start+2+12]);
1776 f32 pitch = (f32)readS32(&data[2+12+12]) / 100.0;
1777 f32 yaw = (f32)readS32(&data[2+12+12+4]) / 100.0;
1779 if(datasize >= 2+12+12+4+4+4)
1780 keyPressed = (u32)readU32(&data[2+12+12+4+4]);
1781 v3f position((f32)ps.X/100., (f32)ps.Y/100., (f32)ps.Z/100.);
1782 v3f speed((f32)ss.X/100., (f32)ss.Y/100., (f32)ss.Z/100.);
1783 pitch = wrapDegrees(pitch);
1784 yaw = wrapDegrees(yaw);
1786 player->setPosition(position);
1787 player->setSpeed(speed);
1788 player->setPitch(pitch);
1789 player->setYaw(yaw);
1790 player->keyPressed=keyPressed;
1791 player->control.up = (bool)(keyPressed&1);
1792 player->control.down = (bool)(keyPressed&2);
1793 player->control.left = (bool)(keyPressed&4);
1794 player->control.right = (bool)(keyPressed&8);
1795 player->control.jump = (bool)(keyPressed&16);
1796 player->control.aux1 = (bool)(keyPressed&32);
1797 player->control.sneak = (bool)(keyPressed&64);
1798 player->control.LMB = (bool)(keyPressed&128);
1799 player->control.RMB = (bool)(keyPressed&256);
1801 bool cheated = playersao->checkMovementCheat();
1804 m_script->on_cheat(playersao, "moved_too_fast");
1807 /*infostream<<"Server::ProcessData(): Moved player "<<peer_id<<" to "
1808 <<"("<<position.X<<","<<position.Y<<","<<position.Z<<")"
1809 <<" pitch="<<pitch<<" yaw="<<yaw<<std::endl;*/
1811 else if(command == TOSERVER_DELETEDBLOCKS)
1824 u16 count = data[2];
1825 for(u16 i=0; i<count; i++)
1827 if((s16)datasize < 2+1+(i+1)*6)
1828 throw con::InvalidIncomingDataException
1829 ("DELETEDBLOCKS length is too short");
1830 v3s16 p = readV3S16(&data[2+1+i*6]);
1831 /*infostream<<"Server: DELETEDBLOCKS ("
1832 <<p.X<<","<<p.Y<<","<<p.Z<<")"<<std::endl;*/
1833 RemoteClient *client = getClient(peer_id);
1834 client->SetBlockNotSent(p);
1837 else if(command == TOSERVER_CLICK_OBJECT)
1839 infostream<<"Server: CLICK_OBJECT not supported anymore"<<std::endl;
1842 else if(command == TOSERVER_CLICK_ACTIVEOBJECT)
1844 infostream<<"Server: CLICK_ACTIVEOBJECT not supported anymore"<<std::endl;
1847 else if(command == TOSERVER_GROUND_ACTION)
1849 infostream<<"Server: GROUND_ACTION not supported anymore"<<std::endl;
1853 else if(command == TOSERVER_RELEASE)
1855 infostream<<"Server: RELEASE not supported anymore"<<std::endl;
1858 else if(command == TOSERVER_SIGNTEXT)
1860 infostream<<"Server: SIGNTEXT not supported anymore"
1864 else if(command == TOSERVER_SIGNNODETEXT)
1866 infostream<<"Server: SIGNNODETEXT not supported anymore"
1870 else if(command == TOSERVER_INVENTORY_ACTION)
1872 // Strip command and create a stream
1873 std::string datastring((char*)&data[2], datasize-2);
1874 verbosestream<<"TOSERVER_INVENTORY_ACTION: data="<<datastring<<std::endl;
1875 std::istringstream is(datastring, std::ios_base::binary);
1877 InventoryAction *a = InventoryAction::deSerialize(is);
1880 infostream<<"TOSERVER_INVENTORY_ACTION: "
1881 <<"InventoryAction::deSerialize() returned NULL"
1886 // If something goes wrong, this player is to blame
1887 RollbackScopeActor rollback_scope(m_rollback,
1888 std::string("player:")+player->getName());
1891 Note: Always set inventory not sent, to repair cases
1892 where the client made a bad prediction.
1896 Handle restrictions and special cases of the move action
1898 if(a->getType() == IACTION_MOVE)
1900 IMoveAction *ma = (IMoveAction*)a;
1902 ma->from_inv.applyCurrentPlayer(player->getName());
1903 ma->to_inv.applyCurrentPlayer(player->getName());
1905 setInventoryModified(ma->from_inv);
1906 setInventoryModified(ma->to_inv);
1908 bool from_inv_is_current_player =
1909 (ma->from_inv.type == InventoryLocation::PLAYER) &&
1910 (ma->from_inv.name == player->getName());
1912 bool to_inv_is_current_player =
1913 (ma->to_inv.type == InventoryLocation::PLAYER) &&
1914 (ma->to_inv.name == player->getName());
1917 Disable moving items out of craftpreview
1919 if(ma->from_list == "craftpreview")
1921 infostream<<"Ignoring IMoveAction from "
1922 <<(ma->from_inv.dump())<<":"<<ma->from_list
1923 <<" to "<<(ma->to_inv.dump())<<":"<<ma->to_list
1924 <<" because src is "<<ma->from_list<<std::endl;
1930 Disable moving items into craftresult and craftpreview
1932 if(ma->to_list == "craftpreview" || ma->to_list == "craftresult")
1934 infostream<<"Ignoring IMoveAction from "
1935 <<(ma->from_inv.dump())<<":"<<ma->from_list
1936 <<" to "<<(ma->to_inv.dump())<<":"<<ma->to_list
1937 <<" because dst is "<<ma->to_list<<std::endl;
1942 // Disallow moving items in elsewhere than player's inventory
1943 // if not allowed to interact
1944 if(!checkPriv(player->getName(), "interact") &&
1945 (!from_inv_is_current_player ||
1946 !to_inv_is_current_player))
1948 infostream<<"Cannot move outside of player's inventory: "
1949 <<"No interact privilege"<<std::endl;
1955 Handle restrictions and special cases of the drop action
1957 else if(a->getType() == IACTION_DROP)
1959 IDropAction *da = (IDropAction*)a;
1961 da->from_inv.applyCurrentPlayer(player->getName());
1963 setInventoryModified(da->from_inv);
1966 Disable dropping items out of craftpreview
1968 if(da->from_list == "craftpreview")
1970 infostream<<"Ignoring IDropAction from "
1971 <<(da->from_inv.dump())<<":"<<da->from_list
1972 <<" because src is "<<da->from_list<<std::endl;
1977 // Disallow dropping items if not allowed to interact
1978 if(!checkPriv(player->getName(), "interact"))
1985 Handle restrictions and special cases of the craft action
1987 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"))
2002 infostream<<"Cannot craft: "
2003 <<"No interact privilege"<<std::endl;
2010 a->apply(this, playersao, this);
2014 else if(command == TOSERVER_CHAT_MESSAGE)
2022 std::string datastring((char*)&data[2], datasize-2);
2023 std::istringstream is(datastring, std::ios_base::binary);
2026 is.read((char*)buf, 2);
2027 u16 len = readU16(buf);
2029 std::wstring message;
2030 for(u16 i=0; i<len; i++)
2032 is.read((char*)buf, 2);
2033 message += (wchar_t)readU16(buf);
2036 // If something goes wrong, this player is to blame
2037 RollbackScopeActor rollback_scope(m_rollback,
2038 std::string("player:")+player->getName());
2040 // Get player name of this client
2041 std::wstring name = narrow_to_wide(player->getName());
2044 bool ate = m_script->on_chat_message(player->getName(),
2045 wide_to_narrow(message));
2046 // If script ate the message, don't proceed
2050 // Line to send to players
2052 // Whether to send to the player that sent the line
2053 bool send_to_sender_only = false;
2055 // Commands are implemented in Lua, so only catch invalid
2056 // commands that were not "eaten" and send an error back
2057 if(message[0] == L'/')
2059 message = message.substr(1);
2060 send_to_sender_only = true;
2061 if(message.length() == 0)
2062 line += L"-!- Empty command";
2064 line += L"-!- Invalid command: " + str_split(message, L' ')[0];
2068 if(checkPriv(player->getName(), "shout")){
2074 line += L"-!- You don't have permission to shout.";
2075 send_to_sender_only = true;
2082 Send the message to sender
2084 if (send_to_sender_only)
2086 SendChatMessage(peer_id, line);
2089 Send the message to others
2093 actionstream<<"CHAT: "<<wide_to_narrow(line)<<std::endl;
2095 std::list<u16> clients = m_clients.getClientIDs();
2097 for(std::list<u16>::iterator
2098 i = clients.begin();
2099 i != clients.end(); ++i)
2102 SendChatMessage(*i, line);
2107 else if(command == TOSERVER_DAMAGE)
2109 std::string datastring((char*)&data[2], datasize-2);
2110 std::istringstream is(datastring, std::ios_base::binary);
2111 u8 damage = readU8(is);
2113 if(g_settings->getBool("enable_damage"))
2115 actionstream<<player->getName()<<" damaged by "
2116 <<(int)damage<<" hp at "<<PP(player->getPosition()/BS)
2119 playersao->setHP(playersao->getHP() - damage);
2121 if(playersao->getHP() == 0 && playersao->m_hp_not_sent)
2124 if(playersao->m_hp_not_sent)
2125 SendPlayerHP(peer_id);
2128 else if(command == TOSERVER_BREATH)
2130 std::string datastring((char*)&data[2], datasize-2);
2131 std::istringstream is(datastring, std::ios_base::binary);
2132 u16 breath = readU16(is);
2133 playersao->setBreath(breath);
2135 else if(command == TOSERVER_PASSWORD)
2138 [0] u16 TOSERVER_PASSWORD
2139 [2] u8[28] old password
2140 [30] u8[28] new password
2143 if(datasize != 2+PASSWORD_SIZE*2)
2145 /*char password[PASSWORD_SIZE];
2146 for(u32 i=0; i<PASSWORD_SIZE-1; i++)
2147 password[i] = data[2+i];
2148 password[PASSWORD_SIZE-1] = 0;*/
2150 for(u32 i=0; i<PASSWORD_SIZE-1; i++)
2158 for(u32 i=0; i<PASSWORD_SIZE-1; i++)
2160 char c = data[2+PASSWORD_SIZE+i];
2166 if(!base64_is_valid(newpwd)){
2167 infostream<<"Server: "<<player->getName()<<" supplied invalid password hash"<<std::endl;
2168 // Wrong old password supplied!!
2169 SendChatMessage(peer_id, L"Invalid new password hash supplied. Password NOT changed.");
2173 infostream<<"Server: Client requests a password change from "
2174 <<"'"<<oldpwd<<"' to '"<<newpwd<<"'"<<std::endl;
2176 std::string playername = player->getName();
2178 std::string checkpwd;
2179 m_script->getAuth(playername, &checkpwd, NULL);
2181 if(oldpwd != checkpwd)
2183 infostream<<"Server: invalid old password"<<std::endl;
2184 // Wrong old password supplied!!
2185 SendChatMessage(peer_id, L"Invalid old password supplied. Password NOT changed.");
2189 bool success = m_script->setPassword(playername, newpwd);
2191 actionstream<<player->getName()<<" changes password"<<std::endl;
2192 SendChatMessage(peer_id, L"Password change successful.");
2194 actionstream<<player->getName()<<" tries to change password but "
2195 <<"it fails"<<std::endl;
2196 SendChatMessage(peer_id, L"Password change failed or inavailable.");
2199 else if(command == TOSERVER_PLAYERITEM)
2204 u16 item = readU16(&data[2]);
2205 playersao->setWieldIndex(item);
2207 else if(command == TOSERVER_RESPAWN)
2209 if(player->hp != 0 || !g_settings->getBool("enable_damage"))
2212 RespawnPlayer(peer_id);
2214 actionstream<<player->getName()<<" respawns at "
2215 <<PP(player->getPosition()/BS)<<std::endl;
2217 // ActiveObject is added to environment in AsyncRunStep after
2218 // the previous addition has been succesfully removed
2220 else if(command == TOSERVER_INTERACT)
2222 std::string datastring((char*)&data[2], datasize-2);
2223 std::istringstream is(datastring, std::ios_base::binary);
2229 [5] u32 length of the next item
2230 [9] serialized PointedThing
2232 0: start digging (from undersurface) or use
2233 1: stop digging (all parameters ignored)
2234 2: digging completed
2235 3: place block or item (to abovesurface)
2238 u8 action = readU8(is);
2239 u16 item_i = readU16(is);
2240 std::istringstream tmp_is(deSerializeLongString(is), std::ios::binary);
2241 PointedThing pointed;
2242 pointed.deSerialize(tmp_is);
2244 verbosestream<<"TOSERVER_INTERACT: action="<<(int)action<<", item="
2245 <<item_i<<", pointed="<<pointed.dump()<<std::endl;
2249 verbosestream<<"TOSERVER_INTERACT: "<<player->getName()
2250 <<" tried to interact, but is dead!"<<std::endl;
2254 v3f player_pos = playersao->getLastGoodPosition();
2256 // Update wielded item
2257 playersao->setWieldIndex(item_i);
2259 // Get pointed to node (undefined if not POINTEDTYPE_NODE)
2260 v3s16 p_under = pointed.node_undersurface;
2261 v3s16 p_above = pointed.node_abovesurface;
2263 // Get pointed to object (NULL if not POINTEDTYPE_OBJECT)
2264 ServerActiveObject *pointed_object = NULL;
2265 if(pointed.type == POINTEDTHING_OBJECT)
2267 pointed_object = m_env->getActiveObject(pointed.object_id);
2268 if(pointed_object == NULL)
2270 verbosestream<<"TOSERVER_INTERACT: "
2271 "pointed object is NULL"<<std::endl;
2277 v3f pointed_pos_under = player_pos;
2278 v3f pointed_pos_above = player_pos;
2279 if(pointed.type == POINTEDTHING_NODE)
2281 pointed_pos_under = intToFloat(p_under, BS);
2282 pointed_pos_above = intToFloat(p_above, BS);
2284 else if(pointed.type == POINTEDTHING_OBJECT)
2286 pointed_pos_under = pointed_object->getBasePosition();
2287 pointed_pos_above = pointed_pos_under;
2291 Check that target is reasonably close
2292 (only when digging or placing things)
2294 if(action == 0 || action == 2 || action == 3)
2296 float d = player_pos.getDistanceFrom(pointed_pos_under);
2297 float max_d = BS * 14; // Just some large enough value
2299 actionstream<<"Player "<<player->getName()
2300 <<" tried to access "<<pointed.dump()
2302 <<"d="<<d<<", max_d="<<max_d
2303 <<". ignoring."<<std::endl;
2304 // Re-send block to revert change on client-side
2305 RemoteClient *client = getClient(peer_id);
2306 v3s16 blockpos = getNodeBlockPos(floatToInt(pointed_pos_under, BS));
2307 client->SetBlockNotSent(blockpos);
2309 m_script->on_cheat(playersao, "interacted_too_far");
2316 Make sure the player is allowed to do it
2318 if(!checkPriv(player->getName(), "interact"))
2320 actionstream<<player->getName()<<" attempted to interact with "
2321 <<pointed.dump()<<" without 'interact' privilege"
2323 // Re-send block to revert change on client-side
2324 RemoteClient *client = getClient(peer_id);
2325 // Digging completed -> under
2327 v3s16 blockpos = getNodeBlockPos(floatToInt(pointed_pos_under, BS));
2328 client->SetBlockNotSent(blockpos);
2330 // Placement -> above
2332 v3s16 blockpos = getNodeBlockPos(floatToInt(pointed_pos_above, BS));
2333 client->SetBlockNotSent(blockpos);
2339 If something goes wrong, this player is to blame
2341 RollbackScopeActor rollback_scope(m_rollback,
2342 std::string("player:")+player->getName());
2345 0: start digging or punch object
2349 if(pointed.type == POINTEDTHING_NODE)
2352 NOTE: This can be used in the future to check if
2353 somebody is cheating, by checking the timing.
2355 MapNode n(CONTENT_IGNORE);
2358 n = m_env->getMap().getNode(p_under);
2360 catch(InvalidPositionException &e)
2362 infostream<<"Server: Not punching: Node not found."
2363 <<" Adding block to emerge queue."
2365 m_emerge->enqueueBlockEmerge(peer_id, getNodeBlockPos(p_above), false);
2367 if(n.getContent() != CONTENT_IGNORE)
2368 m_script->node_on_punch(p_under, n, playersao, pointed);
2370 playersao->noCheatDigStart(p_under);
2372 else if(pointed.type == POINTEDTHING_OBJECT)
2374 // Skip if object has been removed
2375 if(pointed_object->m_removed)
2378 actionstream<<player->getName()<<" punches object "
2379 <<pointed.object_id<<": "
2380 <<pointed_object->getDescription()<<std::endl;
2382 ItemStack punchitem = playersao->getWieldedItem();
2383 ToolCapabilities toolcap =
2384 punchitem.getToolCapabilities(m_itemdef);
2385 v3f dir = (pointed_object->getBasePosition() -
2386 (player->getPosition() + player->getEyeOffset())
2388 float time_from_last_punch =
2389 playersao->resetTimeFromLastPunch();
2390 pointed_object->punch(dir, &toolcap, playersao,
2391 time_from_last_punch);
2399 else if(action == 1)
2404 2: Digging completed
2406 else if(action == 2)
2408 // Only digging of nodes
2409 if(pointed.type == POINTEDTHING_NODE)
2411 MapNode n(CONTENT_IGNORE);
2414 n = m_env->getMap().getNode(p_under);
2416 catch(InvalidPositionException &e)
2418 infostream<<"Server: Not finishing digging: Node not found."
2419 <<" Adding block to emerge queue."
2421 m_emerge->enqueueBlockEmerge(peer_id, getNodeBlockPos(p_above), false);
2424 /* Cheat prevention */
2425 bool is_valid_dig = true;
2426 if(!isSingleplayer() && !g_settings->getBool("disable_anticheat"))
2428 v3s16 nocheat_p = playersao->getNoCheatDigPos();
2429 float nocheat_t = playersao->getNoCheatDigTime();
2430 playersao->noCheatDigEnd();
2431 // If player didn't start digging this, ignore dig
2432 if(nocheat_p != p_under){
2433 infostream<<"Server: NoCheat: "<<player->getName()
2434 <<" started digging "
2435 <<PP(nocheat_p)<<" and completed digging "
2436 <<PP(p_under)<<"; not digging."<<std::endl;
2437 is_valid_dig = false;
2439 m_script->on_cheat(playersao, "finished_unknown_dig");
2441 // Get player's wielded item
2442 ItemStack playeritem;
2443 InventoryList *mlist = playersao->getInventory()->getList("main");
2445 playeritem = mlist->getItem(playersao->getWieldIndex());
2446 ToolCapabilities playeritem_toolcap =
2447 playeritem.getToolCapabilities(m_itemdef);
2448 // Get diggability and expected digging time
2449 DigParams params = getDigParams(m_nodedef->get(n).groups,
2450 &playeritem_toolcap);
2451 // If can't dig, try hand
2452 if(!params.diggable){
2453 const ItemDefinition &hand = m_itemdef->get("");
2454 const ToolCapabilities *tp = hand.tool_capabilities;
2456 params = getDigParams(m_nodedef->get(n).groups, tp);
2458 // If can't dig, ignore dig
2459 if(!params.diggable){
2460 infostream<<"Server: NoCheat: "<<player->getName()
2461 <<" completed digging "<<PP(p_under)
2462 <<", which is not diggable with tool. not digging."
2464 is_valid_dig = false;
2466 m_script->on_cheat(playersao, "dug_unbreakable");
2468 // Check digging time
2469 // If already invalidated, we don't have to
2471 // Well not our problem then
2473 // Clean and long dig
2474 else if(params.time > 2.0 && nocheat_t * 1.2 > params.time){
2475 // All is good, but grab time from pool; don't care if
2476 // it's actually available
2477 playersao->getDigPool().grab(params.time);
2479 // Short or laggy dig
2480 // Try getting the time from pool
2481 else if(playersao->getDigPool().grab(params.time)){
2486 infostream<<"Server: NoCheat: "<<player->getName()
2487 <<" completed digging "<<PP(p_under)
2488 <<"too fast; not digging."<<std::endl;
2489 is_valid_dig = false;
2491 m_script->on_cheat(playersao, "dug_too_fast");
2495 /* Actually dig node */
2497 if(is_valid_dig && n.getContent() != CONTENT_IGNORE)
2498 m_script->node_on_dig(p_under, n, playersao);
2500 // Send unusual result (that is, node not being removed)
2501 if(m_env->getMap().getNodeNoEx(p_under).getContent() != CONTENT_AIR)
2503 // Re-send block to revert change on client-side
2504 RemoteClient *client = getClient(peer_id);
2505 v3s16 blockpos = getNodeBlockPos(floatToInt(pointed_pos_under, BS));
2506 client->SetBlockNotSent(blockpos);
2512 3: place block or right-click object
2514 else if(action == 3)
2516 ItemStack item = playersao->getWieldedItem();
2518 // Reset build time counter
2519 if(pointed.type == POINTEDTHING_NODE &&
2520 item.getDefinition(m_itemdef).type == ITEM_NODE)
2521 getClient(peer_id)->m_time_from_building = 0.0;
2523 if(pointed.type == POINTEDTHING_OBJECT)
2525 // Right click object
2527 // Skip if object has been removed
2528 if(pointed_object->m_removed)
2531 actionstream<<player->getName()<<" right-clicks object "
2532 <<pointed.object_id<<": "
2533 <<pointed_object->getDescription()<<std::endl;
2536 pointed_object->rightClick(playersao);
2538 else if(m_script->item_OnPlace(
2539 item, playersao, pointed))
2541 // Placement was handled in lua
2543 // Apply returned ItemStack
2544 playersao->setWieldedItem(item);
2547 // If item has node placement prediction, always send the
2548 // blocks to make sure the client knows what exactly happened
2549 if(item.getDefinition(m_itemdef).node_placement_prediction != ""){
2550 RemoteClient *client = getClient(peer_id);
2551 v3s16 blockpos = getNodeBlockPos(floatToInt(pointed_pos_above, BS));
2552 client->SetBlockNotSent(blockpos);
2553 v3s16 blockpos2 = getNodeBlockPos(floatToInt(pointed_pos_under, BS));
2554 if(blockpos2 != blockpos){
2555 client->SetBlockNotSent(blockpos2);
2563 else if(action == 4)
2565 ItemStack item = playersao->getWieldedItem();
2567 actionstream<<player->getName()<<" uses "<<item.name
2568 <<", pointing at "<<pointed.dump()<<std::endl;
2570 if(m_script->item_OnUse(
2571 item, playersao, pointed))
2573 // Apply returned ItemStack
2574 playersao->setWieldedItem(item);
2581 Catch invalid actions
2585 infostream<<"WARNING: Server: Invalid action "
2586 <<action<<std::endl;
2589 else if(command == TOSERVER_REMOVED_SOUNDS)
2591 std::string datastring((char*)&data[2], datasize-2);
2592 std::istringstream is(datastring, std::ios_base::binary);
2594 int num = readU16(is);
2595 for(int k=0; k<num; k++){
2596 s32 id = readS32(is);
2597 std::map<s32, ServerPlayingSound>::iterator i =
2598 m_playing_sounds.find(id);
2599 if(i == m_playing_sounds.end())
2601 ServerPlayingSound &psound = i->second;
2602 psound.clients.erase(peer_id);
2603 if(psound.clients.size() == 0)
2604 m_playing_sounds.erase(i++);
2607 else if(command == TOSERVER_NODEMETA_FIELDS)
2609 std::string datastring((char*)&data[2], datasize-2);
2610 std::istringstream is(datastring, std::ios_base::binary);
2612 v3s16 p = readV3S16(is);
2613 std::string formname = deSerializeString(is);
2614 int num = readU16(is);
2615 std::map<std::string, std::string> fields;
2616 for(int k=0; k<num; k++){
2617 std::string fieldname = deSerializeString(is);
2618 std::string fieldvalue = deSerializeLongString(is);
2619 fields[fieldname] = fieldvalue;
2622 // If something goes wrong, this player is to blame
2623 RollbackScopeActor rollback_scope(m_rollback,
2624 std::string("player:")+player->getName());
2626 // Check the target node for rollback data; leave others unnoticed
2627 RollbackNode rn_old(&m_env->getMap(), p, this);
2629 m_script->node_on_receive_fields(p, formname, fields,playersao);
2631 // Report rollback data
2632 RollbackNode rn_new(&m_env->getMap(), p, this);
2633 if(rollback() && rn_new != rn_old){
2634 RollbackAction action;
2635 action.setSetNode(p, rn_old, rn_new);
2636 rollback()->reportAction(action);
2639 else if(command == TOSERVER_INVENTORY_FIELDS)
2641 std::string datastring((char*)&data[2], datasize-2);
2642 std::istringstream is(datastring, std::ios_base::binary);
2644 std::string formname = deSerializeString(is);
2645 int num = readU16(is);
2646 std::map<std::string, std::string> fields;
2647 for(int k=0; k<num; k++){
2648 std::string fieldname = deSerializeString(is);
2649 std::string fieldvalue = deSerializeLongString(is);
2650 fields[fieldname] = fieldvalue;
2653 m_script->on_playerReceiveFields(playersao, formname, fields);
2657 infostream<<"Server::ProcessData(): Ignoring "
2658 "unknown command "<<command<<std::endl;
2662 catch(SendFailedException &e)
2664 errorstream<<"Server::ProcessData(): SendFailedException: "
2670 void Server::setTimeOfDay(u32 time)
2672 m_env->setTimeOfDay(time);
2673 m_time_of_day_send_timer = 0;
2676 void Server::onMapEditEvent(MapEditEvent *event)
2678 //infostream<<"Server::onMapEditEvent()"<<std::endl;
2679 if(m_ignore_map_edit_events)
2681 if(m_ignore_map_edit_events_area.contains(event->getArea()))
2683 MapEditEvent *e = event->clone();
2684 m_unsent_map_edit_queue.push_back(e);
2687 Inventory* Server::getInventory(const InventoryLocation &loc)
2690 case InventoryLocation::UNDEFINED:
2693 case InventoryLocation::CURRENT_PLAYER:
2696 case InventoryLocation::PLAYER:
2698 Player *player = m_env->getPlayer(loc.name.c_str());
2701 PlayerSAO *playersao = player->getPlayerSAO();
2704 return playersao->getInventory();
2707 case InventoryLocation::NODEMETA:
2709 NodeMetadata *meta = m_env->getMap().getNodeMetadata(loc.p);
2712 return meta->getInventory();
2715 case InventoryLocation::DETACHED:
2717 if(m_detached_inventories.count(loc.name) == 0)
2719 return m_detached_inventories[loc.name];
2727 void Server::setInventoryModified(const InventoryLocation &loc)
2730 case InventoryLocation::UNDEFINED:
2733 case InventoryLocation::PLAYER:
2735 Player *player = m_env->getPlayer(loc.name.c_str());
2738 PlayerSAO *playersao = player->getPlayerSAO();
2741 playersao->m_inventory_not_sent = true;
2742 playersao->m_wielded_item_not_sent = true;
2745 case InventoryLocation::NODEMETA:
2747 v3s16 blockpos = getNodeBlockPos(loc.p);
2749 MapBlock *block = m_env->getMap().getBlockNoCreateNoEx(blockpos);
2751 block->raiseModified(MOD_STATE_WRITE_NEEDED);
2753 setBlockNotSent(blockpos);
2756 case InventoryLocation::DETACHED:
2758 sendDetachedInventory(loc.name,PEER_ID_INEXISTENT);
2766 void Server::SetBlocksNotSent(std::map<v3s16, MapBlock *>& block)
2768 std::list<u16> clients = m_clients.getClientIDs();
2770 // Set the modified blocks unsent for all the clients
2771 for (std::list<u16>::iterator
2772 i = clients.begin();
2773 i != clients.end(); ++i) {
2774 RemoteClient *client = m_clients.lockedGetClientNoEx(*i);
2776 client->SetBlocksNotSent(block);
2781 void Server::peerAdded(con::Peer *peer)
2783 DSTACK(__FUNCTION_NAME);
2784 verbosestream<<"Server::peerAdded(): peer->id="
2785 <<peer->id<<std::endl;
2788 c.type = con::PEER_ADDED;
2789 c.peer_id = peer->id;
2791 m_peer_change_queue.push_back(c);
2794 void Server::deletingPeer(con::Peer *peer, bool timeout)
2796 DSTACK(__FUNCTION_NAME);
2797 verbosestream<<"Server::deletingPeer(): peer->id="
2798 <<peer->id<<", timeout="<<timeout<<std::endl;
2800 m_clients.event(peer->id,Disconnect);
2802 c.type = con::PEER_REMOVED;
2803 c.peer_id = peer->id;
2804 c.timeout = timeout;
2805 m_peer_change_queue.push_back(c);
2808 void Server::handlePeerChanges()
2810 while(m_peer_change_queue.size() > 0)
2812 con::PeerChange c = m_peer_change_queue.pop_front();
2814 verbosestream<<"Server: Handling peer change: "
2815 <<"id="<<c.peer_id<<", timeout="<<c.timeout
2820 case con::PEER_ADDED:
2821 m_clients.CreateClient(c.peer_id);
2824 case con::PEER_REMOVED:
2825 DeleteClient(c.peer_id, c.timeout?CDR_TIMEOUT:CDR_LEAVE);
2829 assert("Invalid peer change event received!" == 0);
2835 void Server::SendMovement(u16 peer_id)
2837 DSTACK(__FUNCTION_NAME);
2838 std::ostringstream os(std::ios_base::binary);
2840 writeU16(os, TOCLIENT_MOVEMENT);
2841 writeF1000(os, g_settings->getFloat("movement_acceleration_default"));
2842 writeF1000(os, g_settings->getFloat("movement_acceleration_air"));
2843 writeF1000(os, g_settings->getFloat("movement_acceleration_fast"));
2844 writeF1000(os, g_settings->getFloat("movement_speed_walk"));
2845 writeF1000(os, g_settings->getFloat("movement_speed_crouch"));
2846 writeF1000(os, g_settings->getFloat("movement_speed_fast"));
2847 writeF1000(os, g_settings->getFloat("movement_speed_climb"));
2848 writeF1000(os, g_settings->getFloat("movement_speed_jump"));
2849 writeF1000(os, g_settings->getFloat("movement_liquid_fluidity"));
2850 writeF1000(os, g_settings->getFloat("movement_liquid_fluidity_smooth"));
2851 writeF1000(os, g_settings->getFloat("movement_liquid_sink"));
2852 writeF1000(os, g_settings->getFloat("movement_gravity"));
2855 std::string s = os.str();
2856 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
2858 m_clients.send(peer_id, 0, data, true);
2861 void Server::SendHP(u16 peer_id, u8 hp)
2863 DSTACK(__FUNCTION_NAME);
2864 std::ostringstream os(std::ios_base::binary);
2866 writeU16(os, TOCLIENT_HP);
2870 std::string s = os.str();
2871 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
2873 m_clients.send(peer_id, 0, data, true);
2876 void Server::SendBreath(u16 peer_id, u16 breath)
2878 DSTACK(__FUNCTION_NAME);
2879 std::ostringstream os(std::ios_base::binary);
2881 writeU16(os, TOCLIENT_BREATH);
2882 writeU16(os, breath);
2885 std::string s = os.str();
2886 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
2888 m_clients.send(peer_id, 0, data, true);
2891 void Server::SendAccessDenied(u16 peer_id,const std::wstring &reason)
2893 DSTACK(__FUNCTION_NAME);
2894 std::ostringstream os(std::ios_base::binary);
2896 writeU16(os, TOCLIENT_ACCESS_DENIED);
2897 os<<serializeWideString(reason);
2900 std::string s = os.str();
2901 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
2903 m_clients.send(peer_id, 0, data, true);
2906 void Server::SendDeathscreen(u16 peer_id,bool set_camera_point_target,
2907 v3f camera_point_target)
2909 DSTACK(__FUNCTION_NAME);
2910 std::ostringstream os(std::ios_base::binary);
2912 writeU16(os, TOCLIENT_DEATHSCREEN);
2913 writeU8(os, set_camera_point_target);
2914 writeV3F1000(os, camera_point_target);
2917 std::string s = os.str();
2918 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
2920 m_clients.send(peer_id, 0, data, true);
2923 void Server::SendItemDef(u16 peer_id,
2924 IItemDefManager *itemdef, u16 protocol_version)
2926 DSTACK(__FUNCTION_NAME);
2927 std::ostringstream os(std::ios_base::binary);
2931 u32 length of the next item
2932 zlib-compressed serialized ItemDefManager
2934 writeU16(os, TOCLIENT_ITEMDEF);
2935 std::ostringstream tmp_os(std::ios::binary);
2936 itemdef->serialize(tmp_os, protocol_version);
2937 std::ostringstream tmp_os2(std::ios::binary);
2938 compressZlib(tmp_os.str(), tmp_os2);
2939 os<<serializeLongString(tmp_os2.str());
2942 std::string s = os.str();
2943 verbosestream<<"Server: Sending item definitions to id("<<peer_id
2944 <<"): size="<<s.size()<<std::endl;
2945 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
2947 m_clients.send(peer_id, 0, data, true);
2950 void Server::SendNodeDef(u16 peer_id,
2951 INodeDefManager *nodedef, u16 protocol_version)
2953 DSTACK(__FUNCTION_NAME);
2954 std::ostringstream os(std::ios_base::binary);
2958 u32 length of the next item
2959 zlib-compressed serialized NodeDefManager
2961 writeU16(os, TOCLIENT_NODEDEF);
2962 std::ostringstream tmp_os(std::ios::binary);
2963 nodedef->serialize(tmp_os, protocol_version);
2964 std::ostringstream tmp_os2(std::ios::binary);
2965 compressZlib(tmp_os.str(), tmp_os2);
2966 os<<serializeLongString(tmp_os2.str());
2969 std::string s = os.str();
2970 verbosestream<<"Server: Sending node definitions to id("<<peer_id
2971 <<"): size="<<s.size()<<std::endl;
2972 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
2974 m_clients.send(peer_id, 0, data, true);
2978 Non-static send methods
2981 void Server::SendInventory(u16 peer_id)
2983 DSTACK(__FUNCTION_NAME);
2985 PlayerSAO *playersao = getPlayerSAO(peer_id);
2988 playersao->m_inventory_not_sent = false;
2994 std::ostringstream os;
2995 playersao->getInventory()->serialize(os);
2997 std::string s = os.str();
2999 SharedBuffer<u8> data(s.size()+2);
3000 writeU16(&data[0], TOCLIENT_INVENTORY);
3001 memcpy(&data[2], s.c_str(), s.size());
3004 m_clients.send(peer_id, 0, data, true);
3007 void Server::SendChatMessage(u16 peer_id, const std::wstring &message)
3009 DSTACK(__FUNCTION_NAME);
3011 std::ostringstream os(std::ios_base::binary);
3015 writeU16(buf, TOCLIENT_CHAT_MESSAGE);
3016 os.write((char*)buf, 2);
3019 writeU16(buf, message.size());
3020 os.write((char*)buf, 2);
3023 for(u32 i=0; i<message.size(); i++)
3027 os.write((char*)buf, 2);
3031 std::string s = os.str();
3032 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3034 if (peer_id != PEER_ID_INEXISTENT)
3037 m_clients.send(peer_id, 0, data, true);
3041 m_clients.sendToAll(0,data,true);
3045 void Server::SendShowFormspecMessage(u16 peer_id, const std::string formspec,
3046 const std::string formname)
3048 DSTACK(__FUNCTION_NAME);
3050 std::ostringstream os(std::ios_base::binary);
3054 writeU16(buf, TOCLIENT_SHOW_FORMSPEC);
3055 os.write((char*)buf, 2);
3056 os<<serializeLongString(formspec);
3057 os<<serializeString(formname);
3060 std::string s = os.str();
3061 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3063 m_clients.send(peer_id, 0, data, true);
3066 // Spawns a particle on peer with peer_id
3067 void Server::SendSpawnParticle(u16 peer_id, v3f pos, v3f velocity, v3f acceleration,
3068 float expirationtime, float size, bool collisiondetection,
3069 bool vertical, std::string texture)
3071 DSTACK(__FUNCTION_NAME);
3073 std::ostringstream os(std::ios_base::binary);
3074 writeU16(os, TOCLIENT_SPAWN_PARTICLE);
3075 writeV3F1000(os, pos);
3076 writeV3F1000(os, velocity);
3077 writeV3F1000(os, acceleration);
3078 writeF1000(os, expirationtime);
3079 writeF1000(os, size);
3080 writeU8(os, collisiondetection);
3081 os<<serializeLongString(texture);
3082 writeU8(os, vertical);
3085 std::string s = os.str();
3086 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3088 if (peer_id != PEER_ID_INEXISTENT)
3091 m_clients.send(peer_id, 0, data, true);
3095 m_clients.sendToAll(0,data,true);
3099 // Adds a ParticleSpawner on peer with peer_id
3100 void Server::SendAddParticleSpawner(u16 peer_id, u16 amount, float spawntime, v3f minpos, v3f maxpos,
3101 v3f minvel, v3f maxvel, v3f minacc, v3f maxacc, float minexptime, float maxexptime,
3102 float minsize, float maxsize, bool collisiondetection, bool vertical, std::string texture, u32 id)
3104 DSTACK(__FUNCTION_NAME);
3106 std::ostringstream os(std::ios_base::binary);
3107 writeU16(os, TOCLIENT_ADD_PARTICLESPAWNER);
3109 writeU16(os, amount);
3110 writeF1000(os, spawntime);
3111 writeV3F1000(os, minpos);
3112 writeV3F1000(os, maxpos);
3113 writeV3F1000(os, minvel);
3114 writeV3F1000(os, maxvel);
3115 writeV3F1000(os, minacc);
3116 writeV3F1000(os, maxacc);
3117 writeF1000(os, minexptime);
3118 writeF1000(os, maxexptime);
3119 writeF1000(os, minsize);
3120 writeF1000(os, maxsize);
3121 writeU8(os, collisiondetection);
3122 os<<serializeLongString(texture);
3124 writeU8(os, vertical);
3127 std::string s = os.str();
3128 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3130 if (peer_id != PEER_ID_INEXISTENT)
3133 m_clients.send(peer_id, 0, data, true);
3136 m_clients.sendToAll(0,data,true);
3140 void Server::SendDeleteParticleSpawner(u16 peer_id, u32 id)
3142 DSTACK(__FUNCTION_NAME);
3144 std::ostringstream os(std::ios_base::binary);
3145 writeU16(os, TOCLIENT_DELETE_PARTICLESPAWNER);
3150 std::string s = os.str();
3151 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3153 if (peer_id != PEER_ID_INEXISTENT) {
3155 m_clients.send(peer_id, 0, data, true);
3158 m_clients.sendToAll(0,data,true);
3163 void Server::SendHUDAdd(u16 peer_id, u32 id, HudElement *form)
3165 std::ostringstream os(std::ios_base::binary);
3168 writeU16(os, TOCLIENT_HUDADD);
3170 writeU8(os, (u8)form->type);
3171 writeV2F1000(os, form->pos);
3172 os << serializeString(form->name);
3173 writeV2F1000(os, form->scale);
3174 os << serializeString(form->text);
3175 writeU32(os, form->number);
3176 writeU32(os, form->item);
3177 writeU32(os, form->dir);
3178 writeV2F1000(os, form->align);
3179 writeV2F1000(os, form->offset);
3180 writeV3F1000(os, form->world_pos);
3183 std::string s = os.str();
3184 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3186 m_clients.send(peer_id, 1, data, true);
3189 void Server::SendHUDRemove(u16 peer_id, u32 id)
3191 std::ostringstream os(std::ios_base::binary);
3194 writeU16(os, TOCLIENT_HUDRM);
3198 std::string s = os.str();
3199 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3202 m_clients.send(peer_id, 1, data, true);
3205 void Server::SendHUDChange(u16 peer_id, u32 id, HudElementStat stat, void *value)
3207 std::ostringstream os(std::ios_base::binary);
3210 writeU16(os, TOCLIENT_HUDCHANGE);
3212 writeU8(os, (u8)stat);
3215 case HUD_STAT_SCALE:
3216 case HUD_STAT_ALIGN:
3217 case HUD_STAT_OFFSET:
3218 writeV2F1000(os, *(v2f *)value);
3222 os << serializeString(*(std::string *)value);
3224 case HUD_STAT_WORLD_POS:
3225 writeV3F1000(os, *(v3f *)value);
3227 case HUD_STAT_NUMBER:
3231 writeU32(os, *(u32 *)value);
3236 std::string s = os.str();
3237 SharedBuffer<u8> data((u8 *)s.c_str(), s.size());
3239 m_clients.send(peer_id, 0, data, true);
3242 void Server::SendHUDSetFlags(u16 peer_id, u32 flags, u32 mask)
3244 std::ostringstream os(std::ios_base::binary);
3247 writeU16(os, TOCLIENT_HUD_SET_FLAGS);
3248 writeU32(os, flags);
3252 std::string s = os.str();
3253 SharedBuffer<u8> data((u8 *)s.c_str(), s.size());
3255 m_clients.send(peer_id, 0, data, true);
3258 void Server::SendHUDSetParam(u16 peer_id, u16 param, const std::string &value)
3260 std::ostringstream os(std::ios_base::binary);
3263 writeU16(os, TOCLIENT_HUD_SET_PARAM);
3264 writeU16(os, param);
3265 os<<serializeString(value);
3268 std::string s = os.str();
3269 SharedBuffer<u8> data((u8 *)s.c_str(), s.size());
3271 m_clients.send(peer_id, 0, data, true);
3274 void Server::SendSetSky(u16 peer_id, const video::SColor &bgcolor,
3275 const std::string &type, const std::vector<std::string> ¶ms)
3277 std::ostringstream os(std::ios_base::binary);
3280 writeU16(os, TOCLIENT_SET_SKY);
3281 writeARGB8(os, bgcolor);
3282 os<<serializeString(type);
3283 writeU16(os, params.size());
3284 for(size_t i=0; i<params.size(); i++)
3285 os<<serializeString(params[i]);
3288 std::string s = os.str();
3289 SharedBuffer<u8> data((u8 *)s.c_str(), s.size());
3291 m_clients.send(peer_id, 0, data, true);
3294 void Server::SendOverrideDayNightRatio(u16 peer_id, bool do_override,
3297 std::ostringstream os(std::ios_base::binary);
3300 writeU16(os, TOCLIENT_OVERRIDE_DAY_NIGHT_RATIO);
3301 writeU8(os, do_override);
3302 writeU16(os, ratio*65535);
3305 std::string s = os.str();
3306 SharedBuffer<u8> data((u8 *)s.c_str(), s.size());
3308 m_clients.send(peer_id, 0, data, true);
3311 void Server::SendTimeOfDay(u16 peer_id, u16 time, f32 time_speed)
3313 DSTACK(__FUNCTION_NAME);
3316 SharedBuffer<u8> data(2+2+4);
3317 writeU16(&data[0], TOCLIENT_TIME_OF_DAY);
3318 writeU16(&data[2], time);
3319 writeF1000(&data[4], time_speed);
3321 if (peer_id == PEER_ID_INEXISTENT) {
3322 m_clients.sendToAll(0,data,true);
3326 m_clients.send(peer_id, 0, data, true);
3330 void Server::SendPlayerHP(u16 peer_id)
3332 DSTACK(__FUNCTION_NAME);
3333 PlayerSAO *playersao = getPlayerSAO(peer_id);
3335 playersao->m_hp_not_sent = false;
3336 SendHP(peer_id, playersao->getHP());
3338 // Send to other clients
3339 std::string str = gob_cmd_punched(playersao->readDamage(), playersao->getHP());
3340 ActiveObjectMessage aom(playersao->getId(), true, str);
3341 playersao->m_messages_out.push_back(aom);
3344 void Server::SendPlayerBreath(u16 peer_id)
3346 DSTACK(__FUNCTION_NAME);
3347 PlayerSAO *playersao = getPlayerSAO(peer_id);
3349 playersao->m_breath_not_sent = false;
3350 SendBreath(peer_id, playersao->getBreath());
3353 void Server::SendMovePlayer(u16 peer_id)
3355 DSTACK(__FUNCTION_NAME);
3356 Player *player = m_env->getPlayer(peer_id);
3359 std::ostringstream os(std::ios_base::binary);
3360 writeU16(os, TOCLIENT_MOVE_PLAYER);
3361 writeV3F1000(os, player->getPosition());
3362 writeF1000(os, player->getPitch());
3363 writeF1000(os, player->getYaw());
3366 v3f pos = player->getPosition();
3367 f32 pitch = player->getPitch();
3368 f32 yaw = player->getYaw();
3369 verbosestream<<"Server: Sending TOCLIENT_MOVE_PLAYER"
3370 <<" pos=("<<pos.X<<","<<pos.Y<<","<<pos.Z<<")"
3377 std::string s = os.str();
3378 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3380 m_clients.send(peer_id, 0, data, true);
3383 void Server::SendPlayerPrivileges(u16 peer_id)
3385 Player *player = m_env->getPlayer(peer_id);
3387 if(player->peer_id == PEER_ID_INEXISTENT)
3390 std::set<std::string> privs;
3391 m_script->getAuth(player->getName(), NULL, &privs);
3393 std::ostringstream os(std::ios_base::binary);
3394 writeU16(os, TOCLIENT_PRIVILEGES);
3395 writeU16(os, privs.size());
3396 for(std::set<std::string>::const_iterator i = privs.begin();
3397 i != privs.end(); i++){
3398 os<<serializeString(*i);
3402 std::string s = os.str();
3403 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3405 m_clients.send(peer_id, 0, data, true);
3408 void Server::SendPlayerInventoryFormspec(u16 peer_id)
3410 Player *player = m_env->getPlayer(peer_id);
3412 if(player->peer_id == PEER_ID_INEXISTENT)
3415 std::ostringstream os(std::ios_base::binary);
3416 writeU16(os, TOCLIENT_INVENTORY_FORMSPEC);
3417 os<<serializeLongString(player->inventory_formspec);
3420 std::string s = os.str();
3421 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3423 m_clients.send(peer_id, 0, data, true);
3426 s32 Server::playSound(const SimpleSoundSpec &spec,
3427 const ServerSoundParams ¶ms)
3429 // Find out initial position of sound
3430 bool pos_exists = false;
3431 v3f pos = params.getPos(m_env, &pos_exists);
3432 // If position is not found while it should be, cancel sound
3433 if(pos_exists != (params.type != ServerSoundParams::SSP_LOCAL))
3436 // Filter destination clients
3437 std::list<u16> dst_clients;
3438 if(params.to_player != "")
3440 Player *player = m_env->getPlayer(params.to_player.c_str());
3442 infostream<<"Server::playSound: Player \""<<params.to_player
3443 <<"\" not found"<<std::endl;
3446 if(player->peer_id == PEER_ID_INEXISTENT){
3447 infostream<<"Server::playSound: Player \""<<params.to_player
3448 <<"\" not connected"<<std::endl;
3451 dst_clients.push_back(player->peer_id);
3455 std::list<u16> clients = m_clients.getClientIDs();
3457 for(std::list<u16>::iterator
3458 i = clients.begin(); i != clients.end(); ++i)
3460 Player *player = m_env->getPlayer(*i);
3464 if(player->getPosition().getDistanceFrom(pos) >
3465 params.max_hear_distance)
3468 dst_clients.push_back(*i);
3471 if(dst_clients.size() == 0)
3475 s32 id = m_next_sound_id++;
3476 // The sound will exist as a reference in m_playing_sounds
3477 m_playing_sounds[id] = ServerPlayingSound();
3478 ServerPlayingSound &psound = m_playing_sounds[id];
3479 psound.params = params;
3480 for(std::list<u16>::iterator i = dst_clients.begin();
3481 i != dst_clients.end(); i++)
3482 psound.clients.insert(*i);
3484 std::ostringstream os(std::ios_base::binary);
3485 writeU16(os, TOCLIENT_PLAY_SOUND);
3487 os<<serializeString(spec.name);
3488 writeF1000(os, spec.gain * params.gain);
3489 writeU8(os, params.type);
3490 writeV3F1000(os, pos);
3491 writeU16(os, params.object);
3492 writeU8(os, params.loop);
3494 std::string s = os.str();
3495 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3497 for(std::list<u16>::iterator i = dst_clients.begin();
3498 i != dst_clients.end(); i++){
3500 m_clients.send(*i, 0, data, true);
3504 void Server::stopSound(s32 handle)
3506 // Get sound reference
3507 std::map<s32, ServerPlayingSound>::iterator i =
3508 m_playing_sounds.find(handle);
3509 if(i == m_playing_sounds.end())
3511 ServerPlayingSound &psound = i->second;
3513 std::ostringstream os(std::ios_base::binary);
3514 writeU16(os, TOCLIENT_STOP_SOUND);
3515 writeS32(os, handle);
3517 std::string s = os.str();
3518 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3520 for(std::set<u16>::iterator i = psound.clients.begin();
3521 i != psound.clients.end(); i++){
3523 m_clients.send(*i, 0, data, true);
3525 // Remove sound reference
3526 m_playing_sounds.erase(i);
3529 void Server::sendRemoveNode(v3s16 p, u16 ignore_id,
3530 std::list<u16> *far_players, float far_d_nodes)
3532 float maxd = far_d_nodes*BS;
3533 v3f p_f = intToFloat(p, BS);
3537 SharedBuffer<u8> reply(replysize);
3538 writeU16(&reply[0], TOCLIENT_REMOVENODE);
3539 writeS16(&reply[2], p.X);
3540 writeS16(&reply[4], p.Y);
3541 writeS16(&reply[6], p.Z);
3543 std::list<u16> clients = m_clients.getClientIDs();
3544 for(std::list<u16>::iterator
3545 i = clients.begin();
3546 i != clients.end(); ++i)
3551 Player *player = m_env->getPlayer(*i);
3554 // If player is far away, only set modified blocks not sent
3555 v3f player_pos = player->getPosition();
3556 if(player_pos.getDistanceFrom(p_f) > maxd)
3558 far_players->push_back(*i);
3565 m_clients.send(*i, 0, reply, true);
3569 void Server::sendAddNode(v3s16 p, MapNode n, u16 ignore_id,
3570 std::list<u16> *far_players, float far_d_nodes,
3571 bool remove_metadata)
3573 float maxd = far_d_nodes*BS;
3574 v3f p_f = intToFloat(p, BS);
3576 std::list<u16> clients = m_clients.getClientIDs();
3577 for(std::list<u16>::iterator
3578 i = clients.begin();
3579 i != clients.end(); ++i)
3585 Player *player = m_env->getPlayer(*i);
3588 // If player is far away, only set modified blocks not sent
3589 v3f player_pos = player->getPosition();
3590 if(player_pos.getDistanceFrom(p_f) > maxd)
3592 far_players->push_back(*i);
3597 SharedBuffer<u8> reply(0);
3599 RemoteClient* client = m_clients.lockedGetClientNoEx(*i);
3603 u32 replysize = 9 + MapNode::serializedLength(client->serialization_version);
3604 reply = SharedBuffer<u8>(replysize);
3605 writeU16(&reply[0], TOCLIENT_ADDNODE);
3606 writeS16(&reply[2], p.X);
3607 writeS16(&reply[4], p.Y);
3608 writeS16(&reply[6], p.Z);
3609 n.serialize(&reply[8], client->serialization_version);
3610 u32 index = 8 + MapNode::serializedLength(client->serialization_version);
3611 writeU8(&reply[index], remove_metadata ? 0 : 1);
3613 if (!remove_metadata) {
3614 if (client->net_proto_version <= 21) {
3615 // Old clients always clear metadata; fix it
3616 // by sending the full block again.
3617 client->SetBlockNotSent(p);
3624 if (reply.getSize() > 0)
3625 m_clients.send(*i, 0, reply, true);
3629 void Server::setBlockNotSent(v3s16 p)
3631 std::list<u16> clients = m_clients.getClientIDs();
3633 for(std::list<u16>::iterator
3634 i = clients.begin();
3635 i != clients.end(); ++i)
3637 RemoteClient *client = m_clients.lockedGetClientNoEx(*i);
3638 client->SetBlockNotSent(p);
3643 void Server::SendBlockNoLock(u16 peer_id, MapBlock *block, u8 ver, u16 net_proto_version)
3645 DSTACK(__FUNCTION_NAME);
3647 v3s16 p = block->getPos();
3651 bool completely_air = true;
3652 for(s16 z0=0; z0<MAP_BLOCKSIZE; z0++)
3653 for(s16 x0=0; x0<MAP_BLOCKSIZE; x0++)
3654 for(s16 y0=0; y0<MAP_BLOCKSIZE; y0++)
3656 if(block->getNodeNoEx(v3s16(x0,y0,z0)).d != CONTENT_AIR)
3658 completely_air = false;
3659 x0 = y0 = z0 = MAP_BLOCKSIZE; // Break out
3664 infostream<<"Server: Sending block ("<<p.X<<","<<p.Y<<","<<p.Z<<"): ";
3666 infostream<<"[completely air] ";
3667 infostream<<std::endl;
3671 Create a packet with the block in the right format
3674 std::ostringstream os(std::ios_base::binary);
3675 block->serialize(os, ver, false);
3676 block->serializeNetworkSpecific(os, net_proto_version);
3677 std::string s = os.str();
3678 SharedBuffer<u8> blockdata((u8*)s.c_str(), s.size());
3680 u32 replysize = 8 + blockdata.getSize();
3681 SharedBuffer<u8> reply(replysize);
3682 writeU16(&reply[0], TOCLIENT_BLOCKDATA);
3683 writeS16(&reply[2], p.X);
3684 writeS16(&reply[4], p.Y);
3685 writeS16(&reply[6], p.Z);
3686 memcpy(&reply[8], *blockdata, blockdata.getSize());
3688 /*infostream<<"Server: Sending block ("<<p.X<<","<<p.Y<<","<<p.Z<<")"
3689 <<": \tpacket size: "<<replysize<<std::endl;*/
3694 m_clients.send(peer_id, 2, reply, true);
3697 void Server::SendBlocks(float dtime)
3699 DSTACK(__FUNCTION_NAME);
3701 JMutexAutoLock envlock(m_env_mutex);
3702 //TODO check if one big lock could be faster then multiple small ones
3704 ScopeProfiler sp(g_profiler, "Server: sel and send blocks to clients");
3706 std::vector<PrioritySortedBlockTransfer> queue;
3708 s32 total_sending = 0;
3711 ScopeProfiler sp(g_profiler, "Server: selecting blocks for sending");
3713 std::list<u16> clients = m_clients.getClientIDs();
3716 for(std::list<u16>::iterator
3717 i = clients.begin();
3718 i != clients.end(); ++i)
3720 RemoteClient *client = m_clients.lockedGetClientNoEx(*i,Active);
3725 total_sending += client->SendingCount();
3726 client->GetNextBlocks(m_env,m_emerge, dtime, queue);
3732 // Lowest priority number comes first.
3733 // Lowest is most important.
3734 std::sort(queue.begin(), queue.end());
3737 for(u32 i=0; i<queue.size(); i++)
3739 //TODO: Calculate limit dynamically
3740 if(total_sending >= g_settings->getS32
3741 ("max_simultaneous_block_sends_server_total"))
3744 PrioritySortedBlockTransfer q = queue[i];
3746 MapBlock *block = NULL;
3749 block = m_env->getMap().getBlockNoCreate(q.pos);
3751 catch(InvalidPositionException &e)
3756 RemoteClient *client = m_clients.lockedGetClientNoEx(q.peer_id,Active);
3761 SendBlockNoLock(q.peer_id, block, client->serialization_version, client->net_proto_version);
3763 client->SentBlock(q.pos);
3769 void Server::fillMediaCache()
3771 DSTACK(__FUNCTION_NAME);
3773 infostream<<"Server: Calculating media file checksums"<<std::endl;
3775 // Collect all media file paths
3776 std::list<std::string> paths;
3777 for(std::vector<ModSpec>::iterator i = m_mods.begin();
3778 i != m_mods.end(); i++){
3779 const ModSpec &mod = *i;
3780 paths.push_back(mod.path + DIR_DELIM + "textures");
3781 paths.push_back(mod.path + DIR_DELIM + "sounds");
3782 paths.push_back(mod.path + DIR_DELIM + "media");
3783 paths.push_back(mod.path + DIR_DELIM + "models");
3785 paths.push_back(porting::path_user + DIR_DELIM + "textures" + DIR_DELIM + "server");
3787 // Collect media file information from paths into cache
3788 for(std::list<std::string>::iterator i = paths.begin();
3789 i != paths.end(); i++)
3791 std::string mediapath = *i;
3792 std::vector<fs::DirListNode> dirlist = fs::GetDirListing(mediapath);
3793 for(u32 j=0; j<dirlist.size(); j++){
3794 if(dirlist[j].dir) // Ignode dirs
3796 std::string filename = dirlist[j].name;
3797 // If name contains illegal characters, ignore the file
3798 if(!string_allowed(filename, TEXTURENAME_ALLOWED_CHARS)){
3799 infostream<<"Server: ignoring illegal file name: \""
3800 <<filename<<"\""<<std::endl;
3803 // If name is not in a supported format, ignore it
3804 const char *supported_ext[] = {
3805 ".png", ".jpg", ".bmp", ".tga",
3806 ".pcx", ".ppm", ".psd", ".wal", ".rgb",
3808 ".x", ".b3d", ".md2", ".obj",
3811 if(removeStringEnd(filename, supported_ext) == ""){
3812 infostream<<"Server: ignoring unsupported file extension: \""
3813 <<filename<<"\""<<std::endl;
3816 // Ok, attempt to load the file and add to cache
3817 std::string filepath = mediapath + DIR_DELIM + filename;
3819 std::ifstream fis(filepath.c_str(), std::ios_base::binary);
3820 if(fis.good() == false){
3821 errorstream<<"Server::fillMediaCache(): Could not open \""
3822 <<filename<<"\" for reading"<<std::endl;
3825 std::ostringstream tmp_os(std::ios_base::binary);
3829 fis.read(buf, 1024);
3830 std::streamsize len = fis.gcount();
3831 tmp_os.write(buf, len);
3840 errorstream<<"Server::fillMediaCache(): Failed to read \""
3841 <<filename<<"\""<<std::endl;
3844 if(tmp_os.str().length() == 0){
3845 errorstream<<"Server::fillMediaCache(): Empty file \""
3846 <<filepath<<"\""<<std::endl;
3851 sha1.addBytes(tmp_os.str().c_str(), tmp_os.str().length());
3853 unsigned char *digest = sha1.getDigest();
3854 std::string sha1_base64 = base64_encode(digest, 20);
3855 std::string sha1_hex = hex_encode((char*)digest, 20);
3859 this->m_media[filename] = MediaInfo(filepath, sha1_base64);
3860 verbosestream<<"Server: "<<sha1_hex<<" is "<<filename<<std::endl;
3865 struct SendableMediaAnnouncement
3868 std::string sha1_digest;
3870 SendableMediaAnnouncement(const std::string name_="",
3871 const std::string sha1_digest_=""):
3873 sha1_digest(sha1_digest_)
3877 void Server::sendMediaAnnouncement(u16 peer_id)
3879 DSTACK(__FUNCTION_NAME);
3881 verbosestream<<"Server: Announcing files to id("<<peer_id<<")"
3884 std::list<SendableMediaAnnouncement> file_announcements;
3886 for(std::map<std::string, MediaInfo>::iterator i = m_media.begin();
3887 i != m_media.end(); i++){
3889 file_announcements.push_back(
3890 SendableMediaAnnouncement(i->first, i->second.sha1_digest));
3894 std::ostringstream os(std::ios_base::binary);
3902 u16 length of sha1_digest
3907 writeU16(os, TOCLIENT_ANNOUNCE_MEDIA);
3908 writeU16(os, file_announcements.size());
3910 for(std::list<SendableMediaAnnouncement>::iterator
3911 j = file_announcements.begin();
3912 j != file_announcements.end(); ++j){
3913 os<<serializeString(j->name);
3914 os<<serializeString(j->sha1_digest);
3916 os<<serializeString(g_settings->get("remote_media"));
3919 std::string s = os.str();
3920 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3923 m_clients.send(peer_id, 0, data, true);
3926 struct SendableMedia
3932 SendableMedia(const std::string &name_="", const std::string path_="",
3933 const std::string &data_=""):
3940 void Server::sendRequestedMedia(u16 peer_id,
3941 const std::list<std::string> &tosend)
3943 DSTACK(__FUNCTION_NAME);
3945 verbosestream<<"Server::sendRequestedMedia(): "
3946 <<"Sending files to client"<<std::endl;
3950 // Put 5kB in one bunch (this is not accurate)
3951 u32 bytes_per_bunch = 5000;
3953 std::vector< std::list<SendableMedia> > file_bunches;
3954 file_bunches.push_back(std::list<SendableMedia>());
3956 u32 file_size_bunch_total = 0;
3958 for(std::list<std::string>::const_iterator i = tosend.begin();
3959 i != tosend.end(); ++i)
3961 const std::string &name = *i;
3963 if(m_media.find(name) == m_media.end()){
3964 errorstream<<"Server::sendRequestedMedia(): Client asked for "
3965 <<"unknown file \""<<(name)<<"\""<<std::endl;
3969 //TODO get path + name
3970 std::string tpath = m_media[name].path;
3973 std::ifstream fis(tpath.c_str(), std::ios_base::binary);
3974 if(fis.good() == false){
3975 errorstream<<"Server::sendRequestedMedia(): Could not open \""
3976 <<tpath<<"\" for reading"<<std::endl;
3979 std::ostringstream tmp_os(std::ios_base::binary);
3983 fis.read(buf, 1024);
3984 std::streamsize len = fis.gcount();
3985 tmp_os.write(buf, len);
3986 file_size_bunch_total += len;
3995 errorstream<<"Server::sendRequestedMedia(): Failed to read \""
3996 <<name<<"\""<<std::endl;
3999 /*infostream<<"Server::sendRequestedMedia(): Loaded \""
4000 <<tname<<"\""<<std::endl;*/
4002 file_bunches[file_bunches.size()-1].push_back(
4003 SendableMedia(name, tpath, tmp_os.str()));
4005 // Start next bunch if got enough data
4006 if(file_size_bunch_total >= bytes_per_bunch){
4007 file_bunches.push_back(std::list<SendableMedia>());
4008 file_size_bunch_total = 0;
4013 /* Create and send packets */
4015 u32 num_bunches = file_bunches.size();
4016 for(u32 i=0; i<num_bunches; i++)
4018 std::ostringstream os(std::ios_base::binary);
4022 u16 total number of texture bunches
4023 u16 index of this bunch
4024 u32 number of files in this bunch
4033 writeU16(os, TOCLIENT_MEDIA);
4034 writeU16(os, num_bunches);
4036 writeU32(os, file_bunches[i].size());
4038 for(std::list<SendableMedia>::iterator
4039 j = file_bunches[i].begin();
4040 j != file_bunches[i].end(); ++j){
4041 os<<serializeString(j->name);
4042 os<<serializeLongString(j->data);
4046 std::string s = os.str();
4047 verbosestream<<"Server::sendRequestedMedia(): bunch "
4048 <<i<<"/"<<num_bunches
4049 <<" files="<<file_bunches[i].size()
4050 <<" size=" <<s.size()<<std::endl;
4051 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
4053 m_clients.send(peer_id, 2, data, true);
4057 void Server::sendDetachedInventory(const std::string &name, u16 peer_id)
4059 if(m_detached_inventories.count(name) == 0){
4060 errorstream<<__FUNCTION_NAME<<": \""<<name<<"\" not found"<<std::endl;
4063 Inventory *inv = m_detached_inventories[name];
4065 std::ostringstream os(std::ios_base::binary);
4066 writeU16(os, TOCLIENT_DETACHED_INVENTORY);
4067 os<<serializeString(name);
4071 std::string s = os.str();
4072 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
4074 if (peer_id != PEER_ID_INEXISTENT)
4077 m_clients.send(peer_id, 0, data, true);
4081 m_clients.sendToAll(0,data,true);
4085 void Server::sendDetachedInventories(u16 peer_id)
4087 DSTACK(__FUNCTION_NAME);
4089 for(std::map<std::string, Inventory*>::iterator
4090 i = m_detached_inventories.begin();
4091 i != m_detached_inventories.end(); i++){
4092 const std::string &name = i->first;
4093 //Inventory *inv = i->second;
4094 sendDetachedInventory(name, peer_id);
4102 void Server::DiePlayer(u16 peer_id)
4104 DSTACK(__FUNCTION_NAME);
4106 PlayerSAO *playersao = getPlayerSAO(peer_id);
4109 infostream<<"Server::DiePlayer(): Player "
4110 <<playersao->getPlayer()->getName()
4111 <<" dies"<<std::endl;
4113 playersao->setHP(0);
4115 // Trigger scripted stuff
4116 m_script->on_dieplayer(playersao);
4118 SendPlayerHP(peer_id);
4119 SendDeathscreen(peer_id, false, v3f(0,0,0));
4122 void Server::RespawnPlayer(u16 peer_id)
4124 DSTACK(__FUNCTION_NAME);
4126 PlayerSAO *playersao = getPlayerSAO(peer_id);
4129 infostream<<"Server::RespawnPlayer(): Player "
4130 <<playersao->getPlayer()->getName()
4131 <<" respawns"<<std::endl;
4133 playersao->setHP(PLAYER_MAX_HP);
4135 bool repositioned = m_script->on_respawnplayer(playersao);
4137 v3f pos = findSpawnPos(m_env->getServerMap());
4138 playersao->setPos(pos);
4142 void Server::DenyAccess(u16 peer_id, const std::wstring &reason)
4144 DSTACK(__FUNCTION_NAME);
4146 SendAccessDenied(peer_id, reason);
4147 m_clients.event(peer_id,SetDenied);
4148 m_con.DisconnectPeer(peer_id);
4151 void Server::DeleteClient(u16 peer_id, ClientDeletionReason reason)
4153 DSTACK(__FUNCTION_NAME);
4154 std::wstring message;
4157 Clear references to playing sounds
4159 for(std::map<s32, ServerPlayingSound>::iterator
4160 i = m_playing_sounds.begin();
4161 i != m_playing_sounds.end();)
4163 ServerPlayingSound &psound = i->second;
4164 psound.clients.erase(peer_id);
4165 if(psound.clients.size() == 0)
4166 m_playing_sounds.erase(i++);
4171 Player *player = m_env->getPlayer(peer_id);
4173 // Collect information about leaving in chat
4175 if(player != NULL && reason != CDR_DENY)
4177 std::wstring name = narrow_to_wide(player->getName());
4180 message += L" left the game.";
4181 if(reason == CDR_TIMEOUT)
4182 message += L" (timed out)";
4186 /* Run scripts and remove from environment */
4190 PlayerSAO *playersao = player->getPlayerSAO();
4193 m_script->on_leaveplayer(playersao);
4195 playersao->disconnected();
4203 if(player != NULL && reason != CDR_DENY)
4205 std::ostringstream os(std::ios_base::binary);
4206 std::list<u16> clients = m_clients.getClientIDs();
4208 for(std::list<u16>::iterator
4209 i = clients.begin();
4210 i != clients.end(); ++i)
4213 Player *player = m_env->getPlayer(*i);
4216 // Get name of player
4217 os<<player->getName()<<" ";
4220 actionstream<<player->getName()<<" "
4221 <<(reason==CDR_TIMEOUT?"times out.":"leaves game.")
4222 <<" List of players: "<<os.str()<<std::endl;
4226 m_clients.DeleteClient(peer_id);
4227 m_env_mutex.Unlock();
4230 // Send leave chat message to all remaining clients
4231 if(message.length() != 0)
4232 SendChatMessage(PEER_ID_INEXISTENT,message);
4235 void Server::UpdateCrafting(u16 peer_id)
4237 DSTACK(__FUNCTION_NAME);
4239 Player* player = m_env->getPlayer(peer_id);
4242 // Get a preview for crafting
4244 InventoryLocation loc;
4245 loc.setPlayer(player->getName());
4246 getCraftingResult(&player->inventory, preview, false, this);
4247 m_env->getScriptIface()->item_CraftPredict(preview, player->getPlayerSAO(), (&player->inventory)->getList("craft"), loc);
4249 // Put the new preview in
4250 InventoryList *plist = player->inventory.getList("craftpreview");
4252 assert(plist->getSize() >= 1);
4253 plist->changeItem(0, preview);
4256 RemoteClient* Server::getClient(u16 peer_id, ClientState state_min)
4258 RemoteClient *client = getClientNoEx(peer_id,state_min);
4260 throw ClientNotFoundException("Client not found");
4264 RemoteClient* Server::getClientNoEx(u16 peer_id, ClientState state_min)
4266 return m_clients.getClientNoEx(peer_id, state_min);
4269 std::string Server::getPlayerName(u16 peer_id)
4271 Player *player = m_env->getPlayer(peer_id);
4273 return "[id="+itos(peer_id)+"]";
4274 return player->getName();
4277 PlayerSAO* Server::getPlayerSAO(u16 peer_id)
4279 Player *player = m_env->getPlayer(peer_id);
4282 return player->getPlayerSAO();
4285 std::wstring Server::getStatusString()
4287 std::wostringstream os(std::ios_base::binary);
4290 os<<L"version="<<narrow_to_wide(minetest_version_simple);
4292 os<<L", uptime="<<m_uptime.get();
4294 os<<L", max_lag="<<m_env->getMaxLagEstimate();
4295 // Information about clients
4298 std::list<u16> clients = m_clients.getClientIDs();
4299 for(std::list<u16>::iterator i = clients.begin();
4300 i != clients.end(); ++i)
4303 Player *player = m_env->getPlayer(*i);
4304 // Get name of player
4305 std::wstring name = L"unknown";
4307 name = narrow_to_wide(player->getName());
4308 // Add name to information string
4316 if(((ServerMap*)(&m_env->getMap()))->isSavingEnabled() == false)
4317 os<<std::endl<<L"# Server: "<<" WARNING: Map saving is disabled.";
4318 if(g_settings->get("motd") != "")
4319 os<<std::endl<<L"# Server: "<<narrow_to_wide(g_settings->get("motd"));
4323 std::set<std::string> Server::getPlayerEffectivePrivs(const std::string &name)
4325 std::set<std::string> privs;
4326 m_script->getAuth(name, NULL, &privs);
4330 bool Server::checkPriv(const std::string &name, const std::string &priv)
4332 std::set<std::string> privs = getPlayerEffectivePrivs(name);
4333 return (privs.count(priv) != 0);
4336 void Server::reportPrivsModified(const std::string &name)
4339 std::list<u16> clients = m_clients.getClientIDs();
4340 for(std::list<u16>::iterator
4341 i = clients.begin();
4342 i != clients.end(); ++i){
4343 Player *player = m_env->getPlayer(*i);
4344 reportPrivsModified(player->getName());
4347 Player *player = m_env->getPlayer(name.c_str());
4350 SendPlayerPrivileges(player->peer_id);
4351 PlayerSAO *sao = player->getPlayerSAO();
4354 sao->updatePrivileges(
4355 getPlayerEffectivePrivs(name),
4360 void Server::reportInventoryFormspecModified(const std::string &name)
4362 Player *player = m_env->getPlayer(name.c_str());
4365 SendPlayerInventoryFormspec(player->peer_id);
4368 void Server::setIpBanned(const std::string &ip, const std::string &name)
4370 m_banmanager->add(ip, name);
4373 void Server::unsetIpBanned(const std::string &ip_or_name)
4375 m_banmanager->remove(ip_or_name);
4378 std::string Server::getBanDescription(const std::string &ip_or_name)
4380 return m_banmanager->getBanDescription(ip_or_name);
4383 void Server::notifyPlayer(const char *name, const std::wstring msg, const bool prepend = true)
4385 Player *player = m_env->getPlayer(name);
4389 if (player->peer_id == PEER_ID_INEXISTENT)
4393 SendChatMessage(player->peer_id, std::wstring(L"Server -!- ")+msg);
4395 SendChatMessage(player->peer_id, msg);
4398 bool Server::showFormspec(const char *playername, const std::string &formspec, const std::string &formname)
4400 Player *player = m_env->getPlayer(playername);
4404 infostream<<"showFormspec: couldn't find player:"<<playername<<std::endl;
4408 SendShowFormspecMessage(player->peer_id, formspec, formname);
4412 u32 Server::hudAdd(Player *player, HudElement *form) {
4416 u32 id = player->getFreeHudID();
4417 if (id < player->hud.size())
4418 player->hud[id] = form;
4420 player->hud.push_back(form);
4422 SendHUDAdd(player->peer_id, id, form);
4426 bool Server::hudRemove(Player *player, u32 id) {
4427 if (!player || id >= player->hud.size() || !player->hud[id])
4430 delete player->hud[id];
4431 player->hud[id] = NULL;
4433 SendHUDRemove(player->peer_id, id);
4437 bool Server::hudChange(Player *player, u32 id, HudElementStat stat, void *data) {
4441 SendHUDChange(player->peer_id, id, stat, data);
4445 bool Server::hudSetFlags(Player *player, u32 flags, u32 mask) {
4449 SendHUDSetFlags(player->peer_id, flags, mask);
4453 bool Server::hudSetHotbarItemcount(Player *player, s32 hotbar_itemcount) {
4456 if (hotbar_itemcount <= 0 || hotbar_itemcount > HUD_HOTBAR_ITEMCOUNT_MAX)
4459 std::ostringstream os(std::ios::binary);
4460 writeS32(os, hotbar_itemcount);
4461 SendHUDSetParam(player->peer_id, HUD_PARAM_HOTBAR_ITEMCOUNT, os.str());
4465 void Server::hudSetHotbarImage(Player *player, std::string name) {
4469 SendHUDSetParam(player->peer_id, HUD_PARAM_HOTBAR_IMAGE, name);
4472 void Server::hudSetHotbarSelectedImage(Player *player, std::string name) {
4476 SendHUDSetParam(player->peer_id, HUD_PARAM_HOTBAR_SELECTED_IMAGE, name);
4479 bool Server::setSky(Player *player, const video::SColor &bgcolor,
4480 const std::string &type, const std::vector<std::string> ¶ms)
4485 SendSetSky(player->peer_id, bgcolor, type, params);
4489 bool Server::overrideDayNightRatio(Player *player, bool do_override,
4495 SendOverrideDayNightRatio(player->peer_id, do_override, ratio);
4499 void Server::notifyPlayers(const std::wstring msg)
4501 SendChatMessage(PEER_ID_INEXISTENT,msg);
4504 void Server::spawnParticle(const char *playername, v3f pos,
4505 v3f velocity, v3f acceleration,
4506 float expirationtime, float size, bool
4507 collisiondetection, bool vertical, std::string texture)
4509 Player *player = m_env->getPlayer(playername);
4512 SendSpawnParticle(player->peer_id, pos, velocity, acceleration,
4513 expirationtime, size, collisiondetection, vertical, texture);
4516 void Server::spawnParticleAll(v3f pos, v3f velocity, v3f acceleration,
4517 float expirationtime, float size,
4518 bool collisiondetection, bool vertical, std::string texture)
4520 SendSpawnParticle(PEER_ID_INEXISTENT,pos, velocity, acceleration,
4521 expirationtime, size, collisiondetection, vertical, texture);
4524 u32 Server::addParticleSpawner(const char *playername,
4525 u16 amount, float spawntime,
4526 v3f minpos, v3f maxpos,
4527 v3f minvel, v3f maxvel,
4528 v3f minacc, v3f maxacc,
4529 float minexptime, float maxexptime,
4530 float minsize, float maxsize,
4531 bool collisiondetection, bool vertical, std::string texture)
4533 Player *player = m_env->getPlayer(playername);
4538 for(;;) // look for unused particlespawner id
4541 if (std::find(m_particlespawner_ids.begin(),
4542 m_particlespawner_ids.end(), id)
4543 == m_particlespawner_ids.end())
4545 m_particlespawner_ids.push_back(id);
4550 SendAddParticleSpawner(player->peer_id, amount, spawntime,
4551 minpos, maxpos, minvel, maxvel, minacc, maxacc,
4552 minexptime, maxexptime, minsize, maxsize,
4553 collisiondetection, vertical, texture, id);
4558 u32 Server::addParticleSpawnerAll(u16 amount, float spawntime,
4559 v3f minpos, v3f maxpos,
4560 v3f minvel, v3f maxvel,
4561 v3f minacc, v3f maxacc,
4562 float minexptime, float maxexptime,
4563 float minsize, float maxsize,
4564 bool collisiondetection, bool vertical, std::string texture)
4567 for(;;) // look for unused particlespawner id
4570 if (std::find(m_particlespawner_ids.begin(),
4571 m_particlespawner_ids.end(), id)
4572 == m_particlespawner_ids.end())
4574 m_particlespawner_ids.push_back(id);
4579 SendAddParticleSpawner(PEER_ID_INEXISTENT, amount, spawntime,
4580 minpos, maxpos, minvel, maxvel, minacc, maxacc,
4581 minexptime, maxexptime, minsize, maxsize,
4582 collisiondetection, vertical, texture, id);
4587 void Server::deleteParticleSpawner(const char *playername, u32 id)
4589 Player *player = m_env->getPlayer(playername);
4593 m_particlespawner_ids.erase(
4594 std::remove(m_particlespawner_ids.begin(),
4595 m_particlespawner_ids.end(), id),
4596 m_particlespawner_ids.end());
4597 SendDeleteParticleSpawner(player->peer_id, id);
4600 void Server::deleteParticleSpawnerAll(u32 id)
4602 m_particlespawner_ids.erase(
4603 std::remove(m_particlespawner_ids.begin(),
4604 m_particlespawner_ids.end(), id),
4605 m_particlespawner_ids.end());
4606 SendDeleteParticleSpawner(PEER_ID_INEXISTENT, id);
4609 Inventory* Server::createDetachedInventory(const std::string &name)
4611 if(m_detached_inventories.count(name) > 0){
4612 infostream<<"Server clearing detached inventory \""<<name<<"\""<<std::endl;
4613 delete m_detached_inventories[name];
4615 infostream<<"Server creating detached inventory \""<<name<<"\""<<std::endl;
4617 Inventory *inv = new Inventory(m_itemdef);
4619 m_detached_inventories[name] = inv;
4620 //TODO find a better way to do this
4621 sendDetachedInventory(name,PEER_ID_INEXISTENT);
4628 BoolScopeSet(bool *dst, bool val):
4631 m_orig_state = *m_dst;
4636 *m_dst = m_orig_state;
4643 // actions: time-reversed list
4644 // Return value: success/failure
4645 bool Server::rollbackRevertActions(const std::list<RollbackAction> &actions,
4646 std::list<std::string> *log)
4648 infostream<<"Server::rollbackRevertActions(len="<<actions.size()<<")"<<std::endl;
4649 ServerMap *map = (ServerMap*)(&m_env->getMap());
4650 // Disable rollback report sink while reverting
4651 BoolScopeSet rollback_scope_disable(&m_rollback_sink_enabled, false);
4653 // Fail if no actions to handle
4654 if(actions.empty()){
4655 log->push_back("Nothing to do.");
4662 for(std::list<RollbackAction>::const_iterator
4663 i = actions.begin();
4664 i != actions.end(); i++)
4666 const RollbackAction &action = *i;
4668 bool success = action.applyRevert(map, this, this);
4671 std::ostringstream os;
4672 os<<"Revert of step ("<<num_tried<<") "<<action.toString()<<" failed";
4673 infostream<<"Map::rollbackRevertActions(): "<<os.str()<<std::endl;
4675 log->push_back(os.str());
4677 std::ostringstream os;
4678 os<<"Successfully reverted step ("<<num_tried<<") "<<action.toString();
4679 infostream<<"Map::rollbackRevertActions(): "<<os.str()<<std::endl;
4681 log->push_back(os.str());
4685 infostream<<"Map::rollbackRevertActions(): "<<num_failed<<"/"<<num_tried
4686 <<" failed"<<std::endl;
4688 // Call it done if less than half failed
4689 return num_failed <= num_tried/2;
4692 // IGameDef interface
4694 IItemDefManager* Server::getItemDefManager()
4698 INodeDefManager* Server::getNodeDefManager()
4702 ICraftDefManager* Server::getCraftDefManager()
4706 ITextureSource* Server::getTextureSource()
4710 IShaderSource* Server::getShaderSource()
4714 u16 Server::allocateUnknownNodeId(const std::string &name)
4716 return m_nodedef->allocateDummy(name);
4718 ISoundManager* Server::getSoundManager()
4720 return &dummySoundManager;
4722 MtEventManager* Server::getEventManager()
4726 IRollbackReportSink* Server::getRollbackReportSink()
4728 if(!m_enable_rollback_recording)
4730 if(!m_rollback_sink_enabled)
4735 IWritableItemDefManager* Server::getWritableItemDefManager()
4739 IWritableNodeDefManager* Server::getWritableNodeDefManager()
4743 IWritableCraftDefManager* Server::getWritableCraftDefManager()
4748 const ModSpec* Server::getModSpec(const std::string &modname)
4750 for(std::vector<ModSpec>::iterator i = m_mods.begin();
4751 i != m_mods.end(); i++){
4752 const ModSpec &mod = *i;
4753 if(mod.name == modname)
4758 void Server::getModNames(std::list<std::string> &modlist)
4760 for(std::vector<ModSpec>::iterator i = m_mods.begin(); i != m_mods.end(); i++)
4762 modlist.push_back(i->name);
4765 std::string Server::getBuiltinLuaPath()
4767 return porting::path_share + DIR_DELIM + "builtin";
4770 v3f findSpawnPos(ServerMap &map)
4772 //return v3f(50,50,50)*BS;
4777 nodepos = v2s16(0,0);
4782 s16 water_level = map.getWaterLevel();
4784 // Try to find a good place a few times
4785 for(s32 i=0; i<1000; i++)
4788 // We're going to try to throw the player to this position
4789 v2s16 nodepos2d = v2s16(
4790 -range + (myrand() % (range * 2)),
4791 -range + (myrand() % (range * 2)));
4793 // Get ground height at point
4794 s16 groundheight = map.findGroundLevel(nodepos2d);
4795 if (groundheight <= water_level) // Don't go underwater
4797 if (groundheight > water_level + 6) // Don't go to high places
4800 nodepos = v3s16(nodepos2d.X, groundheight, nodepos2d.Y);
4801 bool is_good = false;
4803 for (s32 i = 0; i < 10; i++) {
4804 v3s16 blockpos = getNodeBlockPos(nodepos);
4805 map.emergeBlock(blockpos, true);
4806 content_t c = map.getNodeNoEx(nodepos).getContent();
4807 if (c == CONTENT_AIR || c == CONTENT_IGNORE) {
4809 if (air_count >= 2){
4817 // Found a good place
4818 //infostream<<"Searched through "<<i<<" places."<<std::endl;
4824 return intToFloat(nodepos, BS);
4827 PlayerSAO* Server::emergePlayer(const char *name, u16 peer_id)
4829 RemotePlayer *player = NULL;
4830 bool newplayer = false;
4833 Try to get an existing player
4835 player = static_cast<RemotePlayer*>(m_env->getPlayer(name));
4837 // If player is already connected, cancel
4838 if(player != NULL && player->peer_id != 0)
4840 infostream<<"emergePlayer(): Player already connected"<<std::endl;
4845 If player with the wanted peer_id already exists, cancel.
4847 if(m_env->getPlayer(peer_id) != NULL)
4849 infostream<<"emergePlayer(): Player with wrong name but same"
4850 " peer_id already exists"<<std::endl;
4855 Create a new player if it doesn't exist yet
4860 player = new RemotePlayer(this);
4861 player->updateName(name);
4863 /* Set player position */
4864 infostream<<"Server: Finding spawn place for player \""
4865 <<name<<"\""<<std::endl;
4866 v3f pos = findSpawnPos(m_env->getServerMap());
4867 player->setPosition(pos);
4869 /* Add player to environment */
4870 m_env->addPlayer(player);
4874 Create a new player active object
4876 PlayerSAO *playersao = new PlayerSAO(m_env, player, peer_id,
4877 getPlayerEffectivePrivs(player->getName()),
4880 /* Clean up old HUD elements from previous sessions */
4881 player->hud.clear();
4883 /* Add object to environment */
4884 m_env->addActiveObject(playersao);
4888 m_script->on_newplayer(playersao);
4893 void dedicated_server_loop(Server &server, bool &kill)
4895 DSTACK(__FUNCTION_NAME);
4897 verbosestream<<"dedicated_server_loop()"<<std::endl;
4899 IntervalLimiter m_profiler_interval;
4903 float steplen = g_settings->getFloat("dedicated_server_step");
4904 // This is kind of a hack but can be done like this
4905 // because server.step() is very light
4907 ScopeProfiler sp(g_profiler, "dedicated server sleep");
4908 sleep_ms((int)(steplen*1000.0));
4910 server.step(steplen);
4912 if(server.getShutdownRequested() || kill)
4914 infostream<<"Dedicated server quitting"<<std::endl;
4916 if(g_settings->getBool("server_announce") == true)
4917 ServerList::sendAnnounce("delete");
4925 float profiler_print_interval =
4926 g_settings->getFloat("profiler_print_interval");
4927 if(profiler_print_interval != 0)
4929 if(m_profiler_interval.step(steplen, profiler_print_interval))
4931 infostream<<"Profiler:"<<std::endl;
4932 g_profiler->print(infostream);
4933 g_profiler->clear();