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 "jmutexautolock.h"
28 #include "constants.h"
33 #include "serverobject.h"
37 #include "script/cpp_api/scriptapi.h"
44 #include "content_mapnode.h"
45 #include "content_nodemeta.h"
46 #include "content_abm.h"
47 #include "content_sao.h"
52 #include "sound.h" // dummySoundManager
53 #include "event_manager.h"
55 #include "serverlist.h"
56 #include "util/string.h"
57 #include "util/pointedthing.h"
58 #include "util/mathconstants.h"
60 #include "util/serialize.h"
61 #include "defaultsettings.h"
63 class ClientNotFoundException : public BaseException
66 ClientNotFoundException(const char *s):
71 void * ServerThread::Thread()
75 log_register_thread("ServerThread");
77 DSTACK(__FUNCTION_NAME);
79 BEGIN_DEBUG_EXCEPTION_HANDLER
84 //TimeTaker timer("AsyncRunStep() + Receive()");
87 //TimeTaker timer("AsyncRunStep()");
88 m_server->AsyncRunStep();
91 //infostream<<"Running m_server->Receive()"<<std::endl;
94 catch(con::NoIncomingDataException &e)
97 catch(con::PeerNotFoundException &e)
99 infostream<<"Server: PeerNotFoundException"<<std::endl;
101 catch(ClientNotFoundException &e)
104 catch(con::ConnectionBindFailed &e)
106 m_server->setAsyncFatalError(e.what());
110 m_server->setAsyncFatalError(e.what());
114 END_DEBUG_EXCEPTION_HANDLER(errorstream)
119 v3f ServerSoundParams::getPos(ServerEnvironment *env, bool *pos_exists) const
121 if(pos_exists) *pos_exists = false;
126 if(pos_exists) *pos_exists = true;
131 ServerActiveObject *sao = env->getActiveObject(object);
134 if(pos_exists) *pos_exists = true;
135 return sao->getBasePosition(); }
140 void RemoteClient::GetNextBlocks(Server *server, float dtime,
141 std::vector<PrioritySortedBlockTransfer> &dest)
143 DSTACK(__FUNCTION_NAME);
146 TimeTaker timer("RemoteClient::GetNextBlocks", &timer_result);*/
149 m_nothing_to_send_pause_timer -= dtime;
150 m_nearest_unsent_reset_timer += dtime;
152 if(m_nothing_to_send_pause_timer >= 0)
155 Player *player = server->m_env->getPlayer(peer_id);
156 // This can happen sometimes; clients and players are not in perfect sync.
160 // Won't send anything if already sending
161 if(m_blocks_sending.size() >= g_settings->getU16
162 ("max_simultaneous_block_sends_per_client"))
164 //infostream<<"Not sending any blocks, Queue full."<<std::endl;
168 //TimeTaker timer("RemoteClient::GetNextBlocks");
170 v3f playerpos = player->getPosition();
171 v3f playerspeed = player->getSpeed();
172 v3f playerspeeddir(0,0,0);
173 if(playerspeed.getLength() > 1.0*BS)
174 playerspeeddir = playerspeed / playerspeed.getLength();
175 // Predict to next block
176 v3f playerpos_predicted = playerpos + playerspeeddir*MAP_BLOCKSIZE*BS;
178 v3s16 center_nodepos = floatToInt(playerpos_predicted, BS);
180 v3s16 center = getNodeBlockPos(center_nodepos);
182 // Camera position and direction
183 v3f camera_pos = player->getEyePosition();
184 v3f camera_dir = v3f(0,0,1);
185 camera_dir.rotateYZBy(player->getPitch());
186 camera_dir.rotateXZBy(player->getYaw());
188 /*infostream<<"camera_dir=("<<camera_dir.X<<","<<camera_dir.Y<<","
189 <<camera_dir.Z<<")"<<std::endl;*/
192 Get the starting value of the block finder radius.
195 if(m_last_center != center)
197 m_nearest_unsent_d = 0;
198 m_last_center = center;
201 /*infostream<<"m_nearest_unsent_reset_timer="
202 <<m_nearest_unsent_reset_timer<<std::endl;*/
204 // Reset periodically to workaround for some bugs or stuff
205 if(m_nearest_unsent_reset_timer > 20.0)
207 m_nearest_unsent_reset_timer = 0;
208 m_nearest_unsent_d = 0;
209 //infostream<<"Resetting m_nearest_unsent_d for "
210 // <<server->getPlayerName(peer_id)<<std::endl;
213 //s16 last_nearest_unsent_d = m_nearest_unsent_d;
214 s16 d_start = m_nearest_unsent_d;
216 //infostream<<"d_start="<<d_start<<std::endl;
218 u16 max_simul_sends_setting = g_settings->getU16
219 ("max_simultaneous_block_sends_per_client");
220 u16 max_simul_sends_usually = max_simul_sends_setting;
223 Check the time from last addNode/removeNode.
225 Decrease send rate if player is building stuff.
227 m_time_from_building += dtime;
228 if(m_time_from_building < g_settings->getFloat(
229 "full_block_send_enable_min_time_from_building"))
231 max_simul_sends_usually
232 = LIMITED_MAX_SIMULTANEOUS_BLOCK_SENDS;
236 Number of blocks sending + number of blocks selected for sending
238 u32 num_blocks_selected = m_blocks_sending.size();
241 next time d will be continued from the d from which the nearest
242 unsent block was found this time.
244 This is because not necessarily any of the blocks found this
245 time are actually sent.
247 s32 new_nearest_unsent_d = -1;
249 s16 d_max = g_settings->getS16("max_block_send_distance");
250 s16 d_max_gen = g_settings->getS16("max_block_generate_distance");
252 // Don't loop very much at a time
253 s16 max_d_increment_at_time = 2;
254 if(d_max > d_start + max_d_increment_at_time)
255 d_max = d_start + max_d_increment_at_time;
256 /*if(d_max_gen > d_start+2)
257 d_max_gen = d_start+2;*/
259 //infostream<<"Starting from "<<d_start<<std::endl;
261 s32 nearest_emerged_d = -1;
262 s32 nearest_emergefull_d = -1;
263 s32 nearest_sent_d = -1;
264 bool queue_is_full = false;
267 for(d = d_start; d <= d_max; d++)
269 /*errorstream<<"checking d="<<d<<" for "
270 <<server->getPlayerName(peer_id)<<std::endl;*/
271 //infostream<<"RemoteClient::SendBlocks(): d="<<d<<std::endl;
274 If m_nearest_unsent_d was changed by the EmergeThread
275 (it can change it to 0 through SetBlockNotSent),
277 Else update m_nearest_unsent_d
279 /*if(m_nearest_unsent_d != last_nearest_unsent_d)
281 d = m_nearest_unsent_d;
282 last_nearest_unsent_d = m_nearest_unsent_d;
286 Get the border/face dot coordinates of a "d-radiused"
289 std::list<v3s16> list;
290 getFacePositions(list, d);
292 std::list<v3s16>::iterator li;
293 for(li=list.begin(); li!=list.end(); ++li)
295 v3s16 p = *li + center;
299 - Don't allow too many simultaneous transfers
300 - EXCEPT when the blocks are very close
302 Also, don't send blocks that are already flying.
305 // Start with the usual maximum
306 u16 max_simul_dynamic = max_simul_sends_usually;
308 // If block is very close, allow full maximum
309 if(d <= BLOCK_SEND_DISABLE_LIMITS_MAX_D)
310 max_simul_dynamic = max_simul_sends_setting;
312 // Don't select too many blocks for sending
313 if(num_blocks_selected >= max_simul_dynamic)
315 queue_is_full = true;
316 goto queue_full_break;
319 // Don't send blocks that are currently being transferred
320 if(m_blocks_sending.find(p) != m_blocks_sending.end())
326 if(p.X < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
327 || p.X > MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
328 || p.Y < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
329 || p.Y > MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
330 || p.Z < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
331 || p.Z > MAP_GENERATION_LIMIT / MAP_BLOCKSIZE)
334 // If this is true, inexistent block will be made from scratch
335 bool generate = d <= d_max_gen;
338 /*// Limit the generating area vertically to 2/3
339 if(abs(p.Y - center.Y) > d_max_gen - d_max_gen / 3)
342 // Limit the send area vertically to 1/2
343 if(abs(p.Y - center.Y) > d_max / 2)
349 If block is far away, don't generate it unless it is
355 // Block center y in nodes
356 f32 y = (f32)(p.Y * MAP_BLOCKSIZE + MAP_BLOCKSIZE/2);
357 // Don't generate if it's very high or very low
358 if(y < -64 || y > 64)
362 v2s16 p2d_nodes_center(
366 // Get ground height in nodes
367 s16 gh = server->m_env->getServerMap().findGroundLevel(
370 // If differs a lot, don't generate
371 if(fabs(gh - y) > MAP_BLOCKSIZE*2)
373 // Actually, don't even send it
379 //infostream<<"d="<<d<<std::endl;
382 Don't generate or send if not in sight
383 FIXME This only works if the client uses a small enough
384 FOV setting. The default of 72 degrees is fine.
387 float camera_fov = (72.0*M_PI/180) * 4./3.;
388 if(isBlockInSight(p, camera_pos, camera_dir, camera_fov, 10000*BS) == false)
394 Don't send already sent blocks
397 if(m_blocks_sent.find(p) != m_blocks_sent.end())
404 Check if map has this block
406 MapBlock *block = server->m_env->getMap().getBlockNoCreateNoEx(p);
408 bool surely_not_found_on_disk = false;
409 bool block_is_invalid = false;
412 // Reset usage timer, this block will be of use in the future.
413 block->resetUsageTimer();
415 // Block is dummy if data doesn't exist.
416 // It means it has been not found from disk and not generated
419 surely_not_found_on_disk = true;
422 // Block is valid if lighting is up-to-date and data exists
423 if(block->isValid() == false)
425 block_is_invalid = true;
428 /*if(block->isFullyGenerated() == false)
430 block_is_invalid = true;
435 ServerMap *map = (ServerMap*)(&server->m_env->getMap());
436 v2s16 chunkpos = map->sector_to_chunk(p2d);
437 if(map->chunkNonVolatile(chunkpos) == false)
438 block_is_invalid = true;
440 if(block->isGenerated() == false)
441 block_is_invalid = true;
444 If block is not close, don't send it unless it is near
447 Block is near ground level if night-time mesh
448 differs from day-time mesh.
452 if(block->getDayNightDiff() == false)
459 If block has been marked to not exist on disk (dummy)
460 and generating new ones is not wanted, skip block.
462 if(generate == false && surely_not_found_on_disk == true)
469 Add inexistent block to emerge queue.
471 if(block == NULL || surely_not_found_on_disk || block_is_invalid)
473 /* //TODO: Get value from somewhere
474 // Allow only one block in emerge queue
475 //if(server->m_emerge_queue.peerItemCount(peer_id) < 1)
476 // Allow two blocks in queue per client
477 //if(server->m_emerge_queue.peerItemCount(peer_id) < 2)
479 // Make it more responsive when needing to generate stuff
480 if(surely_not_found_on_disk)
482 if(server->m_emerge_queue.peerItemCount(peer_id) < max_emerge)
484 //infostream<<"Adding block to emerge queue"<<std::endl;
486 // Add it to the emerge queue and trigger the thread
489 if(generate == false)
490 flags |= BLOCK_EMERGE_FLAG_FROMDISK;
492 server->m_emerge_queue.addBlock(peer_id, p, flags);
493 server->m_emergethread.trigger();
495 if(nearest_emerged_d == -1)
496 nearest_emerged_d = d;
498 if(nearest_emergefull_d == -1)
499 nearest_emergefull_d = d;
500 goto queue_full_break;
504 if (server->m_emerge->enqueueBlockEmerge(peer_id, p, generate)) {
505 if (nearest_emerged_d == -1)
506 nearest_emerged_d = d;
508 if (nearest_emergefull_d == -1)
509 nearest_emergefull_d = d;
510 goto queue_full_break;
517 if(nearest_sent_d == -1)
521 Add block to send queue
524 /*errorstream<<"sending from d="<<d<<" to "
525 <<server->getPlayerName(peer_id)<<std::endl;*/
527 PrioritySortedBlockTransfer q((float)d, p, peer_id);
531 num_blocks_selected += 1;
536 //infostream<<"Stopped at "<<d<<std::endl;
538 // If nothing was found for sending and nothing was queued for
539 // emerging, continue next time browsing from here
540 if(nearest_emerged_d != -1){
541 new_nearest_unsent_d = nearest_emerged_d;
542 } else if(nearest_emergefull_d != -1){
543 new_nearest_unsent_d = nearest_emergefull_d;
545 if(d > g_settings->getS16("max_block_send_distance")){
546 new_nearest_unsent_d = 0;
547 m_nothing_to_send_pause_timer = 2.0;
548 /*infostream<<"GetNextBlocks(): d wrapped around for "
549 <<server->getPlayerName(peer_id)
550 <<"; setting to 0 and pausing"<<std::endl;*/
552 if(nearest_sent_d != -1)
553 new_nearest_unsent_d = nearest_sent_d;
555 new_nearest_unsent_d = d;
559 if(new_nearest_unsent_d != -1)
560 m_nearest_unsent_d = new_nearest_unsent_d;
562 /*timer_result = timer.stop(true);
563 if(timer_result != 0)
564 infostream<<"GetNextBlocks timeout: "<<timer_result<<" (!=0)"<<std::endl;*/
567 void RemoteClient::GotBlock(v3s16 p)
569 if(m_blocks_sending.find(p) != m_blocks_sending.end())
570 m_blocks_sending.erase(p);
573 /*infostream<<"RemoteClient::GotBlock(): Didn't find in"
574 " m_blocks_sending"<<std::endl;*/
575 m_excess_gotblocks++;
577 m_blocks_sent.insert(p);
580 void RemoteClient::SentBlock(v3s16 p)
582 if(m_blocks_sending.find(p) == m_blocks_sending.end())
583 m_blocks_sending[p] = 0.0;
585 infostream<<"RemoteClient::SentBlock(): Sent block"
586 " already in m_blocks_sending"<<std::endl;
589 void RemoteClient::SetBlockNotSent(v3s16 p)
591 m_nearest_unsent_d = 0;
593 if(m_blocks_sending.find(p) != m_blocks_sending.end())
594 m_blocks_sending.erase(p);
595 if(m_blocks_sent.find(p) != m_blocks_sent.end())
596 m_blocks_sent.erase(p);
599 void RemoteClient::SetBlocksNotSent(std::map<v3s16, MapBlock*> &blocks)
601 m_nearest_unsent_d = 0;
603 for(std::map<v3s16, MapBlock*>::iterator
605 i != blocks.end(); ++i)
609 if(m_blocks_sending.find(p) != m_blocks_sending.end())
610 m_blocks_sending.erase(p);
611 if(m_blocks_sent.find(p) != m_blocks_sent.end())
612 m_blocks_sent.erase(p);
620 PlayerInfo::PlayerInfo()
626 void PlayerInfo::PrintLine(std::ostream *s)
629 (*s)<<"\""<<name<<"\" ("
630 <<(position.X/10)<<","<<(position.Y/10)
631 <<","<<(position.Z/10)<<") ";
633 (*s)<<" avg_rtt="<<avg_rtt;
642 const std::string &path_world,
643 const std::string &path_config,
644 const SubgameSpec &gamespec,
645 bool simple_singleplayer_mode
647 m_path_world(path_world),
648 m_path_config(path_config),
649 m_gamespec(gamespec),
650 m_simple_singleplayer_mode(simple_singleplayer_mode),
651 m_async_fatal_error(""),
653 m_con(PROTOCOL_ID, 512, CONNECTION_TIMEOUT,
654 g_settings->getBool("enable_ipv6") && g_settings->getBool("ipv6_server"), this),
655 m_banmanager(path_world+DIR_DELIM+"ipban.txt"),
657 m_rollback_sink_enabled(true),
658 m_enable_rollback_recording(false),
661 m_itemdef(createItemDefManager()),
662 m_nodedef(createNodeDefManager()),
663 m_craftdef(createCraftDefManager()),
664 m_event(new EventManager()),
666 m_time_of_day_send_timer(0),
668 m_shutdown_requested(false),
669 m_ignore_map_edit_events(false),
670 m_ignore_map_edit_events_peer_id(0)
672 m_liquid_transform_timer = 0.0;
673 m_liquid_transform_every = 1.0;
674 m_print_info_timer = 0.0;
675 m_masterserver_timer = 0.0;
676 m_objectdata_timer = 0.0;
677 m_emergethread_trigger_timer = 0.0;
678 m_savemap_timer = 0.0;
679 m_clients_number = 0;
683 m_step_dtime_mutex.Init();
687 throw ServerError("Supplied empty world path");
689 if(!gamespec.isValid())
690 throw ServerError("Supplied invalid gamespec");
692 infostream<<"Server created for gameid \""<<m_gamespec.id<<"\"";
693 if(m_simple_singleplayer_mode)
694 infostream<<" in simple singleplayer mode"<<std::endl;
696 infostream<<std::endl;
697 infostream<<"- world: "<<m_path_world<<std::endl;
698 infostream<<"- config: "<<m_path_config<<std::endl;
699 infostream<<"- game: "<<m_gamespec.path<<std::endl;
701 // Initialize default settings and override defaults with those provided
703 set_default_settings(g_settings);
704 Settings gamedefaults;
705 getGameMinetestConfig(gamespec.path, gamedefaults);
706 override_default_settings(g_settings, &gamedefaults);
708 // Create emerge manager
709 m_emerge = new EmergeManager(this);
711 // Create rollback manager
712 std::string rollback_path = m_path_world+DIR_DELIM+"rollback.txt";
713 m_rollback = createRollbackManager(rollback_path, this);
715 // Create world if it doesn't exist
716 if(!initializeWorld(m_path_world, m_gamespec.id))
717 throw ServerError("Failed to initialize world");
719 ModConfiguration modconf(m_path_world);
720 m_mods = modconf.getMods();
721 std::vector<ModSpec> unsatisfied_mods = modconf.getUnsatisfiedMods();
722 // complain about mods with unsatisfied dependencies
723 if(!modconf.isConsistent())
725 for(std::vector<ModSpec>::iterator it = unsatisfied_mods.begin();
726 it != unsatisfied_mods.end(); ++it)
729 errorstream << "mod \"" << mod.name << "\" has unsatisfied dependencies: ";
730 for(std::set<std::string>::iterator dep_it = mod.unsatisfied_depends.begin();
731 dep_it != mod.unsatisfied_depends.end(); ++dep_it)
732 errorstream << " \"" << *dep_it << "\"";
733 errorstream << std::endl;
737 Settings worldmt_settings;
738 std::string worldmt = m_path_world + DIR_DELIM + "world.mt";
739 worldmt_settings.readConfigFile(worldmt.c_str());
740 std::vector<std::string> names = worldmt_settings.getNames();
741 std::set<std::string> load_mod_names;
742 for(std::vector<std::string>::iterator it = names.begin();
743 it != names.end(); ++it)
745 std::string name = *it;
746 if(name.compare(0,9,"load_mod_")==0 && worldmt_settings.getBool(name))
747 load_mod_names.insert(name.substr(9));
749 // complain about mods declared to be loaded, but not found
750 for(std::vector<ModSpec>::iterator it = m_mods.begin();
751 it != m_mods.end(); ++it)
752 load_mod_names.erase((*it).name);
753 for(std::vector<ModSpec>::iterator it = unsatisfied_mods.begin();
754 it != unsatisfied_mods.end(); ++it)
755 load_mod_names.erase((*it).name);
756 if(!load_mod_names.empty())
758 errorstream << "The following mods could not be found:";
759 for(std::set<std::string>::iterator it = load_mod_names.begin();
760 it != load_mod_names.end(); ++it)
761 errorstream << " \"" << (*it) << "\"";
762 errorstream << std::endl;
765 // Path to builtin.lua
766 std::string builtinpath = getBuiltinLuaPath() + DIR_DELIM + "builtin.lua";
769 JMutexAutoLock envlock(m_env_mutex);
770 JMutexAutoLock conlock(m_con_mutex);
772 // Initialize scripting
774 infostream<<"Server: Initializing Lua"<<std::endl;
776 m_script = new ScriptApi(this);
779 // Load and run builtin.lua
780 infostream<<"Server: Loading builtin.lua [\""
781 <<builtinpath<<"\"]"<<std::endl;
782 bool success = m_script->loadMod(builtinpath, "__builtin");
784 errorstream<<"Server: Failed to load and run "
785 <<builtinpath<<std::endl;
786 throw ModError("Failed to load and run "+builtinpath);
789 infostream<<"Server: Loading mods: ";
790 for(std::vector<ModSpec>::iterator i = m_mods.begin();
791 i != m_mods.end(); i++){
792 const ModSpec &mod = *i;
793 infostream<<mod.name<<" ";
795 infostream<<std::endl;
796 // Load and run "mod" scripts
797 for(std::vector<ModSpec>::iterator i = m_mods.begin();
798 i != m_mods.end(); i++){
799 const ModSpec &mod = *i;
800 std::string scriptpath = mod.path + DIR_DELIM + "init.lua";
801 infostream<<" ["<<padStringRight(mod.name, 12)<<"] [\""
802 <<scriptpath<<"\"]"<<std::endl;
803 bool success = m_script->loadMod(scriptpath, mod.name);
805 errorstream<<"Server: Failed to load and run "
806 <<scriptpath<<std::endl;
807 throw ModError("Failed to load and run "+scriptpath);
811 // Read Textures and calculate sha1 sums
814 // Apply item aliases in the node definition manager
815 m_nodedef->updateAliases(m_itemdef);
817 // Initialize Environment
818 ServerMap *servermap = new ServerMap(path_world, this, m_emerge);
819 m_env = new ServerEnvironment(servermap, m_script, this, this);
821 // Run some callbacks after the MG params have been set up but before activation
822 MapgenParams *mgparams = servermap->getMapgenParams();
823 m_script->environment_OnMapgenInit(mgparams);
825 // Initialize mapgens
826 m_emerge->initMapgens(mgparams);
828 // Give environment reference to scripting api
829 m_script->initializeEnvironment(m_env);
831 // Register us to receive map edit events
832 servermap->addEventReceiver(this);
834 // If file exists, load environment metadata
835 if(fs::PathExists(m_path_world+DIR_DELIM+"env_meta.txt"))
837 infostream<<"Server: Loading environment metadata"<<std::endl;
838 m_env->loadMeta(m_path_world);
842 infostream<<"Server: Loading players"<<std::endl;
843 m_env->deSerializePlayers(m_path_world);
846 Add some test ActiveBlockModifiers to environment
848 add_legacy_abms(m_env, m_nodedef);
850 m_liquid_transform_every = g_settings->getFloat("liquid_update");
855 infostream<<"Server destructing"<<std::endl;
858 Send shutdown message
861 JMutexAutoLock conlock(m_con_mutex);
863 std::wstring line = L"*** Server shutting down";
866 Send the message to clients
868 for(std::map<u16, RemoteClient*>::iterator
869 i = m_clients.begin();
870 i != m_clients.end(); ++i)
872 // Get client and check that it is valid
873 RemoteClient *client = i->second;
874 assert(client->peer_id == i->first);
875 if(client->serialization_version == SER_FMT_VER_INVALID)
879 SendChatMessage(client->peer_id, line);
881 catch(con::PeerNotFoundException &e)
887 JMutexAutoLock envlock(m_env_mutex);
888 JMutexAutoLock conlock(m_con_mutex);
891 Execute script shutdown hooks
893 m_script->on_shutdown();
897 JMutexAutoLock envlock(m_env_mutex);
902 infostream<<"Server: Saving players"<<std::endl;
903 m_env->serializePlayers(m_path_world);
906 Save environment metadata
908 infostream<<"Server: Saving environment metadata"<<std::endl;
909 m_env->saveMeta(m_path_world);
917 //shutdown all emerge threads first!
924 JMutexAutoLock clientslock(m_con_mutex);
926 for(std::map<u16, RemoteClient*>::iterator
927 i = m_clients.begin();
928 i != m_clients.end(); ++i)
936 // Delete things in the reverse order of creation
944 // Deinitialize scripting
945 infostream<<"Server: Deinitializing scripting"<<std::endl;
948 // Delete detached inventories
950 for(std::map<std::string, Inventory*>::iterator
951 i = m_detached_inventories.begin();
952 i != m_detached_inventories.end(); i++){
958 void Server::start(unsigned short port)
960 DSTACK(__FUNCTION_NAME);
961 infostream<<"Starting server on port "<<port<<"..."<<std::endl;
963 // Stop thread if already running
966 // Initialize connection
967 m_con.SetTimeoutMs(30);
971 m_thread.setRun(true);
974 // ASCII art for the win!
976 <<" .__ __ __ "<<std::endl
977 <<" _____ |__| ____ _____/ |_ ____ _______/ |_ "<<std::endl
978 <<" / \\| |/ \\_/ __ \\ __\\/ __ \\ / ___/\\ __\\"<<std::endl
979 <<"| Y Y \\ | | \\ ___/| | \\ ___/ \\___ \\ | | "<<std::endl
980 <<"|__|_| /__|___| /\\___ >__| \\___ >____ > |__| "<<std::endl
981 <<" \\/ \\/ \\/ \\/ \\/ "<<std::endl;
982 actionstream<<"World at ["<<m_path_world<<"]"<<std::endl;
983 actionstream<<"Server for gameid=\""<<m_gamespec.id
984 <<"\" listening on port "<<port<<"."<<std::endl;
989 DSTACK(__FUNCTION_NAME);
991 infostream<<"Server: Stopping and waiting threads"<<std::endl;
993 // Stop threads (set run=false first so both start stopping)
994 m_thread.setRun(false);
995 //m_emergethread.setRun(false);
997 //m_emergethread.stop();
999 infostream<<"Server: Threads stopped"<<std::endl;
1002 void Server::step(float dtime)
1004 DSTACK(__FUNCTION_NAME);
1009 JMutexAutoLock lock(m_step_dtime_mutex);
1010 m_step_dtime += dtime;
1012 // Throw if fatal error occurred in thread
1013 std::string async_err = m_async_fatal_error.get();
1014 if(async_err != ""){
1015 throw ServerError(async_err);
1019 void Server::AsyncRunStep()
1021 DSTACK(__FUNCTION_NAME);
1023 g_profiler->add("Server::AsyncRunStep (num)", 1);
1027 JMutexAutoLock lock1(m_step_dtime_mutex);
1028 dtime = m_step_dtime;
1032 // Send blocks to clients
1039 g_profiler->add("Server::AsyncRunStep with dtime (num)", 1);
1041 //infostream<<"Server steps "<<dtime<<std::endl;
1042 //infostream<<"Server::AsyncRunStep(): dtime="<<dtime<<std::endl;
1045 JMutexAutoLock lock1(m_step_dtime_mutex);
1046 m_step_dtime -= dtime;
1053 m_uptime.set(m_uptime.get() + dtime);
1057 // Process connection's timeouts
1058 JMutexAutoLock lock2(m_con_mutex);
1059 ScopeProfiler sp(g_profiler, "Server: connection timeout processing");
1060 m_con.RunTimeouts(dtime);
1064 // This has to be called so that the client list gets synced
1065 // with the peer list of the connection
1066 handlePeerChanges();
1070 Update time of day and overall game time
1073 JMutexAutoLock envlock(m_env_mutex);
1075 m_env->setTimeOfDaySpeed(g_settings->getFloat("time_speed"));
1078 Send to clients at constant intervals
1081 m_time_of_day_send_timer -= dtime;
1082 if(m_time_of_day_send_timer < 0.0)
1084 m_time_of_day_send_timer = g_settings->getFloat("time_send_interval");
1086 //JMutexAutoLock envlock(m_env_mutex);
1087 JMutexAutoLock conlock(m_con_mutex);
1089 for(std::map<u16, RemoteClient*>::iterator
1090 i = m_clients.begin();
1091 i != m_clients.end(); ++i)
1093 RemoteClient *client = i->second;
1094 SharedBuffer<u8> data = makePacket_TOCLIENT_TIME_OF_DAY(
1095 m_env->getTimeOfDay(), g_settings->getFloat("time_speed"));
1097 m_con.Send(client->peer_id, 0, data, true);
1103 JMutexAutoLock lock(m_env_mutex);
1104 // Figure out and report maximum lag to environment
1105 float max_lag = m_env->getMaxLagEstimate();
1106 max_lag *= 0.9998; // Decrease slowly (about half per 5 minutes)
1107 if(dtime > max_lag){
1108 if(dtime > 0.1 && dtime > max_lag * 2.0)
1109 infostream<<"Server: Maximum lag peaked to "<<dtime
1113 m_env->reportMaxLagEstimate(max_lag);
1115 ScopeProfiler sp(g_profiler, "SEnv step");
1116 ScopeProfiler sp2(g_profiler, "SEnv step avg", SPT_AVG);
1120 const float map_timer_and_unload_dtime = 2.92;
1121 if(m_map_timer_and_unload_interval.step(dtime, map_timer_and_unload_dtime))
1123 JMutexAutoLock lock(m_env_mutex);
1124 // Run Map's timers and unload unused data
1125 ScopeProfiler sp(g_profiler, "Server: map timer and unload");
1126 m_env->getMap().timerUpdate(map_timer_and_unload_dtime,
1127 g_settings->getFloat("server_unload_unused_data_timeout"));
1138 JMutexAutoLock lock(m_env_mutex);
1139 JMutexAutoLock lock2(m_con_mutex);
1141 ScopeProfiler sp(g_profiler, "Server: handle players");
1143 for(std::map<u16, RemoteClient*>::iterator
1144 i = m_clients.begin();
1145 i != m_clients.end(); ++i)
1147 RemoteClient *client = i->second;
1148 PlayerSAO *playersao = getPlayerSAO(client->peer_id);
1149 if(playersao == NULL)
1153 Handle player HPs (die if hp=0)
1155 if(playersao->m_hp_not_sent && g_settings->getBool("enable_damage"))
1157 if(playersao->getHP() == 0)
1158 DiePlayer(client->peer_id);
1160 SendPlayerHP(client->peer_id);
1164 Send player breath if changed
1166 if(playersao->m_breath_not_sent){
1167 SendPlayerBreath(client->peer_id);
1171 Send player inventories if necessary
1173 if(playersao->m_moved){
1174 SendMovePlayer(client->peer_id);
1175 playersao->m_moved = false;
1177 if(playersao->m_inventory_not_sent){
1178 UpdateCrafting(client->peer_id);
1179 SendInventory(client->peer_id);
1184 /* Transform liquids */
1185 m_liquid_transform_timer += dtime;
1186 if(m_liquid_transform_timer >= m_liquid_transform_every)
1188 m_liquid_transform_timer -= m_liquid_transform_every;
1190 JMutexAutoLock lock(m_env_mutex);
1192 ScopeProfiler sp(g_profiler, "Server: liquid transform");
1194 std::map<v3s16, MapBlock*> modified_blocks;
1195 m_env->getMap().transformLiquids(modified_blocks);
1200 core::map<v3s16, MapBlock*> lighting_modified_blocks;
1201 ServerMap &map = ((ServerMap&)m_env->getMap());
1202 map.updateLighting(modified_blocks, lighting_modified_blocks);
1204 // Add blocks modified by lighting to modified_blocks
1205 for(core::map<v3s16, MapBlock*>::Iterator
1206 i = lighting_modified_blocks.getIterator();
1207 i.atEnd() == false; i++)
1209 MapBlock *block = i.getNode()->getValue();
1210 modified_blocks.insert(block->getPos(), block);
1214 Set the modified blocks unsent for all the clients
1217 JMutexAutoLock lock2(m_con_mutex);
1219 for(std::map<u16, RemoteClient*>::iterator
1220 i = m_clients.begin();
1221 i != m_clients.end(); ++i)
1223 RemoteClient *client = i->second;
1225 if(modified_blocks.size() > 0)
1227 // Remove block from sent history
1228 client->SetBlocksNotSent(modified_blocks);
1233 // Periodically print some info
1235 float &counter = m_print_info_timer;
1241 JMutexAutoLock lock2(m_con_mutex);
1242 m_clients_number = 0;
1243 if(m_clients.size() != 0)
1244 infostream<<"Players:"<<std::endl;
1245 for(std::map<u16, RemoteClient*>::iterator
1246 i = m_clients.begin();
1247 i != m_clients.end(); ++i)
1249 //u16 peer_id = i.getNode()->getKey();
1250 RemoteClient *client = i->second;
1251 Player *player = m_env->getPlayer(client->peer_id);
1254 infostream<<"* "<<player->getName()<<"\t";
1255 client->PrintInfo(infostream);
1263 // send masterserver announce
1265 float &counter = m_masterserver_timer;
1266 if(!isSingleplayer() && (!counter || counter >= 300.0) && g_settings->getBool("server_announce") == true)
1268 ServerList::sendAnnounce(!counter ? "start" : "update", m_clients_number, m_uptime.get(), m_gamespec.id, m_mods);
1275 //if(g_settings->getBool("enable_experimental"))
1279 Check added and deleted active objects
1282 //infostream<<"Server: Checking added and deleted active objects"<<std::endl;
1283 JMutexAutoLock envlock(m_env_mutex);
1284 JMutexAutoLock conlock(m_con_mutex);
1286 ScopeProfiler sp(g_profiler, "Server: checking added and deleted objs");
1288 // Radius inside which objects are active
1289 s16 radius = g_settings->getS16("active_object_send_range_blocks");
1290 radius *= MAP_BLOCKSIZE;
1292 for(std::map<u16, RemoteClient*>::iterator
1293 i = m_clients.begin();
1294 i != m_clients.end(); ++i)
1296 RemoteClient *client = i->second;
1298 // If definitions and textures have not been sent, don't
1299 // send objects either
1300 if(!client->definitions_sent)
1303 Player *player = m_env->getPlayer(client->peer_id);
1306 // This can happen if the client timeouts somehow
1307 /*infostream<<"WARNING: "<<__FUNCTION_NAME<<": Client "
1309 <<" has no associated player"<<std::endl;*/
1312 v3s16 pos = floatToInt(player->getPosition(), BS);
1314 std::set<u16> removed_objects;
1315 std::set<u16> added_objects;
1316 m_env->getRemovedActiveObjects(pos, radius,
1317 client->m_known_objects, removed_objects);
1318 m_env->getAddedActiveObjects(pos, radius,
1319 client->m_known_objects, added_objects);
1321 // Ignore if nothing happened
1322 if(removed_objects.size() == 0 && added_objects.size() == 0)
1324 //infostream<<"active objects: none changed"<<std::endl;
1328 std::string data_buffer;
1332 // Handle removed objects
1333 writeU16((u8*)buf, removed_objects.size());
1334 data_buffer.append(buf, 2);
1335 for(std::set<u16>::iterator
1336 i = removed_objects.begin();
1337 i != removed_objects.end(); ++i)
1341 ServerActiveObject* obj = m_env->getActiveObject(id);
1343 // Add to data buffer for sending
1344 writeU16((u8*)buf, id);
1345 data_buffer.append(buf, 2);
1347 // Remove from known objects
1348 client->m_known_objects.erase(id);
1350 if(obj && obj->m_known_by_count > 0)
1351 obj->m_known_by_count--;
1354 // Handle added objects
1355 writeU16((u8*)buf, added_objects.size());
1356 data_buffer.append(buf, 2);
1357 for(std::set<u16>::iterator
1358 i = added_objects.begin();
1359 i != added_objects.end(); ++i)
1363 ServerActiveObject* obj = m_env->getActiveObject(id);
1366 u8 type = ACTIVEOBJECT_TYPE_INVALID;
1368 infostream<<"WARNING: "<<__FUNCTION_NAME
1369 <<": NULL object"<<std::endl;
1371 type = obj->getSendType();
1373 // Add to data buffer for sending
1374 writeU16((u8*)buf, id);
1375 data_buffer.append(buf, 2);
1376 writeU8((u8*)buf, type);
1377 data_buffer.append(buf, 1);
1380 data_buffer.append(serializeLongString(
1381 obj->getClientInitializationData(client->net_proto_version)));
1383 data_buffer.append(serializeLongString(""));
1385 // Add to known objects
1386 client->m_known_objects.insert(id);
1389 obj->m_known_by_count++;
1393 SharedBuffer<u8> reply(2 + data_buffer.size());
1394 writeU16(&reply[0], TOCLIENT_ACTIVE_OBJECT_REMOVE_ADD);
1395 memcpy((char*)&reply[2], data_buffer.c_str(),
1396 data_buffer.size());
1398 m_con.Send(client->peer_id, 0, reply, true);
1400 verbosestream<<"Server: Sent object remove/add: "
1401 <<removed_objects.size()<<" removed, "
1402 <<added_objects.size()<<" added, "
1403 <<"packet size is "<<reply.getSize()<<std::endl;
1408 Collect a list of all the objects known by the clients
1409 and report it back to the environment.
1412 core::map<u16, bool> all_known_objects;
1414 for(core::map<u16, RemoteClient*>::Iterator
1415 i = m_clients.getIterator();
1416 i.atEnd() == false; i++)
1418 RemoteClient *client = i.getNode()->getValue();
1419 // Go through all known objects of client
1420 for(core::map<u16, bool>::Iterator
1421 i = client->m_known_objects.getIterator();
1422 i.atEnd()==false; i++)
1424 u16 id = i.getNode()->getKey();
1425 all_known_objects[id] = true;
1429 m_env->setKnownActiveObjects(whatever);
1435 Send object messages
1438 JMutexAutoLock envlock(m_env_mutex);
1439 JMutexAutoLock conlock(m_con_mutex);
1441 ScopeProfiler sp(g_profiler, "Server: sending object messages");
1444 // Value = data sent by object
1445 std::map<u16, std::list<ActiveObjectMessage>* > buffered_messages;
1447 // Get active object messages from environment
1450 ActiveObjectMessage aom = m_env->getActiveObjectMessage();
1454 std::list<ActiveObjectMessage>* message_list = NULL;
1455 std::map<u16, std::list<ActiveObjectMessage>* >::iterator n;
1456 n = buffered_messages.find(aom.id);
1457 if(n == buffered_messages.end())
1459 message_list = new std::list<ActiveObjectMessage>;
1460 buffered_messages[aom.id] = message_list;
1464 message_list = n->second;
1466 message_list->push_back(aom);
1469 // Route data to every client
1470 for(std::map<u16, RemoteClient*>::iterator
1471 i = m_clients.begin();
1472 i != m_clients.end(); ++i)
1474 RemoteClient *client = i->second;
1475 std::string reliable_data;
1476 std::string unreliable_data;
1477 // Go through all objects in message buffer
1478 for(std::map<u16, std::list<ActiveObjectMessage>* >::iterator
1479 j = buffered_messages.begin();
1480 j != buffered_messages.end(); ++j)
1482 // If object is not known by client, skip it
1484 if(client->m_known_objects.find(id) == client->m_known_objects.end())
1486 // Get message list of object
1487 std::list<ActiveObjectMessage>* list = j->second;
1488 // Go through every message
1489 for(std::list<ActiveObjectMessage>::iterator
1490 k = list->begin(); k != list->end(); ++k)
1492 // Compose the full new data with header
1493 ActiveObjectMessage aom = *k;
1494 std::string new_data;
1497 writeU16((u8*)&buf[0], aom.id);
1498 new_data.append(buf, 2);
1500 new_data += serializeString(aom.datastring);
1501 // Add data to buffer
1503 reliable_data += new_data;
1505 unreliable_data += new_data;
1509 reliable_data and unreliable_data are now ready.
1512 if(reliable_data.size() > 0)
1514 SharedBuffer<u8> reply(2 + reliable_data.size());
1515 writeU16(&reply[0], TOCLIENT_ACTIVE_OBJECT_MESSAGES);
1516 memcpy((char*)&reply[2], reliable_data.c_str(),
1517 reliable_data.size());
1519 m_con.Send(client->peer_id, 0, reply, true);
1521 if(unreliable_data.size() > 0)
1523 SharedBuffer<u8> reply(2 + unreliable_data.size());
1524 writeU16(&reply[0], TOCLIENT_ACTIVE_OBJECT_MESSAGES);
1525 memcpy((char*)&reply[2], unreliable_data.c_str(),
1526 unreliable_data.size());
1527 // Send as unreliable
1528 m_con.Send(client->peer_id, 0, reply, false);
1531 /*if(reliable_data.size() > 0 || unreliable_data.size() > 0)
1533 infostream<<"Server: Size of object message data: "
1534 <<"reliable: "<<reliable_data.size()
1535 <<", unreliable: "<<unreliable_data.size()
1540 // Clear buffered_messages
1541 for(std::map<u16, std::list<ActiveObjectMessage>* >::iterator
1542 i = buffered_messages.begin();
1543 i != buffered_messages.end(); ++i)
1549 } // enable_experimental
1552 Send queued-for-sending map edit events.
1555 // We will be accessing the environment and the connection
1556 JMutexAutoLock lock(m_env_mutex);
1557 JMutexAutoLock conlock(m_con_mutex);
1559 // Don't send too many at a time
1562 // Single change sending is disabled if queue size is not small
1563 bool disable_single_change_sending = false;
1564 if(m_unsent_map_edit_queue.size() >= 4)
1565 disable_single_change_sending = true;
1567 int event_count = m_unsent_map_edit_queue.size();
1569 // We'll log the amount of each
1572 while(m_unsent_map_edit_queue.size() != 0)
1574 MapEditEvent* event = m_unsent_map_edit_queue.pop_front();
1576 // Players far away from the change are stored here.
1577 // Instead of sending the changes, MapBlocks are set not sent
1579 std::list<u16> far_players;
1581 if(event->type == MEET_ADDNODE)
1583 //infostream<<"Server: MEET_ADDNODE"<<std::endl;
1584 prof.add("MEET_ADDNODE", 1);
1585 if(disable_single_change_sending)
1586 sendAddNode(event->p, event->n, event->already_known_by_peer,
1589 sendAddNode(event->p, event->n, event->already_known_by_peer,
1592 else if(event->type == MEET_REMOVENODE)
1594 //infostream<<"Server: MEET_REMOVENODE"<<std::endl;
1595 prof.add("MEET_REMOVENODE", 1);
1596 if(disable_single_change_sending)
1597 sendRemoveNode(event->p, event->already_known_by_peer,
1600 sendRemoveNode(event->p, event->already_known_by_peer,
1603 else if(event->type == MEET_BLOCK_NODE_METADATA_CHANGED)
1605 infostream<<"Server: MEET_BLOCK_NODE_METADATA_CHANGED"<<std::endl;
1606 prof.add("MEET_BLOCK_NODE_METADATA_CHANGED", 1);
1607 setBlockNotSent(event->p);
1609 else if(event->type == MEET_OTHER)
1611 infostream<<"Server: MEET_OTHER"<<std::endl;
1612 prof.add("MEET_OTHER", 1);
1613 for(std::set<v3s16>::iterator
1614 i = event->modified_blocks.begin();
1615 i != event->modified_blocks.end(); ++i)
1617 setBlockNotSent(*i);
1622 prof.add("unknown", 1);
1623 infostream<<"WARNING: Server: Unknown MapEditEvent "
1624 <<((u32)event->type)<<std::endl;
1628 Set blocks not sent to far players
1630 if(far_players.size() > 0)
1632 // Convert list format to that wanted by SetBlocksNotSent
1633 std::map<v3s16, MapBlock*> modified_blocks2;
1634 for(std::set<v3s16>::iterator
1635 i = event->modified_blocks.begin();
1636 i != event->modified_blocks.end(); ++i)
1638 modified_blocks2[*i] =
1639 m_env->getMap().getBlockNoCreateNoEx(*i);
1641 // Set blocks not sent
1642 for(std::list<u16>::iterator
1643 i = far_players.begin();
1644 i != far_players.end(); ++i)
1647 RemoteClient *client = getClient(peer_id);
1650 client->SetBlocksNotSent(modified_blocks2);
1656 /*// Don't send too many at a time
1658 if(count >= 1 && m_unsent_map_edit_queue.size() < 100)
1662 if(event_count >= 5){
1663 infostream<<"Server: MapEditEvents:"<<std::endl;
1664 prof.print(infostream);
1665 } else if(event_count != 0){
1666 verbosestream<<"Server: MapEditEvents:"<<std::endl;
1667 prof.print(verbosestream);
1673 Trigger emergethread (it somehow gets to a non-triggered but
1674 bysy state sometimes)
1677 float &counter = m_emergethread_trigger_timer;
1683 for (unsigned int i = 0; i != m_emerge->emergethread.size(); i++)
1684 m_emerge->emergethread[i]->trigger();
1686 // Update m_enable_rollback_recording here too
1687 m_enable_rollback_recording =
1688 g_settings->getBool("enable_rollback_recording");
1692 // Save map, players and auth stuff
1694 float &counter = m_savemap_timer;
1696 if(counter >= g_settings->getFloat("server_map_save_interval"))
1699 JMutexAutoLock lock(m_env_mutex);
1701 ScopeProfiler sp(g_profiler, "Server: saving stuff");
1704 if(m_banmanager.isModified())
1705 m_banmanager.save();
1707 // Save changed parts of map
1708 m_env->getMap().save(MOD_STATE_WRITE_NEEDED);
1711 m_env->serializePlayers(m_path_world);
1713 // Save environment metadata
1714 m_env->saveMeta(m_path_world);
1719 void Server::Receive()
1721 DSTACK(__FUNCTION_NAME);
1722 SharedBuffer<u8> data;
1727 JMutexAutoLock conlock(m_con_mutex);
1728 datasize = m_con.Receive(peer_id, data);
1731 // This has to be called so that the client list gets synced
1732 // with the peer list of the connection
1733 handlePeerChanges();
1735 ProcessData(*data, datasize, peer_id);
1737 catch(con::InvalidIncomingDataException &e)
1739 infostream<<"Server::Receive(): "
1740 "InvalidIncomingDataException: what()="
1741 <<e.what()<<std::endl;
1743 catch(con::PeerNotFoundException &e)
1745 //NOTE: This is not needed anymore
1747 // The peer has been disconnected.
1748 // Find the associated player and remove it.
1750 /*JMutexAutoLock envlock(m_env_mutex);
1752 infostream<<"ServerThread: peer_id="<<peer_id
1753 <<" has apparently closed connection. "
1754 <<"Removing player."<<std::endl;
1756 m_env->removePlayer(peer_id);*/
1760 void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
1762 DSTACK(__FUNCTION_NAME);
1763 // Environment is locked first.
1764 JMutexAutoLock envlock(m_env_mutex);
1765 JMutexAutoLock conlock(m_con_mutex);
1767 ScopeProfiler sp(g_profiler, "Server::ProcessData");
1771 Address address = m_con.GetPeerAddress(peer_id);
1772 addr_s = address.serializeString();
1774 // drop player if is ip is banned
1775 if(m_banmanager.isIpBanned(addr_s)){
1776 infostream<<"Server: A banned client tried to connect from "
1777 <<addr_s<<"; banned name was "
1778 <<m_banmanager.getBanName(addr_s)<<std::endl;
1779 // This actually doesn't seem to transfer to the client
1780 DenyAccess(peer_id, L"Your ip is banned. Banned name was "
1781 +narrow_to_wide(m_banmanager.getBanName(addr_s)));
1782 m_con.DeletePeer(peer_id);
1786 catch(con::PeerNotFoundException &e)
1788 infostream<<"Server::ProcessData(): Cancelling: peer "
1789 <<peer_id<<" not found"<<std::endl;
1793 u8 peer_ser_ver = getClient(peer_id)->serialization_version;
1801 ToServerCommand command = (ToServerCommand)readU16(&data[0]);
1803 if(command == TOSERVER_INIT)
1805 // [0] u16 TOSERVER_INIT
1806 // [2] u8 SER_FMT_VER_HIGHEST_READ
1807 // [3] u8[20] player_name
1808 // [23] u8[28] password <--- can be sent without this, from old versions
1810 if(datasize < 2+1+PLAYERNAME_SIZE)
1813 verbosestream<<"Server: Got TOSERVER_INIT from "<<addr_s<<std::endl;
1815 // Do not allow multiple players in simple singleplayer mode.
1816 // This isn't a perfect way to do it, but will suffice for now.
1817 if(m_simple_singleplayer_mode && m_clients.size() > 1){
1818 infostream<<"Server: Not allowing another client ("<<addr_s
1819 <<") to connect in simple singleplayer mode"<<std::endl;
1820 DenyAccess(peer_id, L"Running in simple singleplayer mode.");
1824 // First byte after command is maximum supported
1825 // serialization version
1826 u8 client_max = data[2];
1827 u8 our_max = SER_FMT_VER_HIGHEST_READ;
1828 // Use the highest version supported by both
1829 u8 deployed = std::min(client_max, our_max);
1830 // If it's lower than the lowest supported, give up.
1831 if(deployed < SER_FMT_VER_LOWEST)
1832 deployed = SER_FMT_VER_INVALID;
1834 //peer->serialization_version = deployed;
1835 getClient(peer_id)->pending_serialization_version = deployed;
1837 if(deployed == SER_FMT_VER_INVALID)
1839 actionstream<<"Server: A mismatched client tried to connect from "
1840 <<addr_s<<std::endl;
1841 infostream<<"Server: Cannot negotiate serialization version with "
1842 <<addr_s<<std::endl;
1843 DenyAccess(peer_id, std::wstring(
1844 L"Your client's version is not supported.\n"
1845 L"Server version is ")
1846 + narrow_to_wide(VERSION_STRING) + L"."
1852 Read and check network protocol version
1855 u16 min_net_proto_version = 0;
1856 if(datasize >= 2+1+PLAYERNAME_SIZE+PASSWORD_SIZE+2)
1857 min_net_proto_version = readU16(&data[2+1+PLAYERNAME_SIZE+PASSWORD_SIZE]);
1859 // Use same version as minimum and maximum if maximum version field
1860 // doesn't exist (backwards compatibility)
1861 u16 max_net_proto_version = min_net_proto_version;
1862 if(datasize >= 2+1+PLAYERNAME_SIZE+PASSWORD_SIZE+2+2)
1863 max_net_proto_version = readU16(&data[2+1+PLAYERNAME_SIZE+PASSWORD_SIZE+2]);
1865 // Start with client's maximum version
1866 u16 net_proto_version = max_net_proto_version;
1868 // Figure out a working version if it is possible at all
1869 if(max_net_proto_version >= SERVER_PROTOCOL_VERSION_MIN ||
1870 min_net_proto_version <= SERVER_PROTOCOL_VERSION_MAX)
1872 // If maximum is larger than our maximum, go with our maximum
1873 if(max_net_proto_version > SERVER_PROTOCOL_VERSION_MAX)
1874 net_proto_version = SERVER_PROTOCOL_VERSION_MAX;
1875 // Else go with client's maximum
1877 net_proto_version = max_net_proto_version;
1880 verbosestream<<"Server: "<<addr_s<<": Protocol version: min: "
1881 <<min_net_proto_version<<", max: "<<max_net_proto_version
1882 <<", chosen: "<<net_proto_version<<std::endl;
1884 getClient(peer_id)->net_proto_version = net_proto_version;
1886 if(net_proto_version < SERVER_PROTOCOL_VERSION_MIN ||
1887 net_proto_version > SERVER_PROTOCOL_VERSION_MAX)
1889 actionstream<<"Server: A mismatched client tried to connect from "
1890 <<addr_s<<std::endl;
1891 DenyAccess(peer_id, std::wstring(
1892 L"Your client's version is not supported.\n"
1893 L"Server version is ")
1894 + narrow_to_wide(VERSION_STRING) + L",\n"
1895 + L"server's PROTOCOL_VERSION is "
1896 + narrow_to_wide(itos(SERVER_PROTOCOL_VERSION_MIN))
1898 + narrow_to_wide(itos(SERVER_PROTOCOL_VERSION_MAX))
1899 + L", client's PROTOCOL_VERSION is "
1900 + narrow_to_wide(itos(min_net_proto_version))
1902 + narrow_to_wide(itos(max_net_proto_version))
1907 if(g_settings->getBool("strict_protocol_version_checking"))
1909 if(net_proto_version != LATEST_PROTOCOL_VERSION)
1911 actionstream<<"Server: A mismatched (strict) client tried to "
1912 <<"connect from "<<addr_s<<std::endl;
1913 DenyAccess(peer_id, std::wstring(
1914 L"Your client's version is not supported.\n"
1915 L"Server version is ")
1916 + narrow_to_wide(VERSION_STRING) + L",\n"
1917 + L"server's PROTOCOL_VERSION (strict) is "
1918 + narrow_to_wide(itos(LATEST_PROTOCOL_VERSION))
1919 + L", client's PROTOCOL_VERSION is "
1920 + narrow_to_wide(itos(min_net_proto_version))
1922 + narrow_to_wide(itos(max_net_proto_version))
1933 char playername[PLAYERNAME_SIZE];
1934 for(u32 i=0; i<PLAYERNAME_SIZE-1; i++)
1936 playername[i] = data[3+i];
1938 playername[PLAYERNAME_SIZE-1] = 0;
1940 if(playername[0]=='\0')
1942 actionstream<<"Server: Player with an empty name "
1943 <<"tried to connect from "<<addr_s<<std::endl;
1944 DenyAccess(peer_id, L"Empty name");
1948 if(string_allowed(playername, PLAYERNAME_ALLOWED_CHARS)==false)
1950 actionstream<<"Server: Player with an invalid name "
1951 <<"tried to connect from "<<addr_s<<std::endl;
1952 DenyAccess(peer_id, L"Name contains unallowed characters");
1956 if(!isSingleplayer() && strcasecmp(playername, "singleplayer") == 0)
1958 actionstream<<"Server: Player with the name \"singleplayer\" "
1959 <<"tried to connect from "<<addr_s<<std::endl;
1960 DenyAccess(peer_id, L"Name is not allowed");
1964 infostream<<"Server: New connection: \""<<playername<<"\" from "
1965 <<addr_s<<" (peer_id="<<peer_id<<")"<<std::endl;
1968 char given_password[PASSWORD_SIZE];
1969 if(datasize < 2+1+PLAYERNAME_SIZE+PASSWORD_SIZE)
1971 // old version - assume blank password
1972 given_password[0] = 0;
1976 for(u32 i=0; i<PASSWORD_SIZE-1; i++)
1978 given_password[i] = data[23+i];
1980 given_password[PASSWORD_SIZE-1] = 0;
1983 if(!base64_is_valid(given_password)){
1984 actionstream<<"Server: "<<playername
1985 <<" supplied invalid password hash"<<std::endl;
1986 DenyAccess(peer_id, L"Invalid password hash");
1990 // Enforce user limit.
1991 // Don't enforce for users that have some admin right
1992 if(m_clients.size() >= g_settings->getU16("max_users") &&
1993 !checkPriv(playername, "server") &&
1994 !checkPriv(playername, "ban") &&
1995 !checkPriv(playername, "privs") &&
1996 !checkPriv(playername, "password") &&
1997 playername != g_settings->get("name"))
1999 actionstream<<"Server: "<<playername<<" tried to join, but there"
2000 <<" are already max_users="
2001 <<g_settings->getU16("max_users")<<" players."<<std::endl;
2002 DenyAccess(peer_id, L"Too many users.");
2006 std::string checkpwd; // Password hash to check against
2007 bool has_auth = m_script->getAuth(playername, &checkpwd, NULL);
2009 // If no authentication info exists for user, create it
2011 if(!isSingleplayer() &&
2012 g_settings->getBool("disallow_empty_password") &&
2013 std::string(given_password) == ""){
2014 actionstream<<"Server: "<<playername
2015 <<" supplied empty password"<<std::endl;
2016 DenyAccess(peer_id, L"Empty passwords are "
2017 L"disallowed. Set a password and try again.");
2020 std::wstring raw_default_password =
2021 narrow_to_wide(g_settings->get("default_password"));
2022 std::string initial_password =
2023 translatePassword(playername, raw_default_password);
2025 // If default_password is empty, allow any initial password
2026 if (raw_default_password.length() == 0)
2027 initial_password = given_password;
2029 m_script->createAuth(playername, initial_password);
2032 has_auth = m_script->getAuth(playername, &checkpwd, NULL);
2035 actionstream<<"Server: "<<playername<<" cannot be authenticated"
2036 <<" (auth handler does not work?)"<<std::endl;
2037 DenyAccess(peer_id, L"Not allowed to login");
2041 if(given_password != checkpwd){
2042 actionstream<<"Server: "<<playername<<" supplied wrong password"
2044 DenyAccess(peer_id, L"Wrong password");
2049 PlayerSAO *playersao = emergePlayer(playername, peer_id);
2051 // If failed, cancel
2052 if(playersao == NULL)
2054 RemotePlayer *player =
2055 static_cast<RemotePlayer*>(m_env->getPlayer(playername));
2056 if(player && player->peer_id != 0){
2057 errorstream<<"Server: "<<playername<<": Failed to emerge player"
2058 <<" (player allocated to an another client)"<<std::endl;
2059 DenyAccess(peer_id, L"Another client is connected with this "
2060 L"name. If your client closed unexpectedly, try again in "
2063 errorstream<<"Server: "<<playername<<": Failed to emerge player"
2065 DenyAccess(peer_id, L"Could not allocate player.");
2071 Answer with a TOCLIENT_INIT
2074 SharedBuffer<u8> reply(2+1+6+8+4);
2075 writeU16(&reply[0], TOCLIENT_INIT);
2076 writeU8(&reply[2], deployed);
2077 writeV3S16(&reply[2+1], floatToInt(playersao->getPlayer()->getPosition()+v3f(0,BS/2,0), BS));
2078 writeU64(&reply[2+1+6], m_env->getServerMap().getSeed());
2079 writeF1000(&reply[2+1+6+8], g_settings->getFloat("dedicated_server_step"));
2082 m_con.Send(peer_id, 0, reply, true);
2086 Send complete position information
2088 SendMovePlayer(peer_id);
2093 if(command == TOSERVER_INIT2)
2095 verbosestream<<"Server: Got TOSERVER_INIT2 from "
2096 <<peer_id<<std::endl;
2098 Player *player = m_env->getPlayer(peer_id);
2100 verbosestream<<"Server: TOSERVER_INIT2: "
2101 <<"Player not found; ignoring."<<std::endl;
2105 RemoteClient *client = getClient(peer_id);
2106 client->serialization_version =
2107 getClient(peer_id)->pending_serialization_version;
2110 Send some initialization data
2113 infostream<<"Server: Sending content to "
2114 <<getPlayerName(peer_id)<<std::endl;
2116 // Send player movement settings
2117 SendMovement(m_con, peer_id);
2119 // Send item definitions
2120 SendItemDef(m_con, peer_id, m_itemdef, client->net_proto_version);
2122 // Send node definitions
2123 SendNodeDef(m_con, peer_id, m_nodedef, client->net_proto_version);
2125 // Send media announcement
2126 sendMediaAnnouncement(peer_id);
2129 SendPlayerPrivileges(peer_id);
2131 // Send inventory formspec
2132 SendPlayerInventoryFormspec(peer_id);
2135 UpdateCrafting(peer_id);
2136 SendInventory(peer_id);
2139 if(g_settings->getBool("enable_damage"))
2140 SendPlayerHP(peer_id);
2143 SendPlayerBreath(peer_id);
2145 // Send detached inventories
2146 sendDetachedInventories(peer_id);
2148 // Show death screen if necessary
2150 SendDeathscreen(m_con, peer_id, false, v3f(0,0,0));
2154 SharedBuffer<u8> data = makePacket_TOCLIENT_TIME_OF_DAY(
2155 m_env->getTimeOfDay(), g_settings->getFloat("time_speed"));
2156 m_con.Send(peer_id, 0, data, true);
2159 // Note things in chat if not in simple singleplayer mode
2160 if(!m_simple_singleplayer_mode)
2162 // Send information about server to player in chat
2163 SendChatMessage(peer_id, getStatusString());
2165 // Send information about joining in chat
2167 std::wstring name = L"unknown";
2168 Player *player = m_env->getPlayer(peer_id);
2170 name = narrow_to_wide(player->getName());
2172 std::wstring message;
2175 message += L" joined the game.";
2176 BroadcastChatMessage(message);
2180 // Warnings about protocol version can be issued here
2181 if(getClient(peer_id)->net_proto_version < LATEST_PROTOCOL_VERSION)
2183 SendChatMessage(peer_id, L"# Server: WARNING: YOUR CLIENT'S "
2184 L"VERSION MAY NOT BE FULLY COMPATIBLE WITH THIS SERVER!");
2191 std::ostringstream os(std::ios_base::binary);
2192 for(std::map<u16, RemoteClient*>::iterator
2193 i = m_clients.begin();
2194 i != m_clients.end(); ++i)
2196 RemoteClient *client = i->second;
2197 assert(client->peer_id == i->first);
2198 if(client->serialization_version == SER_FMT_VER_INVALID)
2201 Player *player = m_env->getPlayer(client->peer_id);
2204 // Get name of player
2205 os<<player->getName()<<" ";
2208 actionstream<<player->getName()<<" ["<<addr_s<<"] "<<"joins game. List of players: "
2209 <<os.str()<<std::endl;
2215 if(peer_ser_ver == SER_FMT_VER_INVALID)
2217 infostream<<"Server::ProcessData(): Cancelling: Peer"
2218 " serialization format invalid or not initialized."
2219 " Skipping incoming command="<<command<<std::endl;
2223 Player *player = m_env->getPlayer(peer_id);
2225 infostream<<"Server::ProcessData(): Cancelling: "
2226 "No player for peer_id="<<peer_id
2231 PlayerSAO *playersao = player->getPlayerSAO();
2232 if(playersao == NULL){
2233 infostream<<"Server::ProcessData(): Cancelling: "
2234 "No player object for peer_id="<<peer_id
2239 if(command == TOSERVER_PLAYERPOS)
2241 if(datasize < 2+12+12+4+4)
2245 v3s32 ps = readV3S32(&data[start+2]);
2246 v3s32 ss = readV3S32(&data[start+2+12]);
2247 f32 pitch = (f32)readS32(&data[2+12+12]) / 100.0;
2248 f32 yaw = (f32)readS32(&data[2+12+12+4]) / 100.0;
2250 if(datasize >= 2+12+12+4+4+4)
2251 keyPressed = (u32)readU32(&data[2+12+12+4+4]);
2252 v3f position((f32)ps.X/100., (f32)ps.Y/100., (f32)ps.Z/100.);
2253 v3f speed((f32)ss.X/100., (f32)ss.Y/100., (f32)ss.Z/100.);
2254 pitch = wrapDegrees(pitch);
2255 yaw = wrapDegrees(yaw);
2257 player->setPosition(position);
2258 player->setSpeed(speed);
2259 player->setPitch(pitch);
2260 player->setYaw(yaw);
2261 player->keyPressed=keyPressed;
2262 player->control.up = (bool)(keyPressed&1);
2263 player->control.down = (bool)(keyPressed&2);
2264 player->control.left = (bool)(keyPressed&4);
2265 player->control.right = (bool)(keyPressed&8);
2266 player->control.jump = (bool)(keyPressed&16);
2267 player->control.aux1 = (bool)(keyPressed&32);
2268 player->control.sneak = (bool)(keyPressed&64);
2269 player->control.LMB = (bool)(keyPressed&128);
2270 player->control.RMB = (bool)(keyPressed&256);
2272 bool cheated = playersao->checkMovementCheat();
2275 m_script->on_cheat(playersao, "moved_too_fast");
2278 /*infostream<<"Server::ProcessData(): Moved player "<<peer_id<<" to "
2279 <<"("<<position.X<<","<<position.Y<<","<<position.Z<<")"
2280 <<" pitch="<<pitch<<" yaw="<<yaw<<std::endl;*/
2282 else if(command == TOSERVER_GOTBLOCKS)
2295 u16 count = data[2];
2296 for(u16 i=0; i<count; i++)
2298 if((s16)datasize < 2+1+(i+1)*6)
2299 throw con::InvalidIncomingDataException
2300 ("GOTBLOCKS length is too short");
2301 v3s16 p = readV3S16(&data[2+1+i*6]);
2302 /*infostream<<"Server: GOTBLOCKS ("
2303 <<p.X<<","<<p.Y<<","<<p.Z<<")"<<std::endl;*/
2304 RemoteClient *client = getClient(peer_id);
2305 client->GotBlock(p);
2308 else if(command == TOSERVER_DELETEDBLOCKS)
2321 u16 count = data[2];
2322 for(u16 i=0; i<count; i++)
2324 if((s16)datasize < 2+1+(i+1)*6)
2325 throw con::InvalidIncomingDataException
2326 ("DELETEDBLOCKS length is too short");
2327 v3s16 p = readV3S16(&data[2+1+i*6]);
2328 /*infostream<<"Server: DELETEDBLOCKS ("
2329 <<p.X<<","<<p.Y<<","<<p.Z<<")"<<std::endl;*/
2330 RemoteClient *client = getClient(peer_id);
2331 client->SetBlockNotSent(p);
2334 else if(command == TOSERVER_CLICK_OBJECT)
2336 infostream<<"Server: CLICK_OBJECT not supported anymore"<<std::endl;
2339 else if(command == TOSERVER_CLICK_ACTIVEOBJECT)
2341 infostream<<"Server: CLICK_ACTIVEOBJECT not supported anymore"<<std::endl;
2344 else if(command == TOSERVER_GROUND_ACTION)
2346 infostream<<"Server: GROUND_ACTION not supported anymore"<<std::endl;
2350 else if(command == TOSERVER_RELEASE)
2352 infostream<<"Server: RELEASE not supported anymore"<<std::endl;
2355 else if(command == TOSERVER_SIGNTEXT)
2357 infostream<<"Server: SIGNTEXT not supported anymore"
2361 else if(command == TOSERVER_SIGNNODETEXT)
2363 infostream<<"Server: SIGNNODETEXT not supported anymore"
2367 else if(command == TOSERVER_INVENTORY_ACTION)
2369 // Strip command and create a stream
2370 std::string datastring((char*)&data[2], datasize-2);
2371 verbosestream<<"TOSERVER_INVENTORY_ACTION: data="<<datastring<<std::endl;
2372 std::istringstream is(datastring, std::ios_base::binary);
2374 InventoryAction *a = InventoryAction::deSerialize(is);
2377 infostream<<"TOSERVER_INVENTORY_ACTION: "
2378 <<"InventoryAction::deSerialize() returned NULL"
2383 // If something goes wrong, this player is to blame
2384 RollbackScopeActor rollback_scope(m_rollback,
2385 std::string("player:")+player->getName());
2388 Note: Always set inventory not sent, to repair cases
2389 where the client made a bad prediction.
2393 Handle restrictions and special cases of the move action
2395 if(a->getType() == IACTION_MOVE)
2397 IMoveAction *ma = (IMoveAction*)a;
2399 ma->from_inv.applyCurrentPlayer(player->getName());
2400 ma->to_inv.applyCurrentPlayer(player->getName());
2402 setInventoryModified(ma->from_inv);
2403 setInventoryModified(ma->to_inv);
2405 bool from_inv_is_current_player =
2406 (ma->from_inv.type == InventoryLocation::PLAYER) &&
2407 (ma->from_inv.name == player->getName());
2409 bool to_inv_is_current_player =
2410 (ma->to_inv.type == InventoryLocation::PLAYER) &&
2411 (ma->to_inv.name == player->getName());
2414 Disable moving items out of craftpreview
2416 if(ma->from_list == "craftpreview")
2418 infostream<<"Ignoring IMoveAction from "
2419 <<(ma->from_inv.dump())<<":"<<ma->from_list
2420 <<" to "<<(ma->to_inv.dump())<<":"<<ma->to_list
2421 <<" because src is "<<ma->from_list<<std::endl;
2427 Disable moving items into craftresult and craftpreview
2429 if(ma->to_list == "craftpreview" || ma->to_list == "craftresult")
2431 infostream<<"Ignoring IMoveAction from "
2432 <<(ma->from_inv.dump())<<":"<<ma->from_list
2433 <<" to "<<(ma->to_inv.dump())<<":"<<ma->to_list
2434 <<" because dst is "<<ma->to_list<<std::endl;
2439 // Disallow moving items in elsewhere than player's inventory
2440 // if not allowed to interact
2441 if(!checkPriv(player->getName(), "interact") &&
2442 (!from_inv_is_current_player ||
2443 !to_inv_is_current_player))
2445 infostream<<"Cannot move outside of player's inventory: "
2446 <<"No interact privilege"<<std::endl;
2452 Handle restrictions and special cases of the drop action
2454 else if(a->getType() == IACTION_DROP)
2456 IDropAction *da = (IDropAction*)a;
2458 da->from_inv.applyCurrentPlayer(player->getName());
2460 setInventoryModified(da->from_inv);
2463 Disable dropping items out of craftpreview
2465 if(da->from_list == "craftpreview")
2467 infostream<<"Ignoring IDropAction from "
2468 <<(da->from_inv.dump())<<":"<<da->from_list
2469 <<" because src is "<<da->from_list<<std::endl;
2474 // Disallow dropping items if not allowed to interact
2475 if(!checkPriv(player->getName(), "interact"))
2482 Handle restrictions and special cases of the craft action
2484 else if(a->getType() == IACTION_CRAFT)
2486 ICraftAction *ca = (ICraftAction*)a;
2488 ca->craft_inv.applyCurrentPlayer(player->getName());
2490 setInventoryModified(ca->craft_inv);
2492 //bool craft_inv_is_current_player =
2493 // (ca->craft_inv.type == InventoryLocation::PLAYER) &&
2494 // (ca->craft_inv.name == player->getName());
2496 // Disallow crafting if not allowed to interact
2497 if(!checkPriv(player->getName(), "interact"))
2499 infostream<<"Cannot craft: "
2500 <<"No interact privilege"<<std::endl;
2507 a->apply(this, playersao, this);
2511 else if(command == TOSERVER_CHAT_MESSAGE)
2519 std::string datastring((char*)&data[2], datasize-2);
2520 std::istringstream is(datastring, std::ios_base::binary);
2523 is.read((char*)buf, 2);
2524 u16 len = readU16(buf);
2526 std::wstring message;
2527 for(u16 i=0; i<len; i++)
2529 is.read((char*)buf, 2);
2530 message += (wchar_t)readU16(buf);
2533 // If something goes wrong, this player is to blame
2534 RollbackScopeActor rollback_scope(m_rollback,
2535 std::string("player:")+player->getName());
2537 // Get player name of this client
2538 std::wstring name = narrow_to_wide(player->getName());
2541 bool ate = m_script->on_chat_message(player->getName(),
2542 wide_to_narrow(message));
2543 // If script ate the message, don't proceed
2547 // Line to send to players
2549 // Whether to send to the player that sent the line
2550 bool send_to_sender = false;
2551 // Whether to send to other players
2552 bool send_to_others = false;
2554 // Commands are implemented in Lua, so only catch invalid
2555 // commands that were not "eaten" and send an error back
2556 if(message[0] == L'/')
2558 message = message.substr(1);
2559 send_to_sender = true;
2560 if(message.length() == 0)
2561 line += L"-!- Empty command";
2563 line += L"-!- Invalid command: " + str_split(message, L' ')[0];
2567 if(checkPriv(player->getName(), "shout")){
2572 send_to_others = true;
2574 line += L"-!- You don't have permission to shout.";
2575 send_to_sender = true;
2582 actionstream<<"CHAT: "<<wide_to_narrow(line)<<std::endl;
2585 Send the message to clients
2587 for(std::map<u16, RemoteClient*>::iterator
2588 i = m_clients.begin();
2589 i != m_clients.end(); ++i)
2591 // Get client and check that it is valid
2592 RemoteClient *client = i->second;
2593 assert(client->peer_id == i->first);
2594 if(client->serialization_version == SER_FMT_VER_INVALID)
2598 bool sender_selected = (peer_id == client->peer_id);
2599 if(sender_selected == true && send_to_sender == false)
2601 if(sender_selected == false && send_to_others == false)
2604 SendChatMessage(client->peer_id, line);
2608 else if(command == TOSERVER_DAMAGE)
2610 std::string datastring((char*)&data[2], datasize-2);
2611 std::istringstream is(datastring, std::ios_base::binary);
2612 u8 damage = readU8(is);
2614 if(g_settings->getBool("enable_damage"))
2616 actionstream<<player->getName()<<" damaged by "
2617 <<(int)damage<<" hp at "<<PP(player->getPosition()/BS)
2620 playersao->setHP(playersao->getHP() - damage);
2622 if(playersao->getHP() == 0 && playersao->m_hp_not_sent)
2625 if(playersao->m_hp_not_sent)
2626 SendPlayerHP(peer_id);
2629 else if(command == TOSERVER_BREATH)
2631 std::string datastring((char*)&data[2], datasize-2);
2632 std::istringstream is(datastring, std::ios_base::binary);
2633 u16 breath = readU16(is);
2634 playersao->setBreath(breath);
2636 else if(command == TOSERVER_PASSWORD)
2639 [0] u16 TOSERVER_PASSWORD
2640 [2] u8[28] old password
2641 [30] u8[28] new password
2644 if(datasize != 2+PASSWORD_SIZE*2)
2646 /*char password[PASSWORD_SIZE];
2647 for(u32 i=0; i<PASSWORD_SIZE-1; i++)
2648 password[i] = data[2+i];
2649 password[PASSWORD_SIZE-1] = 0;*/
2651 for(u32 i=0; i<PASSWORD_SIZE-1; i++)
2659 for(u32 i=0; i<PASSWORD_SIZE-1; i++)
2661 char c = data[2+PASSWORD_SIZE+i];
2667 if(!base64_is_valid(newpwd)){
2668 infostream<<"Server: "<<player->getName()<<" supplied invalid password hash"<<std::endl;
2669 // Wrong old password supplied!!
2670 SendChatMessage(peer_id, L"Invalid new password hash supplied. Password NOT changed.");
2674 infostream<<"Server: Client requests a password change from "
2675 <<"'"<<oldpwd<<"' to '"<<newpwd<<"'"<<std::endl;
2677 std::string playername = player->getName();
2679 std::string checkpwd;
2680 m_script->getAuth(playername, &checkpwd, NULL);
2682 if(oldpwd != checkpwd)
2684 infostream<<"Server: invalid old password"<<std::endl;
2685 // Wrong old password supplied!!
2686 SendChatMessage(peer_id, L"Invalid old password supplied. Password NOT changed.");
2690 bool success = m_script->setPassword(playername, newpwd);
2692 actionstream<<player->getName()<<" changes password"<<std::endl;
2693 SendChatMessage(peer_id, L"Password change successful.");
2695 actionstream<<player->getName()<<" tries to change password but "
2696 <<"it fails"<<std::endl;
2697 SendChatMessage(peer_id, L"Password change failed or inavailable.");
2700 else if(command == TOSERVER_PLAYERITEM)
2705 u16 item = readU16(&data[2]);
2706 playersao->setWieldIndex(item);
2708 else if(command == TOSERVER_RESPAWN)
2710 if(player->hp != 0 || !g_settings->getBool("enable_damage"))
2713 RespawnPlayer(peer_id);
2715 actionstream<<player->getName()<<" respawns at "
2716 <<PP(player->getPosition()/BS)<<std::endl;
2718 // ActiveObject is added to environment in AsyncRunStep after
2719 // the previous addition has been succesfully removed
2721 else if(command == TOSERVER_REQUEST_MEDIA) {
2722 std::string datastring((char*)&data[2], datasize-2);
2723 std::istringstream is(datastring, std::ios_base::binary);
2725 std::list<MediaRequest> tosend;
2726 u16 numfiles = readU16(is);
2728 infostream<<"Sending "<<numfiles<<" files to "
2729 <<getPlayerName(peer_id)<<std::endl;
2730 verbosestream<<"TOSERVER_REQUEST_MEDIA: "<<std::endl;
2732 for(int i = 0; i < numfiles; i++) {
2733 std::string name = deSerializeString(is);
2734 tosend.push_back(MediaRequest(name));
2735 verbosestream<<"TOSERVER_REQUEST_MEDIA: requested file "
2739 sendRequestedMedia(peer_id, tosend);
2741 // Now the client should know about everything
2742 // (definitions and files)
2743 getClient(peer_id)->definitions_sent = true;
2745 else if(command == TOSERVER_RECEIVED_MEDIA) {
2746 getClient(peer_id)->definitions_sent = true;
2748 else if(command == TOSERVER_INTERACT)
2750 std::string datastring((char*)&data[2], datasize-2);
2751 std::istringstream is(datastring, std::ios_base::binary);
2757 [5] u32 length of the next item
2758 [9] serialized PointedThing
2760 0: start digging (from undersurface) or use
2761 1: stop digging (all parameters ignored)
2762 2: digging completed
2763 3: place block or item (to abovesurface)
2766 u8 action = readU8(is);
2767 u16 item_i = readU16(is);
2768 std::istringstream tmp_is(deSerializeLongString(is), std::ios::binary);
2769 PointedThing pointed;
2770 pointed.deSerialize(tmp_is);
2772 verbosestream<<"TOSERVER_INTERACT: action="<<(int)action<<", item="
2773 <<item_i<<", pointed="<<pointed.dump()<<std::endl;
2777 verbosestream<<"TOSERVER_INTERACT: "<<player->getName()
2778 <<" tried to interact, but is dead!"<<std::endl;
2782 v3f player_pos = playersao->getLastGoodPosition();
2784 // Update wielded item
2785 playersao->setWieldIndex(item_i);
2787 // Get pointed to node (undefined if not POINTEDTYPE_NODE)
2788 v3s16 p_under = pointed.node_undersurface;
2789 v3s16 p_above = pointed.node_abovesurface;
2791 // Get pointed to object (NULL if not POINTEDTYPE_OBJECT)
2792 ServerActiveObject *pointed_object = NULL;
2793 if(pointed.type == POINTEDTHING_OBJECT)
2795 pointed_object = m_env->getActiveObject(pointed.object_id);
2796 if(pointed_object == NULL)
2798 verbosestream<<"TOSERVER_INTERACT: "
2799 "pointed object is NULL"<<std::endl;
2805 v3f pointed_pos_under = player_pos;
2806 v3f pointed_pos_above = player_pos;
2807 if(pointed.type == POINTEDTHING_NODE)
2809 pointed_pos_under = intToFloat(p_under, BS);
2810 pointed_pos_above = intToFloat(p_above, BS);
2812 else if(pointed.type == POINTEDTHING_OBJECT)
2814 pointed_pos_under = pointed_object->getBasePosition();
2815 pointed_pos_above = pointed_pos_under;
2819 Check that target is reasonably close
2820 (only when digging or placing things)
2822 if(action == 0 || action == 2 || action == 3)
2824 float d = player_pos.getDistanceFrom(pointed_pos_under);
2825 float max_d = BS * 14; // Just some large enough value
2827 actionstream<<"Player "<<player->getName()
2828 <<" tried to access "<<pointed.dump()
2830 <<"d="<<d<<", max_d="<<max_d
2831 <<". ignoring."<<std::endl;
2832 // Re-send block to revert change on client-side
2833 RemoteClient *client = getClient(peer_id);
2834 v3s16 blockpos = getNodeBlockPos(floatToInt(pointed_pos_under, BS));
2835 client->SetBlockNotSent(blockpos);
2837 m_script->on_cheat(playersao, "interacted_too_far");
2844 Make sure the player is allowed to do it
2846 if(!checkPriv(player->getName(), "interact"))
2848 actionstream<<player->getName()<<" attempted to interact with "
2849 <<pointed.dump()<<" without 'interact' privilege"
2851 // Re-send block to revert change on client-side
2852 RemoteClient *client = getClient(peer_id);
2853 // Digging completed -> under
2855 v3s16 blockpos = getNodeBlockPos(floatToInt(pointed_pos_under, BS));
2856 client->SetBlockNotSent(blockpos);
2858 // Placement -> above
2860 v3s16 blockpos = getNodeBlockPos(floatToInt(pointed_pos_above, BS));
2861 client->SetBlockNotSent(blockpos);
2867 If something goes wrong, this player is to blame
2869 RollbackScopeActor rollback_scope(m_rollback,
2870 std::string("player:")+player->getName());
2873 0: start digging or punch object
2877 if(pointed.type == POINTEDTHING_NODE)
2880 NOTE: This can be used in the future to check if
2881 somebody is cheating, by checking the timing.
2883 MapNode n(CONTENT_IGNORE);
2886 n = m_env->getMap().getNode(p_under);
2888 catch(InvalidPositionException &e)
2890 infostream<<"Server: Not punching: Node not found."
2891 <<" Adding block to emerge queue."
2893 m_emerge->enqueueBlockEmerge(peer_id, getNodeBlockPos(p_above), false);
2895 if(n.getContent() != CONTENT_IGNORE)
2896 m_script->node_on_punch(p_under, n, playersao);
2898 playersao->noCheatDigStart(p_under);
2900 else if(pointed.type == POINTEDTHING_OBJECT)
2902 // Skip if object has been removed
2903 if(pointed_object->m_removed)
2906 actionstream<<player->getName()<<" punches object "
2907 <<pointed.object_id<<": "
2908 <<pointed_object->getDescription()<<std::endl;
2910 ItemStack punchitem = playersao->getWieldedItem();
2911 ToolCapabilities toolcap =
2912 punchitem.getToolCapabilities(m_itemdef);
2913 v3f dir = (pointed_object->getBasePosition() -
2914 (player->getPosition() + player->getEyeOffset())
2916 float time_from_last_punch =
2917 playersao->resetTimeFromLastPunch();
2918 pointed_object->punch(dir, &toolcap, playersao,
2919 time_from_last_punch);
2927 else if(action == 1)
2932 2: Digging completed
2934 else if(action == 2)
2936 // Only digging of nodes
2937 if(pointed.type == POINTEDTHING_NODE)
2939 MapNode n(CONTENT_IGNORE);
2942 n = m_env->getMap().getNode(p_under);
2944 catch(InvalidPositionException &e)
2946 infostream<<"Server: Not finishing digging: Node not found."
2947 <<" Adding block to emerge queue."
2949 m_emerge->enqueueBlockEmerge(peer_id, getNodeBlockPos(p_above), false);
2952 /* Cheat prevention */
2953 bool is_valid_dig = true;
2954 if(!isSingleplayer() && !g_settings->getBool("disable_anticheat"))
2956 v3s16 nocheat_p = playersao->getNoCheatDigPos();
2957 float nocheat_t = playersao->getNoCheatDigTime();
2958 playersao->noCheatDigEnd();
2959 // If player didn't start digging this, ignore dig
2960 if(nocheat_p != p_under){
2961 infostream<<"Server: NoCheat: "<<player->getName()
2962 <<" started digging "
2963 <<PP(nocheat_p)<<" and completed digging "
2964 <<PP(p_under)<<"; not digging."<<std::endl;
2965 is_valid_dig = false;
2967 m_script->on_cheat(playersao, "finished_unknown_dig");
2969 // Get player's wielded item
2970 ItemStack playeritem;
2971 InventoryList *mlist = playersao->getInventory()->getList("main");
2973 playeritem = mlist->getItem(playersao->getWieldIndex());
2974 ToolCapabilities playeritem_toolcap =
2975 playeritem.getToolCapabilities(m_itemdef);
2976 // Get diggability and expected digging time
2977 DigParams params = getDigParams(m_nodedef->get(n).groups,
2978 &playeritem_toolcap);
2979 // If can't dig, try hand
2980 if(!params.diggable){
2981 const ItemDefinition &hand = m_itemdef->get("");
2982 const ToolCapabilities *tp = hand.tool_capabilities;
2984 params = getDigParams(m_nodedef->get(n).groups, tp);
2986 // If can't dig, ignore dig
2987 if(!params.diggable){
2988 infostream<<"Server: NoCheat: "<<player->getName()
2989 <<" completed digging "<<PP(p_under)
2990 <<", which is not diggable with tool. not digging."
2992 is_valid_dig = false;
2994 m_script->on_cheat(playersao, "dug_unbreakable");
2996 // Check digging time
2997 // If already invalidated, we don't have to
2999 // Well not our problem then
3001 // Clean and long dig
3002 else if(params.time > 2.0 && nocheat_t * 1.2 > params.time){
3003 // All is good, but grab time from pool; don't care if
3004 // it's actually available
3005 playersao->getDigPool().grab(params.time);
3007 // Short or laggy dig
3008 // Try getting the time from pool
3009 else if(playersao->getDigPool().grab(params.time)){
3014 infostream<<"Server: NoCheat: "<<player->getName()
3015 <<" completed digging "<<PP(p_under)
3016 <<"too fast; not digging."<<std::endl;
3017 is_valid_dig = false;
3019 m_script->on_cheat(playersao, "dug_too_fast");
3023 /* Actually dig node */
3025 if(is_valid_dig && n.getContent() != CONTENT_IGNORE)
3026 m_script->node_on_dig(p_under, n, playersao);
3028 // Send unusual result (that is, node not being removed)
3029 if(m_env->getMap().getNodeNoEx(p_under).getContent() != CONTENT_AIR)
3031 // Re-send block to revert change on client-side
3032 RemoteClient *client = getClient(peer_id);
3033 v3s16 blockpos = getNodeBlockPos(floatToInt(pointed_pos_under, BS));
3034 client->SetBlockNotSent(blockpos);
3040 3: place block or right-click object
3042 else if(action == 3)
3044 ItemStack item = playersao->getWieldedItem();
3046 // Reset build time counter
3047 if(pointed.type == POINTEDTHING_NODE &&
3048 item.getDefinition(m_itemdef).type == ITEM_NODE)
3049 getClient(peer_id)->m_time_from_building = 0.0;
3051 if(pointed.type == POINTEDTHING_OBJECT)
3053 // Right click object
3055 // Skip if object has been removed
3056 if(pointed_object->m_removed)
3059 actionstream<<player->getName()<<" right-clicks object "
3060 <<pointed.object_id<<": "
3061 <<pointed_object->getDescription()<<std::endl;
3064 pointed_object->rightClick(playersao);
3066 else if(m_script->item_OnPlace(
3067 item, playersao, pointed))
3069 // Placement was handled in lua
3071 // Apply returned ItemStack
3072 playersao->setWieldedItem(item);
3075 // If item has node placement prediction, always send the
3076 // blocks to make sure the client knows what exactly happened
3077 if(item.getDefinition(m_itemdef).node_placement_prediction != ""){
3078 RemoteClient *client = getClient(peer_id);
3079 v3s16 blockpos = getNodeBlockPos(floatToInt(pointed_pos_above, BS));
3080 client->SetBlockNotSent(blockpos);
3081 v3s16 blockpos2 = getNodeBlockPos(floatToInt(pointed_pos_under, BS));
3082 if(blockpos2 != blockpos){
3083 client->SetBlockNotSent(blockpos2);
3091 else if(action == 4)
3093 ItemStack item = playersao->getWieldedItem();
3095 actionstream<<player->getName()<<" uses "<<item.name
3096 <<", pointing at "<<pointed.dump()<<std::endl;
3098 if(m_script->item_OnUse(
3099 item, playersao, pointed))
3101 // Apply returned ItemStack
3102 playersao->setWieldedItem(item);
3109 Catch invalid actions
3113 infostream<<"WARNING: Server: Invalid action "
3114 <<action<<std::endl;
3117 else if(command == TOSERVER_REMOVED_SOUNDS)
3119 std::string datastring((char*)&data[2], datasize-2);
3120 std::istringstream is(datastring, std::ios_base::binary);
3122 int num = readU16(is);
3123 for(int k=0; k<num; k++){
3124 s32 id = readS32(is);
3125 std::map<s32, ServerPlayingSound>::iterator i =
3126 m_playing_sounds.find(id);
3127 if(i == m_playing_sounds.end())
3129 ServerPlayingSound &psound = i->second;
3130 psound.clients.erase(peer_id);
3131 if(psound.clients.size() == 0)
3132 m_playing_sounds.erase(i++);
3135 else if(command == TOSERVER_NODEMETA_FIELDS)
3137 std::string datastring((char*)&data[2], datasize-2);
3138 std::istringstream is(datastring, std::ios_base::binary);
3140 v3s16 p = readV3S16(is);
3141 std::string formname = deSerializeString(is);
3142 int num = readU16(is);
3143 std::map<std::string, std::string> fields;
3144 for(int k=0; k<num; k++){
3145 std::string fieldname = deSerializeString(is);
3146 std::string fieldvalue = deSerializeLongString(is);
3147 fields[fieldname] = fieldvalue;
3150 // If something goes wrong, this player is to blame
3151 RollbackScopeActor rollback_scope(m_rollback,
3152 std::string("player:")+player->getName());
3154 // Check the target node for rollback data; leave others unnoticed
3155 RollbackNode rn_old(&m_env->getMap(), p, this);
3157 m_script->node_on_receive_fields(p, formname, fields,playersao);
3159 // Report rollback data
3160 RollbackNode rn_new(&m_env->getMap(), p, this);
3161 if(rollback() && rn_new != rn_old){
3162 RollbackAction action;
3163 action.setSetNode(p, rn_old, rn_new);
3164 rollback()->reportAction(action);
3167 else if(command == TOSERVER_INVENTORY_FIELDS)
3169 std::string datastring((char*)&data[2], datasize-2);
3170 std::istringstream is(datastring, std::ios_base::binary);
3172 std::string formname = deSerializeString(is);
3173 int num = readU16(is);
3174 std::map<std::string, std::string> fields;
3175 for(int k=0; k<num; k++){
3176 std::string fieldname = deSerializeString(is);
3177 std::string fieldvalue = deSerializeLongString(is);
3178 fields[fieldname] = fieldvalue;
3181 m_script->on_playerReceiveFields(playersao, formname, fields);
3185 infostream<<"Server::ProcessData(): Ignoring "
3186 "unknown command "<<command<<std::endl;
3190 catch(SendFailedException &e)
3192 errorstream<<"Server::ProcessData(): SendFailedException: "
3198 void Server::onMapEditEvent(MapEditEvent *event)
3200 //infostream<<"Server::onMapEditEvent()"<<std::endl;
3201 if(m_ignore_map_edit_events)
3203 if(m_ignore_map_edit_events_area.contains(event->getArea()))
3205 MapEditEvent *e = event->clone();
3206 m_unsent_map_edit_queue.push_back(e);
3209 Inventory* Server::getInventory(const InventoryLocation &loc)
3212 case InventoryLocation::UNDEFINED:
3215 case InventoryLocation::CURRENT_PLAYER:
3218 case InventoryLocation::PLAYER:
3220 Player *player = m_env->getPlayer(loc.name.c_str());
3223 PlayerSAO *playersao = player->getPlayerSAO();
3226 return playersao->getInventory();
3229 case InventoryLocation::NODEMETA:
3231 NodeMetadata *meta = m_env->getMap().getNodeMetadata(loc.p);
3234 return meta->getInventory();
3237 case InventoryLocation::DETACHED:
3239 if(m_detached_inventories.count(loc.name) == 0)
3241 return m_detached_inventories[loc.name];
3249 void Server::setInventoryModified(const InventoryLocation &loc)
3252 case InventoryLocation::UNDEFINED:
3255 case InventoryLocation::PLAYER:
3257 Player *player = m_env->getPlayer(loc.name.c_str());
3260 PlayerSAO *playersao = player->getPlayerSAO();
3263 playersao->m_inventory_not_sent = true;
3264 playersao->m_wielded_item_not_sent = true;
3267 case InventoryLocation::NODEMETA:
3269 v3s16 blockpos = getNodeBlockPos(loc.p);
3271 MapBlock *block = m_env->getMap().getBlockNoCreateNoEx(blockpos);
3273 block->raiseModified(MOD_STATE_WRITE_NEEDED);
3275 setBlockNotSent(blockpos);
3278 case InventoryLocation::DETACHED:
3280 sendDetachedInventoryToAll(loc.name);
3288 //std::list<PlayerInfo> Server::getPlayerInfo()
3290 // DSTACK(__FUNCTION_NAME);
3291 // JMutexAutoLock envlock(m_env_mutex);
3292 // JMutexAutoLock conlock(m_con_mutex);
3294 // std::list<PlayerInfo> list;
3296 // std::list<Player*> players = m_env->getPlayers();
3298 // std::list<Player*>::iterator i;
3299 // for(i = players.begin();
3300 // i != players.end(); ++i)
3304 // Player *player = *i;
3307 // // Copy info from connection to info struct
3308 // info.id = player->peer_id;
3309 // info.address = m_con.GetPeerAddress(player->peer_id);
3310 // info.avg_rtt = m_con.GetPeerAvgRTT(player->peer_id);
3312 // catch(con::PeerNotFoundException &e)
3314 // // Set dummy peer info
3316 // info.address = Address(0,0,0,0,0);
3317 // info.avg_rtt = 0.0;
3320 // snprintf(info.name, PLAYERNAME_SIZE, "%s", player->getName());
3321 // info.position = player->getPosition();
3323 // list.push_back(info);
3330 void Server::peerAdded(con::Peer *peer)
3332 DSTACK(__FUNCTION_NAME);
3333 verbosestream<<"Server::peerAdded(): peer->id="
3334 <<peer->id<<std::endl;
3337 c.type = PEER_ADDED;
3338 c.peer_id = peer->id;
3340 m_peer_change_queue.push_back(c);
3343 void Server::deletingPeer(con::Peer *peer, bool timeout)
3345 DSTACK(__FUNCTION_NAME);
3346 verbosestream<<"Server::deletingPeer(): peer->id="
3347 <<peer->id<<", timeout="<<timeout<<std::endl;
3350 c.type = PEER_REMOVED;
3351 c.peer_id = peer->id;
3352 c.timeout = timeout;
3353 m_peer_change_queue.push_back(c);
3360 void Server::SendMovement(con::Connection &con, u16 peer_id)
3362 DSTACK(__FUNCTION_NAME);
3363 std::ostringstream os(std::ios_base::binary);
3365 writeU16(os, TOCLIENT_MOVEMENT);
3366 writeF1000(os, g_settings->getFloat("movement_acceleration_default"));
3367 writeF1000(os, g_settings->getFloat("movement_acceleration_air"));
3368 writeF1000(os, g_settings->getFloat("movement_acceleration_fast"));
3369 writeF1000(os, g_settings->getFloat("movement_speed_walk"));
3370 writeF1000(os, g_settings->getFloat("movement_speed_crouch"));
3371 writeF1000(os, g_settings->getFloat("movement_speed_fast"));
3372 writeF1000(os, g_settings->getFloat("movement_speed_climb"));
3373 writeF1000(os, g_settings->getFloat("movement_speed_jump"));
3374 writeF1000(os, g_settings->getFloat("movement_liquid_fluidity"));
3375 writeF1000(os, g_settings->getFloat("movement_liquid_fluidity_smooth"));
3376 writeF1000(os, g_settings->getFloat("movement_liquid_sink"));
3377 writeF1000(os, g_settings->getFloat("movement_gravity"));
3380 std::string s = os.str();
3381 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3383 con.Send(peer_id, 0, data, true);
3386 void Server::SendHP(con::Connection &con, u16 peer_id, u8 hp)
3388 DSTACK(__FUNCTION_NAME);
3389 std::ostringstream os(std::ios_base::binary);
3391 writeU16(os, TOCLIENT_HP);
3395 std::string s = os.str();
3396 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3398 con.Send(peer_id, 0, data, true);
3401 void Server::SendBreath(con::Connection &con, u16 peer_id, u16 breath)
3403 DSTACK(__FUNCTION_NAME);
3404 std::ostringstream os(std::ios_base::binary);
3406 writeU16(os, TOCLIENT_BREATH);
3407 writeU16(os, breath);
3410 std::string s = os.str();
3411 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3413 con.Send(peer_id, 0, data, true);
3416 void Server::SendAccessDenied(con::Connection &con, u16 peer_id,
3417 const std::wstring &reason)
3419 DSTACK(__FUNCTION_NAME);
3420 std::ostringstream os(std::ios_base::binary);
3422 writeU16(os, TOCLIENT_ACCESS_DENIED);
3423 os<<serializeWideString(reason);
3426 std::string s = os.str();
3427 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3429 con.Send(peer_id, 0, data, true);
3432 void Server::SendDeathscreen(con::Connection &con, u16 peer_id,
3433 bool set_camera_point_target, v3f camera_point_target)
3435 DSTACK(__FUNCTION_NAME);
3436 std::ostringstream os(std::ios_base::binary);
3438 writeU16(os, TOCLIENT_DEATHSCREEN);
3439 writeU8(os, set_camera_point_target);
3440 writeV3F1000(os, camera_point_target);
3443 std::string s = os.str();
3444 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3446 con.Send(peer_id, 0, data, true);
3449 void Server::SendItemDef(con::Connection &con, u16 peer_id,
3450 IItemDefManager *itemdef, u16 protocol_version)
3452 DSTACK(__FUNCTION_NAME);
3453 std::ostringstream os(std::ios_base::binary);
3457 u32 length of the next item
3458 zlib-compressed serialized ItemDefManager
3460 writeU16(os, TOCLIENT_ITEMDEF);
3461 std::ostringstream tmp_os(std::ios::binary);
3462 itemdef->serialize(tmp_os, protocol_version);
3463 std::ostringstream tmp_os2(std::ios::binary);
3464 compressZlib(tmp_os.str(), tmp_os2);
3465 os<<serializeLongString(tmp_os2.str());
3468 std::string s = os.str();
3469 verbosestream<<"Server: Sending item definitions to id("<<peer_id
3470 <<"): size="<<s.size()<<std::endl;
3471 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3473 con.Send(peer_id, 0, data, true);
3476 void Server::SendNodeDef(con::Connection &con, u16 peer_id,
3477 INodeDefManager *nodedef, u16 protocol_version)
3479 DSTACK(__FUNCTION_NAME);
3480 std::ostringstream os(std::ios_base::binary);
3484 u32 length of the next item
3485 zlib-compressed serialized NodeDefManager
3487 writeU16(os, TOCLIENT_NODEDEF);
3488 std::ostringstream tmp_os(std::ios::binary);
3489 nodedef->serialize(tmp_os, protocol_version);
3490 std::ostringstream tmp_os2(std::ios::binary);
3491 compressZlib(tmp_os.str(), tmp_os2);
3492 os<<serializeLongString(tmp_os2.str());
3495 std::string s = os.str();
3496 verbosestream<<"Server: Sending node definitions to id("<<peer_id
3497 <<"): size="<<s.size()<<std::endl;
3498 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3500 con.Send(peer_id, 0, data, true);
3504 Non-static send methods
3507 void Server::SendInventory(u16 peer_id)
3509 DSTACK(__FUNCTION_NAME);
3511 PlayerSAO *playersao = getPlayerSAO(peer_id);
3514 playersao->m_inventory_not_sent = false;
3520 std::ostringstream os;
3521 playersao->getInventory()->serialize(os);
3523 std::string s = os.str();
3525 SharedBuffer<u8> data(s.size()+2);
3526 writeU16(&data[0], TOCLIENT_INVENTORY);
3527 memcpy(&data[2], s.c_str(), s.size());
3530 m_con.Send(peer_id, 0, data, true);
3533 void Server::SendChatMessage(u16 peer_id, const std::wstring &message)
3535 DSTACK(__FUNCTION_NAME);
3537 std::ostringstream os(std::ios_base::binary);
3541 writeU16(buf, TOCLIENT_CHAT_MESSAGE);
3542 os.write((char*)buf, 2);
3545 writeU16(buf, message.size());
3546 os.write((char*)buf, 2);
3549 for(u32 i=0; i<message.size(); i++)
3553 os.write((char*)buf, 2);
3557 std::string s = os.str();
3558 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3560 m_con.Send(peer_id, 0, data, true);
3563 void Server::SendShowFormspecMessage(u16 peer_id, const std::string formspec,
3564 const std::string formname)
3566 DSTACK(__FUNCTION_NAME);
3568 std::ostringstream os(std::ios_base::binary);
3572 writeU16(buf, TOCLIENT_SHOW_FORMSPEC);
3573 os.write((char*)buf, 2);
3574 os<<serializeLongString(formspec);
3575 os<<serializeString(formname);
3578 std::string s = os.str();
3579 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3581 m_con.Send(peer_id, 0, data, true);
3584 // Spawns a particle on peer with peer_id
3585 void Server::SendSpawnParticle(u16 peer_id, v3f pos, v3f velocity, v3f acceleration,
3586 float expirationtime, float size, bool collisiondetection,
3587 std::string texture)
3589 DSTACK(__FUNCTION_NAME);
3591 std::ostringstream os(std::ios_base::binary);
3592 writeU16(os, TOCLIENT_SPAWN_PARTICLE);
3593 writeV3F1000(os, pos);
3594 writeV3F1000(os, velocity);
3595 writeV3F1000(os, acceleration);
3596 writeF1000(os, expirationtime);
3597 writeF1000(os, size);
3598 writeU8(os, collisiondetection);
3599 os<<serializeLongString(texture);
3602 std::string s = os.str();
3603 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3605 m_con.Send(peer_id, 0, data, true);
3608 // Spawns a particle on all peers
3609 void Server::SendSpawnParticleAll(v3f pos, v3f velocity, v3f acceleration,
3610 float expirationtime, float size, bool collisiondetection,
3611 std::string texture)
3613 for(std::map<u16, RemoteClient*>::iterator
3614 i = m_clients.begin();
3615 i != m_clients.end(); i++)
3617 // Get client and check that it is valid
3618 RemoteClient *client = i->second;
3619 assert(client->peer_id == i->first);
3620 if(client->serialization_version == SER_FMT_VER_INVALID)
3623 SendSpawnParticle(client->peer_id, pos, velocity, acceleration,
3624 expirationtime, size, collisiondetection, texture);
3628 // Adds a ParticleSpawner on peer with peer_id
3629 void Server::SendAddParticleSpawner(u16 peer_id, u16 amount, float spawntime, v3f minpos, v3f maxpos,
3630 v3f minvel, v3f maxvel, v3f minacc, v3f maxacc, float minexptime, float maxexptime,
3631 float minsize, float maxsize, bool collisiondetection, std::string texture, u32 id)
3633 DSTACK(__FUNCTION_NAME);
3635 std::ostringstream os(std::ios_base::binary);
3636 writeU16(os, TOCLIENT_ADD_PARTICLESPAWNER);
3638 writeU16(os, amount);
3639 writeF1000(os, spawntime);
3640 writeV3F1000(os, minpos);
3641 writeV3F1000(os, maxpos);
3642 writeV3F1000(os, minvel);
3643 writeV3F1000(os, maxvel);
3644 writeV3F1000(os, minacc);
3645 writeV3F1000(os, maxacc);
3646 writeF1000(os, minexptime);
3647 writeF1000(os, maxexptime);
3648 writeF1000(os, minsize);
3649 writeF1000(os, maxsize);
3650 writeU8(os, collisiondetection);
3651 os<<serializeLongString(texture);
3655 std::string s = os.str();
3656 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3658 m_con.Send(peer_id, 0, data, true);
3661 // Adds a ParticleSpawner on all peers
3662 void Server::SendAddParticleSpawnerAll(u16 amount, float spawntime, v3f minpos, v3f maxpos,
3663 v3f minvel, v3f maxvel, v3f minacc, v3f maxacc, float minexptime, float maxexptime,
3664 float minsize, float maxsize, bool collisiondetection, std::string texture, u32 id)
3666 for(std::map<u16, RemoteClient*>::iterator
3667 i = m_clients.begin();
3668 i != m_clients.end(); i++)
3670 // Get client and check that it is valid
3671 RemoteClient *client = i->second;
3672 assert(client->peer_id == i->first);
3673 if(client->serialization_version == SER_FMT_VER_INVALID)
3676 SendAddParticleSpawner(client->peer_id, amount, spawntime,
3677 minpos, maxpos, minvel, maxvel, minacc, maxacc,
3678 minexptime, maxexptime, minsize, maxsize, collisiondetection, texture, id);
3682 void Server::SendDeleteParticleSpawner(u16 peer_id, u32 id)
3684 DSTACK(__FUNCTION_NAME);
3686 std::ostringstream os(std::ios_base::binary);
3687 writeU16(os, TOCLIENT_DELETE_PARTICLESPAWNER);
3692 std::string s = os.str();
3693 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3695 m_con.Send(peer_id, 0, data, true);
3698 void Server::SendDeleteParticleSpawnerAll(u32 id)
3700 for(std::map<u16, RemoteClient*>::iterator
3701 i = m_clients.begin();
3702 i != m_clients.end(); i++)
3704 // Get client and check that it is valid
3705 RemoteClient *client = i->second;
3706 assert(client->peer_id == i->first);
3707 if(client->serialization_version == SER_FMT_VER_INVALID)
3710 SendDeleteParticleSpawner(client->peer_id, id);
3714 void Server::SendHUDAdd(u16 peer_id, u32 id, HudElement *form)
3716 std::ostringstream os(std::ios_base::binary);
3719 writeU16(os, TOCLIENT_HUDADD);
3721 writeU8(os, (u8)form->type);
3722 writeV2F1000(os, form->pos);
3723 os << serializeString(form->name);
3724 writeV2F1000(os, form->scale);
3725 os << serializeString(form->text);
3726 writeU32(os, form->number);
3727 writeU32(os, form->item);
3728 writeU32(os, form->dir);
3729 writeV2F1000(os, form->align);
3730 writeV2F1000(os, form->offset);
3733 std::string s = os.str();
3734 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3736 m_con.Send(peer_id, 0, data, true);
3739 void Server::SendHUDRemove(u16 peer_id, u32 id)
3741 std::ostringstream os(std::ios_base::binary);
3744 writeU16(os, TOCLIENT_HUDRM);
3748 std::string s = os.str();
3749 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3751 m_con.Send(peer_id, 0, data, true);
3754 void Server::SendHUDChange(u16 peer_id, u32 id, HudElementStat stat, void *value)
3756 std::ostringstream os(std::ios_base::binary);
3759 writeU16(os, TOCLIENT_HUDCHANGE);
3761 writeU8(os, (u8)stat);
3764 case HUD_STAT_SCALE:
3765 case HUD_STAT_ALIGN:
3766 case HUD_STAT_OFFSET:
3767 writeV2F1000(os, *(v2f *)value);
3771 os << serializeString(*(std::string *)value);
3773 case HUD_STAT_NUMBER:
3777 writeU32(os, *(u32 *)value);
3782 std::string s = os.str();
3783 SharedBuffer<u8> data((u8 *)s.c_str(), s.size());
3785 m_con.Send(peer_id, 0, data, true);
3788 void Server::SendHUDSetFlags(u16 peer_id, u32 flags, u32 mask)
3790 std::ostringstream os(std::ios_base::binary);
3793 writeU16(os, TOCLIENT_HUD_SET_FLAGS);
3794 writeU32(os, flags);
3798 std::string s = os.str();
3799 SharedBuffer<u8> data((u8 *)s.c_str(), s.size());
3801 m_con.Send(peer_id, 0, data, true);
3804 void Server::SendHUDSetParam(u16 peer_id, u16 param, const std::string &value)
3806 std::ostringstream os(std::ios_base::binary);
3809 writeU16(os, TOCLIENT_HUD_SET_PARAM);
3810 writeU16(os, param);
3811 os<<serializeString(value);
3814 std::string s = os.str();
3815 SharedBuffer<u8> data((u8 *)s.c_str(), s.size());
3817 m_con.Send(peer_id, 0, data, true);
3820 void Server::BroadcastChatMessage(const std::wstring &message)
3822 for(std::map<u16, RemoteClient*>::iterator
3823 i = m_clients.begin();
3824 i != m_clients.end(); ++i)
3826 // Get client and check that it is valid
3827 RemoteClient *client = i->second;
3828 assert(client->peer_id == i->first);
3829 if(client->serialization_version == SER_FMT_VER_INVALID)
3832 SendChatMessage(client->peer_id, message);
3836 void Server::SendPlayerHP(u16 peer_id)
3838 DSTACK(__FUNCTION_NAME);
3839 PlayerSAO *playersao = getPlayerSAO(peer_id);
3841 playersao->m_hp_not_sent = false;
3842 SendHP(m_con, peer_id, playersao->getHP());
3845 void Server::SendPlayerBreath(u16 peer_id)
3847 DSTACK(__FUNCTION_NAME);
3848 PlayerSAO *playersao = getPlayerSAO(peer_id);
3850 playersao->m_breath_not_sent = false;
3851 SendBreath(m_con, peer_id, playersao->getBreath());
3854 void Server::SendMovePlayer(u16 peer_id)
3856 DSTACK(__FUNCTION_NAME);
3857 Player *player = m_env->getPlayer(peer_id);
3860 std::ostringstream os(std::ios_base::binary);
3861 writeU16(os, TOCLIENT_MOVE_PLAYER);
3862 writeV3F1000(os, player->getPosition());
3863 writeF1000(os, player->getPitch());
3864 writeF1000(os, player->getYaw());
3867 v3f pos = player->getPosition();
3868 f32 pitch = player->getPitch();
3869 f32 yaw = player->getYaw();
3870 verbosestream<<"Server: Sending TOCLIENT_MOVE_PLAYER"
3871 <<" pos=("<<pos.X<<","<<pos.Y<<","<<pos.Z<<")"
3878 std::string s = os.str();
3879 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3881 m_con.Send(peer_id, 0, data, true);
3884 void Server::SendPlayerPrivileges(u16 peer_id)
3886 Player *player = m_env->getPlayer(peer_id);
3888 if(player->peer_id == PEER_ID_INEXISTENT)
3891 std::set<std::string> privs;
3892 m_script->getAuth(player->getName(), NULL, &privs);
3894 std::ostringstream os(std::ios_base::binary);
3895 writeU16(os, TOCLIENT_PRIVILEGES);
3896 writeU16(os, privs.size());
3897 for(std::set<std::string>::const_iterator i = privs.begin();
3898 i != privs.end(); i++){
3899 os<<serializeString(*i);
3903 std::string s = os.str();
3904 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3906 m_con.Send(peer_id, 0, data, true);
3909 void Server::SendPlayerInventoryFormspec(u16 peer_id)
3911 Player *player = m_env->getPlayer(peer_id);
3913 if(player->peer_id == PEER_ID_INEXISTENT)
3916 std::ostringstream os(std::ios_base::binary);
3917 writeU16(os, TOCLIENT_INVENTORY_FORMSPEC);
3918 os<<serializeLongString(player->inventory_formspec);
3921 std::string s = os.str();
3922 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3924 m_con.Send(peer_id, 0, data, true);
3927 s32 Server::playSound(const SimpleSoundSpec &spec,
3928 const ServerSoundParams ¶ms)
3930 // Find out initial position of sound
3931 bool pos_exists = false;
3932 v3f pos = params.getPos(m_env, &pos_exists);
3933 // If position is not found while it should be, cancel sound
3934 if(pos_exists != (params.type != ServerSoundParams::SSP_LOCAL))
3936 // Filter destination clients
3937 std::set<RemoteClient*> dst_clients;
3938 if(params.to_player != "")
3940 Player *player = m_env->getPlayer(params.to_player.c_str());
3942 infostream<<"Server::playSound: Player \""<<params.to_player
3943 <<"\" not found"<<std::endl;
3946 if(player->peer_id == PEER_ID_INEXISTENT){
3947 infostream<<"Server::playSound: Player \""<<params.to_player
3948 <<"\" not connected"<<std::endl;
3951 RemoteClient *client = getClient(player->peer_id);
3952 dst_clients.insert(client);
3956 for(std::map<u16, RemoteClient*>::iterator
3957 i = m_clients.begin(); i != m_clients.end(); ++i)
3959 RemoteClient *client = i->second;
3960 Player *player = m_env->getPlayer(client->peer_id);
3964 if(player->getPosition().getDistanceFrom(pos) >
3965 params.max_hear_distance)
3968 dst_clients.insert(client);
3971 if(dst_clients.size() == 0)
3974 s32 id = m_next_sound_id++;
3975 // The sound will exist as a reference in m_playing_sounds
3976 m_playing_sounds[id] = ServerPlayingSound();
3977 ServerPlayingSound &psound = m_playing_sounds[id];
3978 psound.params = params;
3979 for(std::set<RemoteClient*>::iterator i = dst_clients.begin();
3980 i != dst_clients.end(); i++)
3981 psound.clients.insert((*i)->peer_id);
3983 std::ostringstream os(std::ios_base::binary);
3984 writeU16(os, TOCLIENT_PLAY_SOUND);
3986 os<<serializeString(spec.name);
3987 writeF1000(os, spec.gain * params.gain);
3988 writeU8(os, params.type);
3989 writeV3F1000(os, pos);
3990 writeU16(os, params.object);
3991 writeU8(os, params.loop);
3993 std::string s = os.str();
3994 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3996 for(std::set<RemoteClient*>::iterator i = dst_clients.begin();
3997 i != dst_clients.end(); i++){
3999 m_con.Send((*i)->peer_id, 0, data, true);
4003 void Server::stopSound(s32 handle)
4005 // Get sound reference
4006 std::map<s32, ServerPlayingSound>::iterator i =
4007 m_playing_sounds.find(handle);
4008 if(i == m_playing_sounds.end())
4010 ServerPlayingSound &psound = i->second;
4012 std::ostringstream os(std::ios_base::binary);
4013 writeU16(os, TOCLIENT_STOP_SOUND);
4014 writeS32(os, handle);
4016 std::string s = os.str();
4017 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
4019 for(std::set<u16>::iterator i = psound.clients.begin();
4020 i != psound.clients.end(); i++){
4022 m_con.Send(*i, 0, data, true);
4024 // Remove sound reference
4025 m_playing_sounds.erase(i);
4028 void Server::sendRemoveNode(v3s16 p, u16 ignore_id,
4029 std::list<u16> *far_players, float far_d_nodes)
4031 float maxd = far_d_nodes*BS;
4032 v3f p_f = intToFloat(p, BS);
4036 SharedBuffer<u8> reply(replysize);
4037 writeU16(&reply[0], TOCLIENT_REMOVENODE);
4038 writeS16(&reply[2], p.X);
4039 writeS16(&reply[4], p.Y);
4040 writeS16(&reply[6], p.Z);
4042 for(std::map<u16, RemoteClient*>::iterator
4043 i = m_clients.begin();
4044 i != m_clients.end(); ++i)
4046 // Get client and check that it is valid
4047 RemoteClient *client = i->second;
4048 assert(client->peer_id == i->first);
4049 if(client->serialization_version == SER_FMT_VER_INVALID)
4052 // Don't send if it's the same one
4053 if(client->peer_id == ignore_id)
4059 Player *player = m_env->getPlayer(client->peer_id);
4062 // If player is far away, only set modified blocks not sent
4063 v3f player_pos = player->getPosition();
4064 if(player_pos.getDistanceFrom(p_f) > maxd)
4066 far_players->push_back(client->peer_id);
4073 m_con.Send(client->peer_id, 0, reply, true);
4077 void Server::sendAddNode(v3s16 p, MapNode n, u16 ignore_id,
4078 std::list<u16> *far_players, float far_d_nodes)
4080 float maxd = far_d_nodes*BS;
4081 v3f p_f = intToFloat(p, BS);
4083 for(std::map<u16, RemoteClient*>::iterator
4084 i = m_clients.begin();
4085 i != m_clients.end(); ++i)
4087 // Get client and check that it is valid
4088 RemoteClient *client = i->second;
4089 assert(client->peer_id == i->first);
4090 if(client->serialization_version == SER_FMT_VER_INVALID)
4093 // Don't send if it's the same one
4094 if(client->peer_id == ignore_id)
4100 Player *player = m_env->getPlayer(client->peer_id);
4103 // If player is far away, only set modified blocks not sent
4104 v3f player_pos = player->getPosition();
4105 if(player_pos.getDistanceFrom(p_f) > maxd)
4107 far_players->push_back(client->peer_id);
4114 u32 replysize = 8 + MapNode::serializedLength(client->serialization_version);
4115 SharedBuffer<u8> reply(replysize);
4116 writeU16(&reply[0], TOCLIENT_ADDNODE);
4117 writeS16(&reply[2], p.X);
4118 writeS16(&reply[4], p.Y);
4119 writeS16(&reply[6], p.Z);
4120 n.serialize(&reply[8], client->serialization_version);
4123 m_con.Send(client->peer_id, 0, reply, true);
4127 void Server::setBlockNotSent(v3s16 p)
4129 for(std::map<u16, RemoteClient*>::iterator
4130 i = m_clients.begin();
4131 i != m_clients.end(); ++i)
4133 RemoteClient *client = i->second;
4134 client->SetBlockNotSent(p);
4138 void Server::SendBlockNoLock(u16 peer_id, MapBlock *block, u8 ver, u16 net_proto_version)
4140 DSTACK(__FUNCTION_NAME);
4142 v3s16 p = block->getPos();
4146 bool completely_air = true;
4147 for(s16 z0=0; z0<MAP_BLOCKSIZE; z0++)
4148 for(s16 x0=0; x0<MAP_BLOCKSIZE; x0++)
4149 for(s16 y0=0; y0<MAP_BLOCKSIZE; y0++)
4151 if(block->getNodeNoEx(v3s16(x0,y0,z0)).d != CONTENT_AIR)
4153 completely_air = false;
4154 x0 = y0 = z0 = MAP_BLOCKSIZE; // Break out
4159 infostream<<"Server: Sending block ("<<p.X<<","<<p.Y<<","<<p.Z<<"): ";
4161 infostream<<"[completely air] ";
4162 infostream<<std::endl;
4166 Create a packet with the block in the right format
4169 std::ostringstream os(std::ios_base::binary);
4170 block->serialize(os, ver, false);
4171 block->serializeNetworkSpecific(os, net_proto_version);
4172 std::string s = os.str();
4173 SharedBuffer<u8> blockdata((u8*)s.c_str(), s.size());
4175 u32 replysize = 8 + blockdata.getSize();
4176 SharedBuffer<u8> reply(replysize);
4177 writeU16(&reply[0], TOCLIENT_BLOCKDATA);
4178 writeS16(&reply[2], p.X);
4179 writeS16(&reply[4], p.Y);
4180 writeS16(&reply[6], p.Z);
4181 memcpy(&reply[8], *blockdata, blockdata.getSize());
4183 /*infostream<<"Server: Sending block ("<<p.X<<","<<p.Y<<","<<p.Z<<")"
4184 <<": \tpacket size: "<<replysize<<std::endl;*/
4189 m_con.Send(peer_id, 1, reply, true);
4192 void Server::SendBlocks(float dtime)
4194 DSTACK(__FUNCTION_NAME);
4196 JMutexAutoLock envlock(m_env_mutex);
4197 JMutexAutoLock conlock(m_con_mutex);
4199 ScopeProfiler sp(g_profiler, "Server: sel and send blocks to clients");
4201 std::vector<PrioritySortedBlockTransfer> queue;
4203 s32 total_sending = 0;
4206 ScopeProfiler sp(g_profiler, "Server: selecting blocks for sending");
4208 for(std::map<u16, RemoteClient*>::iterator
4209 i = m_clients.begin();
4210 i != m_clients.end(); ++i)
4212 RemoteClient *client = i->second;
4213 assert(client->peer_id == i->first);
4215 // If definitions and textures have not been sent, don't
4216 // send MapBlocks either
4217 if(!client->definitions_sent)
4220 total_sending += client->SendingCount();
4222 if(client->serialization_version == SER_FMT_VER_INVALID)
4225 client->GetNextBlocks(this, dtime, queue);
4230 // Lowest priority number comes first.
4231 // Lowest is most important.
4232 std::sort(queue.begin(), queue.end());
4234 for(u32 i=0; i<queue.size(); i++)
4236 //TODO: Calculate limit dynamically
4237 if(total_sending >= g_settings->getS32
4238 ("max_simultaneous_block_sends_server_total"))
4241 PrioritySortedBlockTransfer q = queue[i];
4243 MapBlock *block = NULL;
4246 block = m_env->getMap().getBlockNoCreate(q.pos);
4248 catch(InvalidPositionException &e)
4253 RemoteClient *client = getClientNoEx(q.peer_id);
4259 SendBlockNoLock(q.peer_id, block, client->serialization_version, client->net_proto_version);
4261 client->SentBlock(q.pos);
4267 void Server::fillMediaCache()
4269 DSTACK(__FUNCTION_NAME);
4271 infostream<<"Server: Calculating media file checksums"<<std::endl;
4273 // Collect all media file paths
4274 std::list<std::string> paths;
4275 for(std::vector<ModSpec>::iterator i = m_mods.begin();
4276 i != m_mods.end(); i++){
4277 const ModSpec &mod = *i;
4278 paths.push_back(mod.path + DIR_DELIM + "textures");
4279 paths.push_back(mod.path + DIR_DELIM + "sounds");
4280 paths.push_back(mod.path + DIR_DELIM + "media");
4281 paths.push_back(mod.path + DIR_DELIM + "models");
4283 paths.push_back(porting::path_user + DIR_DELIM + "textures" + DIR_DELIM + "server");
4285 // Collect media file information from paths into cache
4286 for(std::list<std::string>::iterator i = paths.begin();
4287 i != paths.end(); i++)
4289 std::string mediapath = *i;
4290 std::vector<fs::DirListNode> dirlist = fs::GetDirListing(mediapath);
4291 for(u32 j=0; j<dirlist.size(); j++){
4292 if(dirlist[j].dir) // Ignode dirs
4294 std::string filename = dirlist[j].name;
4295 // If name contains illegal characters, ignore the file
4296 if(!string_allowed(filename, TEXTURENAME_ALLOWED_CHARS)){
4297 infostream<<"Server: ignoring illegal file name: \""
4298 <<filename<<"\""<<std::endl;
4301 // If name is not in a supported format, ignore it
4302 const char *supported_ext[] = {
4303 ".png", ".jpg", ".bmp", ".tga",
4304 ".pcx", ".ppm", ".psd", ".wal", ".rgb",
4306 ".x", ".b3d", ".md2", ".obj",
4309 if(removeStringEnd(filename, supported_ext) == ""){
4310 infostream<<"Server: ignoring unsupported file extension: \""
4311 <<filename<<"\""<<std::endl;
4314 // Ok, attempt to load the file and add to cache
4315 std::string filepath = mediapath + DIR_DELIM + filename;
4317 std::ifstream fis(filepath.c_str(), std::ios_base::binary);
4318 if(fis.good() == false){
4319 errorstream<<"Server::fillMediaCache(): Could not open \""
4320 <<filename<<"\" for reading"<<std::endl;
4323 std::ostringstream tmp_os(std::ios_base::binary);
4327 fis.read(buf, 1024);
4328 std::streamsize len = fis.gcount();
4329 tmp_os.write(buf, len);
4338 errorstream<<"Server::fillMediaCache(): Failed to read \""
4339 <<filename<<"\""<<std::endl;
4342 if(tmp_os.str().length() == 0){
4343 errorstream<<"Server::fillMediaCache(): Empty file \""
4344 <<filepath<<"\""<<std::endl;
4349 sha1.addBytes(tmp_os.str().c_str(), tmp_os.str().length());
4351 unsigned char *digest = sha1.getDigest();
4352 std::string sha1_base64 = base64_encode(digest, 20);
4353 std::string sha1_hex = hex_encode((char*)digest, 20);
4357 this->m_media[filename] = MediaInfo(filepath, sha1_base64);
4358 verbosestream<<"Server: "<<sha1_hex<<" is "<<filename<<std::endl;
4363 struct SendableMediaAnnouncement
4366 std::string sha1_digest;
4368 SendableMediaAnnouncement(const std::string name_="",
4369 const std::string sha1_digest_=""):
4371 sha1_digest(sha1_digest_)
4375 void Server::sendMediaAnnouncement(u16 peer_id)
4377 DSTACK(__FUNCTION_NAME);
4379 verbosestream<<"Server: Announcing files to id("<<peer_id<<")"
4382 std::list<SendableMediaAnnouncement> file_announcements;
4384 for(std::map<std::string, MediaInfo>::iterator i = m_media.begin();
4385 i != m_media.end(); i++){
4387 file_announcements.push_back(
4388 SendableMediaAnnouncement(i->first, i->second.sha1_digest));
4392 std::ostringstream os(std::ios_base::binary);
4400 u16 length of sha1_digest
4405 writeU16(os, TOCLIENT_ANNOUNCE_MEDIA);
4406 writeU16(os, file_announcements.size());
4408 for(std::list<SendableMediaAnnouncement>::iterator
4409 j = file_announcements.begin();
4410 j != file_announcements.end(); ++j){
4411 os<<serializeString(j->name);
4412 os<<serializeString(j->sha1_digest);
4414 os<<serializeString(g_settings->get("remote_media"));
4417 std::string s = os.str();
4418 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
4421 m_con.Send(peer_id, 0, data, true);
4424 struct SendableMedia
4430 SendableMedia(const std::string &name_="", const std::string path_="",
4431 const std::string &data_=""):
4438 void Server::sendRequestedMedia(u16 peer_id,
4439 const std::list<MediaRequest> &tosend)
4441 DSTACK(__FUNCTION_NAME);
4443 verbosestream<<"Server::sendRequestedMedia(): "
4444 <<"Sending files to client"<<std::endl;
4448 // Put 5kB in one bunch (this is not accurate)
4449 u32 bytes_per_bunch = 5000;
4451 std::vector< std::list<SendableMedia> > file_bunches;
4452 file_bunches.push_back(std::list<SendableMedia>());
4454 u32 file_size_bunch_total = 0;
4456 for(std::list<MediaRequest>::const_iterator i = tosend.begin();
4457 i != tosend.end(); ++i)
4459 if(m_media.find(i->name) == m_media.end()){
4460 errorstream<<"Server::sendRequestedMedia(): Client asked for "
4461 <<"unknown file \""<<(i->name)<<"\""<<std::endl;
4465 //TODO get path + name
4466 std::string tpath = m_media[(*i).name].path;
4469 std::ifstream fis(tpath.c_str(), std::ios_base::binary);
4470 if(fis.good() == false){
4471 errorstream<<"Server::sendRequestedMedia(): Could not open \""
4472 <<tpath<<"\" for reading"<<std::endl;
4475 std::ostringstream tmp_os(std::ios_base::binary);
4479 fis.read(buf, 1024);
4480 std::streamsize len = fis.gcount();
4481 tmp_os.write(buf, len);
4482 file_size_bunch_total += len;
4491 errorstream<<"Server::sendRequestedMedia(): Failed to read \""
4492 <<(*i).name<<"\""<<std::endl;
4495 /*infostream<<"Server::sendRequestedMedia(): Loaded \""
4496 <<tname<<"\""<<std::endl;*/
4498 file_bunches[file_bunches.size()-1].push_back(
4499 SendableMedia((*i).name, tpath, tmp_os.str()));
4501 // Start next bunch if got enough data
4502 if(file_size_bunch_total >= bytes_per_bunch){
4503 file_bunches.push_back(std::list<SendableMedia>());
4504 file_size_bunch_total = 0;
4509 /* Create and send packets */
4511 u32 num_bunches = file_bunches.size();
4512 for(u32 i=0; i<num_bunches; i++)
4514 std::ostringstream os(std::ios_base::binary);
4518 u16 total number of texture bunches
4519 u16 index of this bunch
4520 u32 number of files in this bunch
4529 writeU16(os, TOCLIENT_MEDIA);
4530 writeU16(os, num_bunches);
4532 writeU32(os, file_bunches[i].size());
4534 for(std::list<SendableMedia>::iterator
4535 j = file_bunches[i].begin();
4536 j != file_bunches[i].end(); ++j){
4537 os<<serializeString(j->name);
4538 os<<serializeLongString(j->data);
4542 std::string s = os.str();
4543 verbosestream<<"Server::sendRequestedMedia(): bunch "
4544 <<i<<"/"<<num_bunches
4545 <<" files="<<file_bunches[i].size()
4546 <<" size=" <<s.size()<<std::endl;
4547 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
4549 m_con.Send(peer_id, 0, data, true);
4553 void Server::sendDetachedInventory(const std::string &name, u16 peer_id)
4555 if(m_detached_inventories.count(name) == 0){
4556 errorstream<<__FUNCTION_NAME<<": \""<<name<<"\" not found"<<std::endl;
4559 Inventory *inv = m_detached_inventories[name];
4561 std::ostringstream os(std::ios_base::binary);
4562 writeU16(os, TOCLIENT_DETACHED_INVENTORY);
4563 os<<serializeString(name);
4567 std::string s = os.str();
4568 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
4570 m_con.Send(peer_id, 0, data, true);
4573 void Server::sendDetachedInventoryToAll(const std::string &name)
4575 DSTACK(__FUNCTION_NAME);
4577 for(std::map<u16, RemoteClient*>::iterator
4578 i = m_clients.begin();
4579 i != m_clients.end(); ++i){
4580 RemoteClient *client = i->second;
4581 sendDetachedInventory(name, client->peer_id);
4585 void Server::sendDetachedInventories(u16 peer_id)
4587 DSTACK(__FUNCTION_NAME);
4589 for(std::map<std::string, Inventory*>::iterator
4590 i = m_detached_inventories.begin();
4591 i != m_detached_inventories.end(); i++){
4592 const std::string &name = i->first;
4593 //Inventory *inv = i->second;
4594 sendDetachedInventory(name, peer_id);
4602 void Server::DiePlayer(u16 peer_id)
4604 DSTACK(__FUNCTION_NAME);
4606 PlayerSAO *playersao = getPlayerSAO(peer_id);
4609 infostream<<"Server::DiePlayer(): Player "
4610 <<playersao->getPlayer()->getName()
4611 <<" dies"<<std::endl;
4613 playersao->setHP(0);
4615 // Trigger scripted stuff
4616 m_script->on_dieplayer(playersao);
4618 SendPlayerHP(peer_id);
4619 SendDeathscreen(m_con, peer_id, false, v3f(0,0,0));
4622 void Server::RespawnPlayer(u16 peer_id)
4624 DSTACK(__FUNCTION_NAME);
4626 PlayerSAO *playersao = getPlayerSAO(peer_id);
4629 infostream<<"Server::RespawnPlayer(): Player "
4630 <<playersao->getPlayer()->getName()
4631 <<" respawns"<<std::endl;
4633 playersao->setHP(PLAYER_MAX_HP);
4635 bool repositioned = m_script->on_respawnplayer(playersao);
4637 v3f pos = findSpawnPos(m_env->getServerMap());
4638 playersao->setPos(pos);
4642 void Server::DenyAccess(u16 peer_id, const std::wstring &reason)
4644 DSTACK(__FUNCTION_NAME);
4646 SendAccessDenied(m_con, peer_id, reason);
4648 RemoteClient *client = getClientNoEx(peer_id);
4650 client->denied = true;
4652 // If there are way too many clients, get rid of denied new ones immediately
4653 if(m_clients.size() > 2 * g_settings->getU16("max_users")){
4654 // Delete peer to stop sending it data
4655 m_con.DeletePeer(peer_id);
4656 // Delete client also to stop block sends and other stuff
4657 DeleteClient(peer_id, CDR_DENY);
4661 void Server::DeleteClient(u16 peer_id, ClientDeletionReason reason)
4663 DSTACK(__FUNCTION_NAME);
4666 std::map<u16, RemoteClient*>::iterator n;
4667 n = m_clients.find(peer_id);
4668 // The client may not exist; clients are immediately removed if their
4669 // access is denied, and this event occurs later then.
4670 if(n == m_clients.end())
4674 Mark objects to be not known by the client
4676 RemoteClient *client = n->second;
4678 for(std::set<u16>::iterator
4679 i = client->m_known_objects.begin();
4680 i != client->m_known_objects.end(); ++i)
4684 ServerActiveObject* obj = m_env->getActiveObject(id);
4686 if(obj && obj->m_known_by_count > 0)
4687 obj->m_known_by_count--;
4691 Clear references to playing sounds
4693 for(std::map<s32, ServerPlayingSound>::iterator
4694 i = m_playing_sounds.begin();
4695 i != m_playing_sounds.end();)
4697 ServerPlayingSound &psound = i->second;
4698 psound.clients.erase(peer_id);
4699 if(psound.clients.size() == 0)
4700 m_playing_sounds.erase(i++);
4705 Player *player = m_env->getPlayer(peer_id);
4707 // Collect information about leaving in chat
4708 std::wstring message;
4710 if(player != NULL && reason != CDR_DENY)
4712 std::wstring name = narrow_to_wide(player->getName());
4715 message += L" left the game.";
4716 if(reason == CDR_TIMEOUT)
4717 message += L" (timed out)";
4721 /* Run scripts and remove from environment */
4725 PlayerSAO *playersao = player->getPlayerSAO();
4728 m_script->on_leaveplayer(playersao);
4730 playersao->disconnected();
4738 if(player != NULL && reason != CDR_DENY)
4740 std::ostringstream os(std::ios_base::binary);
4741 for(std::map<u16, RemoteClient*>::iterator
4742 i = m_clients.begin();
4743 i != m_clients.end(); ++i)
4745 RemoteClient *client = i->second;
4746 assert(client->peer_id == i->first);
4747 if(client->serialization_version == SER_FMT_VER_INVALID)
4750 Player *player = m_env->getPlayer(client->peer_id);
4753 // Get name of player
4754 os<<player->getName()<<" ";
4757 actionstream<<player->getName()<<" "
4758 <<(reason==CDR_TIMEOUT?"times out.":"leaves game.")
4759 <<" List of players: "<<os.str()<<std::endl;
4764 delete m_clients[peer_id];
4765 m_clients.erase(peer_id);
4767 // Send player info to all remaining clients
4768 //SendPlayerInfos();
4770 // Send leave chat message to all remaining clients
4771 if(message.length() != 0)
4772 BroadcastChatMessage(message);
4775 void Server::UpdateCrafting(u16 peer_id)
4777 DSTACK(__FUNCTION_NAME);
4779 Player* player = m_env->getPlayer(peer_id);
4782 // Get a preview for crafting
4784 getCraftingResult(&player->inventory, preview, false, this);
4786 // Put the new preview in
4787 InventoryList *plist = player->inventory.getList("craftpreview");
4789 assert(plist->getSize() >= 1);
4790 plist->changeItem(0, preview);
4793 RemoteClient* Server::getClient(u16 peer_id)
4795 RemoteClient *client = getClientNoEx(peer_id);
4797 throw ClientNotFoundException("Client not found");
4800 RemoteClient* Server::getClientNoEx(u16 peer_id)
4802 std::map<u16, RemoteClient*>::iterator n;
4803 n = m_clients.find(peer_id);
4804 // The client may not exist; clients are immediately removed if their
4805 // access is denied, and this event occurs later then.
4806 if(n == m_clients.end())
4811 std::wstring Server::getStatusString()
4813 std::wostringstream os(std::ios_base::binary);
4816 os<<L"version="<<narrow_to_wide(VERSION_STRING);
4818 os<<L", uptime="<<m_uptime.get();
4820 os<<L", max_lag="<<m_env->getMaxLagEstimate();
4821 // Information about clients
4822 std::map<u16, RemoteClient*>::iterator i;
4825 for(i = m_clients.begin(), first = true;
4826 i != m_clients.end(); ++i)
4828 // Get client and check that it is valid
4829 RemoteClient *client = i->second;
4830 assert(client->peer_id == i->first);
4831 if(client->serialization_version == SER_FMT_VER_INVALID)
4834 Player *player = m_env->getPlayer(client->peer_id);
4835 // Get name of player
4836 std::wstring name = L"unknown";
4838 name = narrow_to_wide(player->getName());
4839 // Add name to information string
4847 if(((ServerMap*)(&m_env->getMap()))->isSavingEnabled() == false)
4848 os<<std::endl<<L"# Server: "<<" WARNING: Map saving is disabled.";
4849 if(g_settings->get("motd") != "")
4850 os<<std::endl<<L"# Server: "<<narrow_to_wide(g_settings->get("motd"));
4854 std::set<std::string> Server::getPlayerEffectivePrivs(const std::string &name)
4856 std::set<std::string> privs;
4857 m_script->getAuth(name, NULL, &privs);
4861 bool Server::checkPriv(const std::string &name, const std::string &priv)
4863 std::set<std::string> privs = getPlayerEffectivePrivs(name);
4864 return (privs.count(priv) != 0);
4867 void Server::reportPrivsModified(const std::string &name)
4870 for(std::map<u16, RemoteClient*>::iterator
4871 i = m_clients.begin();
4872 i != m_clients.end(); ++i){
4873 RemoteClient *client = i->second;
4874 Player *player = m_env->getPlayer(client->peer_id);
4875 reportPrivsModified(player->getName());
4878 Player *player = m_env->getPlayer(name.c_str());
4881 SendPlayerPrivileges(player->peer_id);
4882 PlayerSAO *sao = player->getPlayerSAO();
4885 sao->updatePrivileges(
4886 getPlayerEffectivePrivs(name),
4891 void Server::reportInventoryFormspecModified(const std::string &name)
4893 Player *player = m_env->getPlayer(name.c_str());
4896 SendPlayerInventoryFormspec(player->peer_id);
4899 // Saves g_settings to configpath given at initialization
4900 void Server::saveConfig()
4902 if(m_path_config != "")
4903 g_settings->updateConfigFile(m_path_config.c_str());
4906 void Server::notifyPlayer(const char *name, const std::wstring msg, const bool prepend = true)
4908 Player *player = m_env->getPlayer(name);
4912 SendChatMessage(player->peer_id, std::wstring(L"Server -!- ")+msg);
4914 SendChatMessage(player->peer_id, msg);
4917 bool Server::showFormspec(const char *playername, const std::string &formspec, const std::string &formname)
4919 Player *player = m_env->getPlayer(playername);
4923 infostream<<"showFormspec: couldn't find player:"<<playername<<std::endl;
4927 SendShowFormspecMessage(player->peer_id, formspec, formname);
4931 u32 Server::hudAdd(Player *player, HudElement *form) {
4935 u32 id = hud_get_free_id(player);
4936 if (id < player->hud.size())
4937 player->hud[id] = form;
4939 player->hud.push_back(form);
4941 SendHUDAdd(player->peer_id, id, form);
4945 bool Server::hudRemove(Player *player, u32 id) {
4946 if (!player || id >= player->hud.size() || !player->hud[id])
4949 delete player->hud[id];
4950 player->hud[id] = NULL;
4952 SendHUDRemove(player->peer_id, id);
4956 bool Server::hudChange(Player *player, u32 id, HudElementStat stat, void *data) {
4960 SendHUDChange(player->peer_id, id, stat, data);
4964 bool Server::hudSetFlags(Player *player, u32 flags, u32 mask) {
4968 SendHUDSetFlags(player->peer_id, flags, mask);
4972 bool Server::hudSetHotbarItemcount(Player *player, s32 hotbar_itemcount) {
4975 if (hotbar_itemcount <= 0 || hotbar_itemcount > HUD_HOTBAR_ITEMCOUNT_MAX)
4978 std::ostringstream os(std::ios::binary);
4979 writeS32(os, hotbar_itemcount);
4980 SendHUDSetParam(player->peer_id, HUD_PARAM_HOTBAR_ITEMCOUNT, os.str());
4984 void Server::notifyPlayers(const std::wstring msg)
4986 BroadcastChatMessage(msg);
4989 void Server::spawnParticle(const char *playername, v3f pos,
4990 v3f velocity, v3f acceleration,
4991 float expirationtime, float size, bool
4992 collisiondetection, std::string texture)
4994 Player *player = m_env->getPlayer(playername);
4997 SendSpawnParticle(player->peer_id, pos, velocity, acceleration,
4998 expirationtime, size, collisiondetection, texture);
5001 void Server::spawnParticleAll(v3f pos, v3f velocity, v3f acceleration,
5002 float expirationtime, float size,
5003 bool collisiondetection, std::string texture)
5005 SendSpawnParticleAll(pos, velocity, acceleration,
5006 expirationtime, size, collisiondetection, texture);
5009 u32 Server::addParticleSpawner(const char *playername,
5010 u16 amount, float spawntime,
5011 v3f minpos, v3f maxpos,
5012 v3f minvel, v3f maxvel,
5013 v3f minacc, v3f maxacc,
5014 float minexptime, float maxexptime,
5015 float minsize, float maxsize,
5016 bool collisiondetection, std::string texture)
5018 Player *player = m_env->getPlayer(playername);
5023 for(;;) // look for unused particlespawner id
5026 if (std::find(m_particlespawner_ids.begin(),
5027 m_particlespawner_ids.end(), id)
5028 == m_particlespawner_ids.end())
5030 m_particlespawner_ids.push_back(id);
5035 SendAddParticleSpawner(player->peer_id, amount, spawntime,
5036 minpos, maxpos, minvel, maxvel, minacc, maxacc,
5037 minexptime, maxexptime, minsize, maxsize,
5038 collisiondetection, texture, id);
5043 u32 Server::addParticleSpawnerAll(u16 amount, float spawntime,
5044 v3f minpos, v3f maxpos,
5045 v3f minvel, v3f maxvel,
5046 v3f minacc, v3f maxacc,
5047 float minexptime, float maxexptime,
5048 float minsize, float maxsize,
5049 bool collisiondetection, std::string texture)
5052 for(;;) // look for unused particlespawner id
5055 if (std::find(m_particlespawner_ids.begin(),
5056 m_particlespawner_ids.end(), id)
5057 == m_particlespawner_ids.end())
5059 m_particlespawner_ids.push_back(id);
5064 SendAddParticleSpawnerAll(amount, spawntime,
5065 minpos, maxpos, minvel, maxvel, minacc, maxacc,
5066 minexptime, maxexptime, minsize, maxsize,
5067 collisiondetection, texture, id);
5072 void Server::deleteParticleSpawner(const char *playername, u32 id)
5074 Player *player = m_env->getPlayer(playername);
5078 m_particlespawner_ids.erase(
5079 std::remove(m_particlespawner_ids.begin(),
5080 m_particlespawner_ids.end(), id),
5081 m_particlespawner_ids.end());
5082 SendDeleteParticleSpawner(player->peer_id, id);
5085 void Server::deleteParticleSpawnerAll(u32 id)
5087 m_particlespawner_ids.erase(
5088 std::remove(m_particlespawner_ids.begin(),
5089 m_particlespawner_ids.end(), id),
5090 m_particlespawner_ids.end());
5091 SendDeleteParticleSpawnerAll(id);
5094 void Server::queueBlockEmerge(v3s16 blockpos, bool allow_generate)
5096 m_emerge->enqueueBlockEmerge(PEER_ID_INEXISTENT, blockpos, allow_generate);
5099 Inventory* Server::createDetachedInventory(const std::string &name)
5101 if(m_detached_inventories.count(name) > 0){
5102 infostream<<"Server clearing detached inventory \""<<name<<"\""<<std::endl;
5103 delete m_detached_inventories[name];
5105 infostream<<"Server creating detached inventory \""<<name<<"\""<<std::endl;
5107 Inventory *inv = new Inventory(m_itemdef);
5109 m_detached_inventories[name] = inv;
5110 sendDetachedInventoryToAll(name);
5117 BoolScopeSet(bool *dst, bool val):
5120 m_orig_state = *m_dst;
5125 *m_dst = m_orig_state;
5132 // actions: time-reversed list
5133 // Return value: success/failure
5134 bool Server::rollbackRevertActions(const std::list<RollbackAction> &actions,
5135 std::list<std::string> *log)
5137 infostream<<"Server::rollbackRevertActions(len="<<actions.size()<<")"<<std::endl;
5138 ServerMap *map = (ServerMap*)(&m_env->getMap());
5139 // Disable rollback report sink while reverting
5140 BoolScopeSet rollback_scope_disable(&m_rollback_sink_enabled, false);
5142 // Fail if no actions to handle
5143 if(actions.empty()){
5144 log->push_back("Nothing to do.");
5151 for(std::list<RollbackAction>::const_iterator
5152 i = actions.begin();
5153 i != actions.end(); i++)
5155 const RollbackAction &action = *i;
5157 bool success = action.applyRevert(map, this, this);
5160 std::ostringstream os;
5161 os<<"Revert of step ("<<num_tried<<") "<<action.toString()<<" failed";
5162 infostream<<"Map::rollbackRevertActions(): "<<os.str()<<std::endl;
5164 log->push_back(os.str());
5166 std::ostringstream os;
5167 os<<"Successfully reverted step ("<<num_tried<<") "<<action.toString();
5168 infostream<<"Map::rollbackRevertActions(): "<<os.str()<<std::endl;
5170 log->push_back(os.str());
5174 infostream<<"Map::rollbackRevertActions(): "<<num_failed<<"/"<<num_tried
5175 <<" failed"<<std::endl;
5177 // Call it done if less than half failed
5178 return num_failed <= num_tried/2;
5181 // IGameDef interface
5183 IItemDefManager* Server::getItemDefManager()
5187 INodeDefManager* Server::getNodeDefManager()
5191 ICraftDefManager* Server::getCraftDefManager()
5195 ITextureSource* Server::getTextureSource()
5199 IShaderSource* Server::getShaderSource()
5203 u16 Server::allocateUnknownNodeId(const std::string &name)
5205 return m_nodedef->allocateDummy(name);
5207 ISoundManager* Server::getSoundManager()
5209 return &dummySoundManager;
5211 MtEventManager* Server::getEventManager()
5215 IRollbackReportSink* Server::getRollbackReportSink()
5217 if(!m_enable_rollback_recording)
5219 if(!m_rollback_sink_enabled)
5224 IWritableItemDefManager* Server::getWritableItemDefManager()
5228 IWritableNodeDefManager* Server::getWritableNodeDefManager()
5232 IWritableCraftDefManager* Server::getWritableCraftDefManager()
5237 const ModSpec* Server::getModSpec(const std::string &modname)
5239 for(std::vector<ModSpec>::iterator i = m_mods.begin();
5240 i != m_mods.end(); i++){
5241 const ModSpec &mod = *i;
5242 if(mod.name == modname)
5247 void Server::getModNames(std::list<std::string> &modlist)
5249 for(std::vector<ModSpec>::iterator i = m_mods.begin(); i != m_mods.end(); i++)
5251 modlist.push_back(i->name);
5254 std::string Server::getBuiltinLuaPath()
5256 return porting::path_share + DIR_DELIM + "builtin";
5259 v3f findSpawnPos(ServerMap &map)
5261 //return v3f(50,50,50)*BS;
5266 nodepos = v2s16(0,0);
5271 s16 water_level = map.m_mgparams->water_level;
5273 // Try to find a good place a few times
5274 for(s32 i=0; i<1000; i++)
5277 // We're going to try to throw the player to this position
5278 v2s16 nodepos2d = v2s16(
5279 -range + (myrand() % (range * 2)),
5280 -range + (myrand() % (range * 2)));
5282 // Get ground height at point
5283 s16 groundheight = map.findGroundLevel(nodepos2d);
5284 if (groundheight <= water_level) // Don't go underwater
5286 if (groundheight > water_level + 6) // Don't go to high places
5289 nodepos = v3s16(nodepos2d.X, groundheight, nodepos2d.Y);
5290 bool is_good = false;
5292 for (s32 i = 0; i < 10; i++) {
5293 v3s16 blockpos = getNodeBlockPos(nodepos);
5294 map.emergeBlock(blockpos, true);
5295 content_t c = map.getNodeNoEx(nodepos).getContent();
5296 if (c == CONTENT_AIR || c == CONTENT_IGNORE) {
5298 if (air_count >= 2){
5306 // Found a good place
5307 //infostream<<"Searched through "<<i<<" places."<<std::endl;
5313 return intToFloat(nodepos, BS);
5316 PlayerSAO* Server::emergePlayer(const char *name, u16 peer_id)
5318 RemotePlayer *player = NULL;
5319 bool newplayer = false;
5322 Try to get an existing player
5324 player = static_cast<RemotePlayer*>(m_env->getPlayer(name));
5326 // If player is already connected, cancel
5327 if(player != NULL && player->peer_id != 0)
5329 infostream<<"emergePlayer(): Player already connected"<<std::endl;
5334 If player with the wanted peer_id already exists, cancel.
5336 if(m_env->getPlayer(peer_id) != NULL)
5338 infostream<<"emergePlayer(): Player with wrong name but same"
5339 " peer_id already exists"<<std::endl;
5344 Create a new player if it doesn't exist yet
5349 player = new RemotePlayer(this);
5350 player->updateName(name);
5352 /* Set player position */
5353 infostream<<"Server: Finding spawn place for player \""
5354 <<name<<"\""<<std::endl;
5355 v3f pos = findSpawnPos(m_env->getServerMap());
5356 player->setPosition(pos);
5358 /* Add player to environment */
5359 m_env->addPlayer(player);
5363 Create a new player active object
5365 PlayerSAO *playersao = new PlayerSAO(m_env, player, peer_id,
5366 getPlayerEffectivePrivs(player->getName()),
5369 /* Clean up old HUD elements from previous sessions */
5370 player->hud.clear();
5372 /* Add object to environment */
5373 m_env->addActiveObject(playersao);
5377 m_script->on_newplayer(playersao);
5379 m_script->on_joinplayer(playersao);
5384 void Server::handlePeerChange(PeerChange &c)
5386 JMutexAutoLock envlock(m_env_mutex);
5387 JMutexAutoLock conlock(m_con_mutex);
5389 if(c.type == PEER_ADDED)
5396 std::map<u16, RemoteClient*>::iterator n;
5397 n = m_clients.find(c.peer_id);
5398 // The client shouldn't already exist
5399 assert(n == m_clients.end());
5402 RemoteClient *client = new RemoteClient();
5403 client->peer_id = c.peer_id;
5404 m_clients[client->peer_id] = client;
5407 else if(c.type == PEER_REMOVED)
5413 DeleteClient(c.peer_id, c.timeout?CDR_TIMEOUT:CDR_LEAVE);
5422 void Server::handlePeerChanges()
5424 while(m_peer_change_queue.size() > 0)
5426 PeerChange c = m_peer_change_queue.pop_front();
5428 verbosestream<<"Server: Handling peer change: "
5429 <<"id="<<c.peer_id<<", timeout="<<c.timeout
5432 handlePeerChange(c);
5436 void dedicated_server_loop(Server &server, bool &kill)
5438 DSTACK(__FUNCTION_NAME);
5440 verbosestream<<"dedicated_server_loop()"<<std::endl;
5442 IntervalLimiter m_profiler_interval;
5446 float steplen = g_settings->getFloat("dedicated_server_step");
5447 // This is kind of a hack but can be done like this
5448 // because server.step() is very light
5450 ScopeProfiler sp(g_profiler, "dedicated server sleep");
5451 sleep_ms((int)(steplen*1000.0));
5453 server.step(steplen);
5455 if(server.getShutdownRequested() || kill)
5457 infostream<<"Dedicated server quitting"<<std::endl;
5459 if(g_settings->getBool("server_announce") == true)
5460 ServerList::sendAnnounce("delete");
5468 float profiler_print_interval =
5469 g_settings->getFloat("profiler_print_interval");
5470 if(profiler_print_interval != 0)
5472 if(m_profiler_interval.step(steplen, profiler_print_interval))
5474 infostream<<"Profiler:"<<std::endl;
5475 g_profiler->print(infostream);
5476 g_profiler->clear();