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 // If net_proto_version is set, this client has already been handled
1814 if(getClient(peer_id)->net_proto_version != 0){
1815 verbosestream<<"Server: Ignoring multiple TOSERVER_INITs from "
1816 <<addr_s<<" (peer_id="<<peer_id<<")"<<std::endl;
1820 verbosestream<<"Server: Got TOSERVER_INIT from "<<addr_s<<" (peer_id="
1821 <<peer_id<<")"<<std::endl;
1823 // Do not allow multiple players in simple singleplayer mode.
1824 // This isn't a perfect way to do it, but will suffice for now.
1825 if(m_simple_singleplayer_mode && m_clients.size() > 1){
1826 infostream<<"Server: Not allowing another client ("<<addr_s
1827 <<") to connect in simple singleplayer mode"<<std::endl;
1828 DenyAccess(peer_id, L"Running in simple singleplayer mode.");
1832 // First byte after command is maximum supported
1833 // serialization version
1834 u8 client_max = data[2];
1835 u8 our_max = SER_FMT_VER_HIGHEST_READ;
1836 // Use the highest version supported by both
1837 u8 deployed = std::min(client_max, our_max);
1838 // If it's lower than the lowest supported, give up.
1839 if(deployed < SER_FMT_VER_LOWEST)
1840 deployed = SER_FMT_VER_INVALID;
1842 //peer->serialization_version = deployed;
1843 getClient(peer_id)->pending_serialization_version = deployed;
1845 if(deployed == SER_FMT_VER_INVALID)
1847 actionstream<<"Server: A mismatched client tried to connect from "
1848 <<addr_s<<std::endl;
1849 infostream<<"Server: Cannot negotiate serialization version with "
1850 <<addr_s<<std::endl;
1851 DenyAccess(peer_id, std::wstring(
1852 L"Your client's version is not supported.\n"
1853 L"Server version is ")
1854 + narrow_to_wide(VERSION_STRING) + L"."
1860 Read and check network protocol version
1863 u16 min_net_proto_version = 0;
1864 if(datasize >= 2+1+PLAYERNAME_SIZE+PASSWORD_SIZE+2)
1865 min_net_proto_version = readU16(&data[2+1+PLAYERNAME_SIZE+PASSWORD_SIZE]);
1867 // Use same version as minimum and maximum if maximum version field
1868 // doesn't exist (backwards compatibility)
1869 u16 max_net_proto_version = min_net_proto_version;
1870 if(datasize >= 2+1+PLAYERNAME_SIZE+PASSWORD_SIZE+2+2)
1871 max_net_proto_version = readU16(&data[2+1+PLAYERNAME_SIZE+PASSWORD_SIZE+2]);
1873 // Start with client's maximum version
1874 u16 net_proto_version = max_net_proto_version;
1876 // Figure out a working version if it is possible at all
1877 if(max_net_proto_version >= SERVER_PROTOCOL_VERSION_MIN ||
1878 min_net_proto_version <= SERVER_PROTOCOL_VERSION_MAX)
1880 // If maximum is larger than our maximum, go with our maximum
1881 if(max_net_proto_version > SERVER_PROTOCOL_VERSION_MAX)
1882 net_proto_version = SERVER_PROTOCOL_VERSION_MAX;
1883 // Else go with client's maximum
1885 net_proto_version = max_net_proto_version;
1888 verbosestream<<"Server: "<<addr_s<<": Protocol version: min: "
1889 <<min_net_proto_version<<", max: "<<max_net_proto_version
1890 <<", chosen: "<<net_proto_version<<std::endl;
1892 getClient(peer_id)->net_proto_version = net_proto_version;
1894 if(net_proto_version < SERVER_PROTOCOL_VERSION_MIN ||
1895 net_proto_version > SERVER_PROTOCOL_VERSION_MAX)
1897 actionstream<<"Server: A mismatched client tried to connect from "
1898 <<addr_s<<std::endl;
1899 DenyAccess(peer_id, std::wstring(
1900 L"Your client's version is not supported.\n"
1901 L"Server version is ")
1902 + narrow_to_wide(VERSION_STRING) + L",\n"
1903 + L"server's PROTOCOL_VERSION is "
1904 + narrow_to_wide(itos(SERVER_PROTOCOL_VERSION_MIN))
1906 + narrow_to_wide(itos(SERVER_PROTOCOL_VERSION_MAX))
1907 + L", client's PROTOCOL_VERSION is "
1908 + narrow_to_wide(itos(min_net_proto_version))
1910 + narrow_to_wide(itos(max_net_proto_version))
1915 if(g_settings->getBool("strict_protocol_version_checking"))
1917 if(net_proto_version != LATEST_PROTOCOL_VERSION)
1919 actionstream<<"Server: A mismatched (strict) client tried to "
1920 <<"connect from "<<addr_s<<std::endl;
1921 DenyAccess(peer_id, std::wstring(
1922 L"Your client's version is not supported.\n"
1923 L"Server version is ")
1924 + narrow_to_wide(VERSION_STRING) + L",\n"
1925 + L"server's PROTOCOL_VERSION (strict) is "
1926 + narrow_to_wide(itos(LATEST_PROTOCOL_VERSION))
1927 + L", client's PROTOCOL_VERSION is "
1928 + narrow_to_wide(itos(min_net_proto_version))
1930 + narrow_to_wide(itos(max_net_proto_version))
1941 char playername[PLAYERNAME_SIZE];
1942 for(u32 i=0; i<PLAYERNAME_SIZE-1; i++)
1944 playername[i] = data[3+i];
1946 playername[PLAYERNAME_SIZE-1] = 0;
1948 if(playername[0]=='\0')
1950 actionstream<<"Server: Player with an empty name "
1951 <<"tried to connect from "<<addr_s<<std::endl;
1952 DenyAccess(peer_id, L"Empty name");
1956 if(string_allowed(playername, PLAYERNAME_ALLOWED_CHARS)==false)
1958 actionstream<<"Server: Player with an invalid name "
1959 <<"tried to connect from "<<addr_s<<std::endl;
1960 DenyAccess(peer_id, L"Name contains unallowed characters");
1964 if(!isSingleplayer() && strcasecmp(playername, "singleplayer") == 0)
1966 actionstream<<"Server: Player with the name \"singleplayer\" "
1967 <<"tried to connect from "<<addr_s<<std::endl;
1968 DenyAccess(peer_id, L"Name is not allowed");
1972 infostream<<"Server: New connection: \""<<playername<<"\" from "
1973 <<addr_s<<" (peer_id="<<peer_id<<")"<<std::endl;
1976 char given_password[PASSWORD_SIZE];
1977 if(datasize < 2+1+PLAYERNAME_SIZE+PASSWORD_SIZE)
1979 // old version - assume blank password
1980 given_password[0] = 0;
1984 for(u32 i=0; i<PASSWORD_SIZE-1; i++)
1986 given_password[i] = data[23+i];
1988 given_password[PASSWORD_SIZE-1] = 0;
1991 if(!base64_is_valid(given_password)){
1992 actionstream<<"Server: "<<playername
1993 <<" supplied invalid password hash"<<std::endl;
1994 DenyAccess(peer_id, L"Invalid password hash");
1998 // Enforce user limit.
1999 // Don't enforce for users that have some admin right
2000 if(m_clients.size() >= g_settings->getU16("max_users") &&
2001 !checkPriv(playername, "server") &&
2002 !checkPriv(playername, "ban") &&
2003 !checkPriv(playername, "privs") &&
2004 !checkPriv(playername, "password") &&
2005 playername != g_settings->get("name"))
2007 actionstream<<"Server: "<<playername<<" tried to join, but there"
2008 <<" are already max_users="
2009 <<g_settings->getU16("max_users")<<" players."<<std::endl;
2010 DenyAccess(peer_id, L"Too many users.");
2014 std::string checkpwd; // Password hash to check against
2015 bool has_auth = m_script->getAuth(playername, &checkpwd, NULL);
2017 // If no authentication info exists for user, create it
2019 if(!isSingleplayer() &&
2020 g_settings->getBool("disallow_empty_password") &&
2021 std::string(given_password) == ""){
2022 actionstream<<"Server: "<<playername
2023 <<" supplied empty password"<<std::endl;
2024 DenyAccess(peer_id, L"Empty passwords are "
2025 L"disallowed. Set a password and try again.");
2028 std::wstring raw_default_password =
2029 narrow_to_wide(g_settings->get("default_password"));
2030 std::string initial_password =
2031 translatePassword(playername, raw_default_password);
2033 // If default_password is empty, allow any initial password
2034 if (raw_default_password.length() == 0)
2035 initial_password = given_password;
2037 m_script->createAuth(playername, initial_password);
2040 has_auth = m_script->getAuth(playername, &checkpwd, NULL);
2043 actionstream<<"Server: "<<playername<<" cannot be authenticated"
2044 <<" (auth handler does not work?)"<<std::endl;
2045 DenyAccess(peer_id, L"Not allowed to login");
2049 if(given_password != checkpwd){
2050 actionstream<<"Server: "<<playername<<" supplied wrong password"
2052 DenyAccess(peer_id, L"Wrong password");
2057 PlayerSAO *playersao = emergePlayer(playername, peer_id);
2059 // If failed, cancel
2060 if(playersao == NULL)
2062 RemotePlayer *player =
2063 static_cast<RemotePlayer*>(m_env->getPlayer(playername));
2064 if(player && player->peer_id != 0){
2065 errorstream<<"Server: "<<playername<<": Failed to emerge player"
2066 <<" (player allocated to an another client)"<<std::endl;
2067 DenyAccess(peer_id, L"Another client is connected with this "
2068 L"name. If your client closed unexpectedly, try again in "
2071 errorstream<<"Server: "<<playername<<": Failed to emerge player"
2073 DenyAccess(peer_id, L"Could not allocate player.");
2079 Answer with a TOCLIENT_INIT
2082 SharedBuffer<u8> reply(2+1+6+8+4);
2083 writeU16(&reply[0], TOCLIENT_INIT);
2084 writeU8(&reply[2], deployed);
2085 writeV3S16(&reply[2+1], floatToInt(playersao->getPlayer()->getPosition()+v3f(0,BS/2,0), BS));
2086 writeU64(&reply[2+1+6], m_env->getServerMap().getSeed());
2087 writeF1000(&reply[2+1+6+8], g_settings->getFloat("dedicated_server_step"));
2090 m_con.Send(peer_id, 0, reply, true);
2094 Send complete position information
2096 SendMovePlayer(peer_id);
2101 if(command == TOSERVER_INIT2)
2103 verbosestream<<"Server: Got TOSERVER_INIT2 from "
2104 <<peer_id<<std::endl;
2106 Player *player = m_env->getPlayer(peer_id);
2108 verbosestream<<"Server: TOSERVER_INIT2: "
2109 <<"Player not found; ignoring."<<std::endl;
2113 RemoteClient *client = getClient(peer_id);
2114 client->serialization_version =
2115 getClient(peer_id)->pending_serialization_version;
2118 Send some initialization data
2121 infostream<<"Server: Sending content to "
2122 <<getPlayerName(peer_id)<<std::endl;
2124 // Send player movement settings
2125 SendMovement(m_con, peer_id);
2127 // Send item definitions
2128 SendItemDef(m_con, peer_id, m_itemdef, client->net_proto_version);
2130 // Send node definitions
2131 SendNodeDef(m_con, peer_id, m_nodedef, client->net_proto_version);
2133 // Send media announcement
2134 sendMediaAnnouncement(peer_id);
2137 SendPlayerPrivileges(peer_id);
2139 // Send inventory formspec
2140 SendPlayerInventoryFormspec(peer_id);
2143 UpdateCrafting(peer_id);
2144 SendInventory(peer_id);
2147 if(g_settings->getBool("enable_damage"))
2148 SendPlayerHP(peer_id);
2151 SendPlayerBreath(peer_id);
2153 // Send detached inventories
2154 sendDetachedInventories(peer_id);
2156 // Show death screen if necessary
2158 SendDeathscreen(m_con, peer_id, false, v3f(0,0,0));
2162 SharedBuffer<u8> data = makePacket_TOCLIENT_TIME_OF_DAY(
2163 m_env->getTimeOfDay(), g_settings->getFloat("time_speed"));
2164 m_con.Send(peer_id, 0, data, true);
2167 // Note things in chat if not in simple singleplayer mode
2168 if(!m_simple_singleplayer_mode)
2170 // Send information about server to player in chat
2171 SendChatMessage(peer_id, getStatusString());
2173 // Send information about joining in chat
2175 std::wstring name = L"unknown";
2176 Player *player = m_env->getPlayer(peer_id);
2178 name = narrow_to_wide(player->getName());
2180 std::wstring message;
2183 message += L" joined the game.";
2184 BroadcastChatMessage(message);
2188 // Warnings about protocol version can be issued here
2189 if(getClient(peer_id)->net_proto_version < LATEST_PROTOCOL_VERSION)
2191 SendChatMessage(peer_id, L"# Server: WARNING: YOUR CLIENT'S "
2192 L"VERSION MAY NOT BE FULLY COMPATIBLE WITH THIS SERVER!");
2199 std::ostringstream os(std::ios_base::binary);
2200 for(std::map<u16, RemoteClient*>::iterator
2201 i = m_clients.begin();
2202 i != m_clients.end(); ++i)
2204 RemoteClient *client = i->second;
2205 assert(client->peer_id == i->first);
2206 if(client->serialization_version == SER_FMT_VER_INVALID)
2209 Player *player = m_env->getPlayer(client->peer_id);
2212 // Get name of player
2213 os<<player->getName()<<" ";
2216 actionstream<<player->getName()<<" ["<<addr_s<<"] "<<"joins game. List of players: "
2217 <<os.str()<<std::endl;
2223 if(peer_ser_ver == SER_FMT_VER_INVALID)
2225 infostream<<"Server::ProcessData(): Cancelling: Peer"
2226 " serialization format invalid or not initialized."
2227 " Skipping incoming command="<<command<<std::endl;
2231 Player *player = m_env->getPlayer(peer_id);
2233 infostream<<"Server::ProcessData(): Cancelling: "
2234 "No player for peer_id="<<peer_id
2239 PlayerSAO *playersao = player->getPlayerSAO();
2240 if(playersao == NULL){
2241 infostream<<"Server::ProcessData(): Cancelling: "
2242 "No player object for peer_id="<<peer_id
2247 if(command == TOSERVER_PLAYERPOS)
2249 if(datasize < 2+12+12+4+4)
2253 v3s32 ps = readV3S32(&data[start+2]);
2254 v3s32 ss = readV3S32(&data[start+2+12]);
2255 f32 pitch = (f32)readS32(&data[2+12+12]) / 100.0;
2256 f32 yaw = (f32)readS32(&data[2+12+12+4]) / 100.0;
2258 if(datasize >= 2+12+12+4+4+4)
2259 keyPressed = (u32)readU32(&data[2+12+12+4+4]);
2260 v3f position((f32)ps.X/100., (f32)ps.Y/100., (f32)ps.Z/100.);
2261 v3f speed((f32)ss.X/100., (f32)ss.Y/100., (f32)ss.Z/100.);
2262 pitch = wrapDegrees(pitch);
2263 yaw = wrapDegrees(yaw);
2265 player->setPosition(position);
2266 player->setSpeed(speed);
2267 player->setPitch(pitch);
2268 player->setYaw(yaw);
2269 player->keyPressed=keyPressed;
2270 player->control.up = (bool)(keyPressed&1);
2271 player->control.down = (bool)(keyPressed&2);
2272 player->control.left = (bool)(keyPressed&4);
2273 player->control.right = (bool)(keyPressed&8);
2274 player->control.jump = (bool)(keyPressed&16);
2275 player->control.aux1 = (bool)(keyPressed&32);
2276 player->control.sneak = (bool)(keyPressed&64);
2277 player->control.LMB = (bool)(keyPressed&128);
2278 player->control.RMB = (bool)(keyPressed&256);
2280 bool cheated = playersao->checkMovementCheat();
2283 m_script->on_cheat(playersao, "moved_too_fast");
2286 /*infostream<<"Server::ProcessData(): Moved player "<<peer_id<<" to "
2287 <<"("<<position.X<<","<<position.Y<<","<<position.Z<<")"
2288 <<" pitch="<<pitch<<" yaw="<<yaw<<std::endl;*/
2290 else if(command == TOSERVER_GOTBLOCKS)
2303 u16 count = data[2];
2304 for(u16 i=0; i<count; i++)
2306 if((s16)datasize < 2+1+(i+1)*6)
2307 throw con::InvalidIncomingDataException
2308 ("GOTBLOCKS length is too short");
2309 v3s16 p = readV3S16(&data[2+1+i*6]);
2310 /*infostream<<"Server: GOTBLOCKS ("
2311 <<p.X<<","<<p.Y<<","<<p.Z<<")"<<std::endl;*/
2312 RemoteClient *client = getClient(peer_id);
2313 client->GotBlock(p);
2316 else if(command == TOSERVER_DELETEDBLOCKS)
2329 u16 count = data[2];
2330 for(u16 i=0; i<count; i++)
2332 if((s16)datasize < 2+1+(i+1)*6)
2333 throw con::InvalidIncomingDataException
2334 ("DELETEDBLOCKS length is too short");
2335 v3s16 p = readV3S16(&data[2+1+i*6]);
2336 /*infostream<<"Server: DELETEDBLOCKS ("
2337 <<p.X<<","<<p.Y<<","<<p.Z<<")"<<std::endl;*/
2338 RemoteClient *client = getClient(peer_id);
2339 client->SetBlockNotSent(p);
2342 else if(command == TOSERVER_CLICK_OBJECT)
2344 infostream<<"Server: CLICK_OBJECT not supported anymore"<<std::endl;
2347 else if(command == TOSERVER_CLICK_ACTIVEOBJECT)
2349 infostream<<"Server: CLICK_ACTIVEOBJECT not supported anymore"<<std::endl;
2352 else if(command == TOSERVER_GROUND_ACTION)
2354 infostream<<"Server: GROUND_ACTION not supported anymore"<<std::endl;
2358 else if(command == TOSERVER_RELEASE)
2360 infostream<<"Server: RELEASE not supported anymore"<<std::endl;
2363 else if(command == TOSERVER_SIGNTEXT)
2365 infostream<<"Server: SIGNTEXT not supported anymore"
2369 else if(command == TOSERVER_SIGNNODETEXT)
2371 infostream<<"Server: SIGNNODETEXT not supported anymore"
2375 else if(command == TOSERVER_INVENTORY_ACTION)
2377 // Strip command and create a stream
2378 std::string datastring((char*)&data[2], datasize-2);
2379 verbosestream<<"TOSERVER_INVENTORY_ACTION: data="<<datastring<<std::endl;
2380 std::istringstream is(datastring, std::ios_base::binary);
2382 InventoryAction *a = InventoryAction::deSerialize(is);
2385 infostream<<"TOSERVER_INVENTORY_ACTION: "
2386 <<"InventoryAction::deSerialize() returned NULL"
2391 // If something goes wrong, this player is to blame
2392 RollbackScopeActor rollback_scope(m_rollback,
2393 std::string("player:")+player->getName());
2396 Note: Always set inventory not sent, to repair cases
2397 where the client made a bad prediction.
2401 Handle restrictions and special cases of the move action
2403 if(a->getType() == IACTION_MOVE)
2405 IMoveAction *ma = (IMoveAction*)a;
2407 ma->from_inv.applyCurrentPlayer(player->getName());
2408 ma->to_inv.applyCurrentPlayer(player->getName());
2410 setInventoryModified(ma->from_inv);
2411 setInventoryModified(ma->to_inv);
2413 bool from_inv_is_current_player =
2414 (ma->from_inv.type == InventoryLocation::PLAYER) &&
2415 (ma->from_inv.name == player->getName());
2417 bool to_inv_is_current_player =
2418 (ma->to_inv.type == InventoryLocation::PLAYER) &&
2419 (ma->to_inv.name == player->getName());
2422 Disable moving items out of craftpreview
2424 if(ma->from_list == "craftpreview")
2426 infostream<<"Ignoring IMoveAction from "
2427 <<(ma->from_inv.dump())<<":"<<ma->from_list
2428 <<" to "<<(ma->to_inv.dump())<<":"<<ma->to_list
2429 <<" because src is "<<ma->from_list<<std::endl;
2435 Disable moving items into craftresult and craftpreview
2437 if(ma->to_list == "craftpreview" || ma->to_list == "craftresult")
2439 infostream<<"Ignoring IMoveAction from "
2440 <<(ma->from_inv.dump())<<":"<<ma->from_list
2441 <<" to "<<(ma->to_inv.dump())<<":"<<ma->to_list
2442 <<" because dst is "<<ma->to_list<<std::endl;
2447 // Disallow moving items in elsewhere than player's inventory
2448 // if not allowed to interact
2449 if(!checkPriv(player->getName(), "interact") &&
2450 (!from_inv_is_current_player ||
2451 !to_inv_is_current_player))
2453 infostream<<"Cannot move outside of player's inventory: "
2454 <<"No interact privilege"<<std::endl;
2460 Handle restrictions and special cases of the drop action
2462 else if(a->getType() == IACTION_DROP)
2464 IDropAction *da = (IDropAction*)a;
2466 da->from_inv.applyCurrentPlayer(player->getName());
2468 setInventoryModified(da->from_inv);
2471 Disable dropping items out of craftpreview
2473 if(da->from_list == "craftpreview")
2475 infostream<<"Ignoring IDropAction from "
2476 <<(da->from_inv.dump())<<":"<<da->from_list
2477 <<" because src is "<<da->from_list<<std::endl;
2482 // Disallow dropping items if not allowed to interact
2483 if(!checkPriv(player->getName(), "interact"))
2490 Handle restrictions and special cases of the craft action
2492 else if(a->getType() == IACTION_CRAFT)
2494 ICraftAction *ca = (ICraftAction*)a;
2496 ca->craft_inv.applyCurrentPlayer(player->getName());
2498 setInventoryModified(ca->craft_inv);
2500 //bool craft_inv_is_current_player =
2501 // (ca->craft_inv.type == InventoryLocation::PLAYER) &&
2502 // (ca->craft_inv.name == player->getName());
2504 // Disallow crafting if not allowed to interact
2505 if(!checkPriv(player->getName(), "interact"))
2507 infostream<<"Cannot craft: "
2508 <<"No interact privilege"<<std::endl;
2515 a->apply(this, playersao, this);
2519 else if(command == TOSERVER_CHAT_MESSAGE)
2527 std::string datastring((char*)&data[2], datasize-2);
2528 std::istringstream is(datastring, std::ios_base::binary);
2531 is.read((char*)buf, 2);
2532 u16 len = readU16(buf);
2534 std::wstring message;
2535 for(u16 i=0; i<len; i++)
2537 is.read((char*)buf, 2);
2538 message += (wchar_t)readU16(buf);
2541 // If something goes wrong, this player is to blame
2542 RollbackScopeActor rollback_scope(m_rollback,
2543 std::string("player:")+player->getName());
2545 // Get player name of this client
2546 std::wstring name = narrow_to_wide(player->getName());
2549 bool ate = m_script->on_chat_message(player->getName(),
2550 wide_to_narrow(message));
2551 // If script ate the message, don't proceed
2555 // Line to send to players
2557 // Whether to send to the player that sent the line
2558 bool send_to_sender = false;
2559 // Whether to send to other players
2560 bool send_to_others = false;
2562 // Commands are implemented in Lua, so only catch invalid
2563 // commands that were not "eaten" and send an error back
2564 if(message[0] == L'/')
2566 message = message.substr(1);
2567 send_to_sender = true;
2568 if(message.length() == 0)
2569 line += L"-!- Empty command";
2571 line += L"-!- Invalid command: " + str_split(message, L' ')[0];
2575 if(checkPriv(player->getName(), "shout")){
2580 send_to_others = true;
2582 line += L"-!- You don't have permission to shout.";
2583 send_to_sender = true;
2590 actionstream<<"CHAT: "<<wide_to_narrow(line)<<std::endl;
2593 Send the message to clients
2595 for(std::map<u16, RemoteClient*>::iterator
2596 i = m_clients.begin();
2597 i != m_clients.end(); ++i)
2599 // Get client and check that it is valid
2600 RemoteClient *client = i->second;
2601 assert(client->peer_id == i->first);
2602 if(client->serialization_version == SER_FMT_VER_INVALID)
2606 bool sender_selected = (peer_id == client->peer_id);
2607 if(sender_selected == true && send_to_sender == false)
2609 if(sender_selected == false && send_to_others == false)
2612 SendChatMessage(client->peer_id, line);
2616 else if(command == TOSERVER_DAMAGE)
2618 std::string datastring((char*)&data[2], datasize-2);
2619 std::istringstream is(datastring, std::ios_base::binary);
2620 u8 damage = readU8(is);
2622 if(g_settings->getBool("enable_damage"))
2624 actionstream<<player->getName()<<" damaged by "
2625 <<(int)damage<<" hp at "<<PP(player->getPosition()/BS)
2628 playersao->setHP(playersao->getHP() - damage);
2630 if(playersao->getHP() == 0 && playersao->m_hp_not_sent)
2633 if(playersao->m_hp_not_sent)
2634 SendPlayerHP(peer_id);
2637 else if(command == TOSERVER_BREATH)
2639 std::string datastring((char*)&data[2], datasize-2);
2640 std::istringstream is(datastring, std::ios_base::binary);
2641 u16 breath = readU16(is);
2642 playersao->setBreath(breath);
2644 else if(command == TOSERVER_PASSWORD)
2647 [0] u16 TOSERVER_PASSWORD
2648 [2] u8[28] old password
2649 [30] u8[28] new password
2652 if(datasize != 2+PASSWORD_SIZE*2)
2654 /*char password[PASSWORD_SIZE];
2655 for(u32 i=0; i<PASSWORD_SIZE-1; i++)
2656 password[i] = data[2+i];
2657 password[PASSWORD_SIZE-1] = 0;*/
2659 for(u32 i=0; i<PASSWORD_SIZE-1; i++)
2667 for(u32 i=0; i<PASSWORD_SIZE-1; i++)
2669 char c = data[2+PASSWORD_SIZE+i];
2675 if(!base64_is_valid(newpwd)){
2676 infostream<<"Server: "<<player->getName()<<" supplied invalid password hash"<<std::endl;
2677 // Wrong old password supplied!!
2678 SendChatMessage(peer_id, L"Invalid new password hash supplied. Password NOT changed.");
2682 infostream<<"Server: Client requests a password change from "
2683 <<"'"<<oldpwd<<"' to '"<<newpwd<<"'"<<std::endl;
2685 std::string playername = player->getName();
2687 std::string checkpwd;
2688 m_script->getAuth(playername, &checkpwd, NULL);
2690 if(oldpwd != checkpwd)
2692 infostream<<"Server: invalid old password"<<std::endl;
2693 // Wrong old password supplied!!
2694 SendChatMessage(peer_id, L"Invalid old password supplied. Password NOT changed.");
2698 bool success = m_script->setPassword(playername, newpwd);
2700 actionstream<<player->getName()<<" changes password"<<std::endl;
2701 SendChatMessage(peer_id, L"Password change successful.");
2703 actionstream<<player->getName()<<" tries to change password but "
2704 <<"it fails"<<std::endl;
2705 SendChatMessage(peer_id, L"Password change failed or inavailable.");
2708 else if(command == TOSERVER_PLAYERITEM)
2713 u16 item = readU16(&data[2]);
2714 playersao->setWieldIndex(item);
2716 else if(command == TOSERVER_RESPAWN)
2718 if(player->hp != 0 || !g_settings->getBool("enable_damage"))
2721 RespawnPlayer(peer_id);
2723 actionstream<<player->getName()<<" respawns at "
2724 <<PP(player->getPosition()/BS)<<std::endl;
2726 // ActiveObject is added to environment in AsyncRunStep after
2727 // the previous addition has been succesfully removed
2729 else if(command == TOSERVER_REQUEST_MEDIA) {
2730 std::string datastring((char*)&data[2], datasize-2);
2731 std::istringstream is(datastring, std::ios_base::binary);
2733 std::list<MediaRequest> tosend;
2734 u16 numfiles = readU16(is);
2736 infostream<<"Sending "<<numfiles<<" files to "
2737 <<getPlayerName(peer_id)<<std::endl;
2738 verbosestream<<"TOSERVER_REQUEST_MEDIA: "<<std::endl;
2740 for(int i = 0; i < numfiles; i++) {
2741 std::string name = deSerializeString(is);
2742 tosend.push_back(MediaRequest(name));
2743 verbosestream<<"TOSERVER_REQUEST_MEDIA: requested file "
2747 sendRequestedMedia(peer_id, tosend);
2749 // Now the client should know about everything
2750 // (definitions and files)
2751 getClient(peer_id)->definitions_sent = true;
2753 else if(command == TOSERVER_RECEIVED_MEDIA) {
2754 getClient(peer_id)->definitions_sent = true;
2756 else if(command == TOSERVER_INTERACT)
2758 std::string datastring((char*)&data[2], datasize-2);
2759 std::istringstream is(datastring, std::ios_base::binary);
2765 [5] u32 length of the next item
2766 [9] serialized PointedThing
2768 0: start digging (from undersurface) or use
2769 1: stop digging (all parameters ignored)
2770 2: digging completed
2771 3: place block or item (to abovesurface)
2774 u8 action = readU8(is);
2775 u16 item_i = readU16(is);
2776 std::istringstream tmp_is(deSerializeLongString(is), std::ios::binary);
2777 PointedThing pointed;
2778 pointed.deSerialize(tmp_is);
2780 verbosestream<<"TOSERVER_INTERACT: action="<<(int)action<<", item="
2781 <<item_i<<", pointed="<<pointed.dump()<<std::endl;
2785 verbosestream<<"TOSERVER_INTERACT: "<<player->getName()
2786 <<" tried to interact, but is dead!"<<std::endl;
2790 v3f player_pos = playersao->getLastGoodPosition();
2792 // Update wielded item
2793 playersao->setWieldIndex(item_i);
2795 // Get pointed to node (undefined if not POINTEDTYPE_NODE)
2796 v3s16 p_under = pointed.node_undersurface;
2797 v3s16 p_above = pointed.node_abovesurface;
2799 // Get pointed to object (NULL if not POINTEDTYPE_OBJECT)
2800 ServerActiveObject *pointed_object = NULL;
2801 if(pointed.type == POINTEDTHING_OBJECT)
2803 pointed_object = m_env->getActiveObject(pointed.object_id);
2804 if(pointed_object == NULL)
2806 verbosestream<<"TOSERVER_INTERACT: "
2807 "pointed object is NULL"<<std::endl;
2813 v3f pointed_pos_under = player_pos;
2814 v3f pointed_pos_above = player_pos;
2815 if(pointed.type == POINTEDTHING_NODE)
2817 pointed_pos_under = intToFloat(p_under, BS);
2818 pointed_pos_above = intToFloat(p_above, BS);
2820 else if(pointed.type == POINTEDTHING_OBJECT)
2822 pointed_pos_under = pointed_object->getBasePosition();
2823 pointed_pos_above = pointed_pos_under;
2827 Check that target is reasonably close
2828 (only when digging or placing things)
2830 if(action == 0 || action == 2 || action == 3)
2832 float d = player_pos.getDistanceFrom(pointed_pos_under);
2833 float max_d = BS * 14; // Just some large enough value
2835 actionstream<<"Player "<<player->getName()
2836 <<" tried to access "<<pointed.dump()
2838 <<"d="<<d<<", max_d="<<max_d
2839 <<". ignoring."<<std::endl;
2840 // Re-send block to revert change on client-side
2841 RemoteClient *client = getClient(peer_id);
2842 v3s16 blockpos = getNodeBlockPos(floatToInt(pointed_pos_under, BS));
2843 client->SetBlockNotSent(blockpos);
2845 m_script->on_cheat(playersao, "interacted_too_far");
2852 Make sure the player is allowed to do it
2854 if(!checkPriv(player->getName(), "interact"))
2856 actionstream<<player->getName()<<" attempted to interact with "
2857 <<pointed.dump()<<" without 'interact' privilege"
2859 // Re-send block to revert change on client-side
2860 RemoteClient *client = getClient(peer_id);
2861 // Digging completed -> under
2863 v3s16 blockpos = getNodeBlockPos(floatToInt(pointed_pos_under, BS));
2864 client->SetBlockNotSent(blockpos);
2866 // Placement -> above
2868 v3s16 blockpos = getNodeBlockPos(floatToInt(pointed_pos_above, BS));
2869 client->SetBlockNotSent(blockpos);
2875 If something goes wrong, this player is to blame
2877 RollbackScopeActor rollback_scope(m_rollback,
2878 std::string("player:")+player->getName());
2881 0: start digging or punch object
2885 if(pointed.type == POINTEDTHING_NODE)
2888 NOTE: This can be used in the future to check if
2889 somebody is cheating, by checking the timing.
2891 MapNode n(CONTENT_IGNORE);
2894 n = m_env->getMap().getNode(p_under);
2896 catch(InvalidPositionException &e)
2898 infostream<<"Server: Not punching: Node not found."
2899 <<" Adding block to emerge queue."
2901 m_emerge->enqueueBlockEmerge(peer_id, getNodeBlockPos(p_above), false);
2903 if(n.getContent() != CONTENT_IGNORE)
2904 m_script->node_on_punch(p_under, n, playersao);
2906 playersao->noCheatDigStart(p_under);
2908 else if(pointed.type == POINTEDTHING_OBJECT)
2910 // Skip if object has been removed
2911 if(pointed_object->m_removed)
2914 actionstream<<player->getName()<<" punches object "
2915 <<pointed.object_id<<": "
2916 <<pointed_object->getDescription()<<std::endl;
2918 ItemStack punchitem = playersao->getWieldedItem();
2919 ToolCapabilities toolcap =
2920 punchitem.getToolCapabilities(m_itemdef);
2921 v3f dir = (pointed_object->getBasePosition() -
2922 (player->getPosition() + player->getEyeOffset())
2924 float time_from_last_punch =
2925 playersao->resetTimeFromLastPunch();
2926 pointed_object->punch(dir, &toolcap, playersao,
2927 time_from_last_punch);
2935 else if(action == 1)
2940 2: Digging completed
2942 else if(action == 2)
2944 // Only digging of nodes
2945 if(pointed.type == POINTEDTHING_NODE)
2947 MapNode n(CONTENT_IGNORE);
2950 n = m_env->getMap().getNode(p_under);
2952 catch(InvalidPositionException &e)
2954 infostream<<"Server: Not finishing digging: Node not found."
2955 <<" Adding block to emerge queue."
2957 m_emerge->enqueueBlockEmerge(peer_id, getNodeBlockPos(p_above), false);
2960 /* Cheat prevention */
2961 bool is_valid_dig = true;
2962 if(!isSingleplayer() && !g_settings->getBool("disable_anticheat"))
2964 v3s16 nocheat_p = playersao->getNoCheatDigPos();
2965 float nocheat_t = playersao->getNoCheatDigTime();
2966 playersao->noCheatDigEnd();
2967 // If player didn't start digging this, ignore dig
2968 if(nocheat_p != p_under){
2969 infostream<<"Server: NoCheat: "<<player->getName()
2970 <<" started digging "
2971 <<PP(nocheat_p)<<" and completed digging "
2972 <<PP(p_under)<<"; not digging."<<std::endl;
2973 is_valid_dig = false;
2975 m_script->on_cheat(playersao, "finished_unknown_dig");
2977 // Get player's wielded item
2978 ItemStack playeritem;
2979 InventoryList *mlist = playersao->getInventory()->getList("main");
2981 playeritem = mlist->getItem(playersao->getWieldIndex());
2982 ToolCapabilities playeritem_toolcap =
2983 playeritem.getToolCapabilities(m_itemdef);
2984 // Get diggability and expected digging time
2985 DigParams params = getDigParams(m_nodedef->get(n).groups,
2986 &playeritem_toolcap);
2987 // If can't dig, try hand
2988 if(!params.diggable){
2989 const ItemDefinition &hand = m_itemdef->get("");
2990 const ToolCapabilities *tp = hand.tool_capabilities;
2992 params = getDigParams(m_nodedef->get(n).groups, tp);
2994 // If can't dig, ignore dig
2995 if(!params.diggable){
2996 infostream<<"Server: NoCheat: "<<player->getName()
2997 <<" completed digging "<<PP(p_under)
2998 <<", which is not diggable with tool. not digging."
3000 is_valid_dig = false;
3002 m_script->on_cheat(playersao, "dug_unbreakable");
3004 // Check digging time
3005 // If already invalidated, we don't have to
3007 // Well not our problem then
3009 // Clean and long dig
3010 else if(params.time > 2.0 && nocheat_t * 1.2 > params.time){
3011 // All is good, but grab time from pool; don't care if
3012 // it's actually available
3013 playersao->getDigPool().grab(params.time);
3015 // Short or laggy dig
3016 // Try getting the time from pool
3017 else if(playersao->getDigPool().grab(params.time)){
3022 infostream<<"Server: NoCheat: "<<player->getName()
3023 <<" completed digging "<<PP(p_under)
3024 <<"too fast; not digging."<<std::endl;
3025 is_valid_dig = false;
3027 m_script->on_cheat(playersao, "dug_too_fast");
3031 /* Actually dig node */
3033 if(is_valid_dig && n.getContent() != CONTENT_IGNORE)
3034 m_script->node_on_dig(p_under, n, playersao);
3036 // Send unusual result (that is, node not being removed)
3037 if(m_env->getMap().getNodeNoEx(p_under).getContent() != CONTENT_AIR)
3039 // Re-send block to revert change on client-side
3040 RemoteClient *client = getClient(peer_id);
3041 v3s16 blockpos = getNodeBlockPos(floatToInt(pointed_pos_under, BS));
3042 client->SetBlockNotSent(blockpos);
3048 3: place block or right-click object
3050 else if(action == 3)
3052 ItemStack item = playersao->getWieldedItem();
3054 // Reset build time counter
3055 if(pointed.type == POINTEDTHING_NODE &&
3056 item.getDefinition(m_itemdef).type == ITEM_NODE)
3057 getClient(peer_id)->m_time_from_building = 0.0;
3059 if(pointed.type == POINTEDTHING_OBJECT)
3061 // Right click object
3063 // Skip if object has been removed
3064 if(pointed_object->m_removed)
3067 actionstream<<player->getName()<<" right-clicks object "
3068 <<pointed.object_id<<": "
3069 <<pointed_object->getDescription()<<std::endl;
3072 pointed_object->rightClick(playersao);
3074 else if(m_script->item_OnPlace(
3075 item, playersao, pointed))
3077 // Placement was handled in lua
3079 // Apply returned ItemStack
3080 playersao->setWieldedItem(item);
3083 // If item has node placement prediction, always send the
3084 // blocks to make sure the client knows what exactly happened
3085 if(item.getDefinition(m_itemdef).node_placement_prediction != ""){
3086 RemoteClient *client = getClient(peer_id);
3087 v3s16 blockpos = getNodeBlockPos(floatToInt(pointed_pos_above, BS));
3088 client->SetBlockNotSent(blockpos);
3089 v3s16 blockpos2 = getNodeBlockPos(floatToInt(pointed_pos_under, BS));
3090 if(blockpos2 != blockpos){
3091 client->SetBlockNotSent(blockpos2);
3099 else if(action == 4)
3101 ItemStack item = playersao->getWieldedItem();
3103 actionstream<<player->getName()<<" uses "<<item.name
3104 <<", pointing at "<<pointed.dump()<<std::endl;
3106 if(m_script->item_OnUse(
3107 item, playersao, pointed))
3109 // Apply returned ItemStack
3110 playersao->setWieldedItem(item);
3117 Catch invalid actions
3121 infostream<<"WARNING: Server: Invalid action "
3122 <<action<<std::endl;
3125 else if(command == TOSERVER_REMOVED_SOUNDS)
3127 std::string datastring((char*)&data[2], datasize-2);
3128 std::istringstream is(datastring, std::ios_base::binary);
3130 int num = readU16(is);
3131 for(int k=0; k<num; k++){
3132 s32 id = readS32(is);
3133 std::map<s32, ServerPlayingSound>::iterator i =
3134 m_playing_sounds.find(id);
3135 if(i == m_playing_sounds.end())
3137 ServerPlayingSound &psound = i->second;
3138 psound.clients.erase(peer_id);
3139 if(psound.clients.size() == 0)
3140 m_playing_sounds.erase(i++);
3143 else if(command == TOSERVER_NODEMETA_FIELDS)
3145 std::string datastring((char*)&data[2], datasize-2);
3146 std::istringstream is(datastring, std::ios_base::binary);
3148 v3s16 p = readV3S16(is);
3149 std::string formname = deSerializeString(is);
3150 int num = readU16(is);
3151 std::map<std::string, std::string> fields;
3152 for(int k=0; k<num; k++){
3153 std::string fieldname = deSerializeString(is);
3154 std::string fieldvalue = deSerializeLongString(is);
3155 fields[fieldname] = fieldvalue;
3158 // If something goes wrong, this player is to blame
3159 RollbackScopeActor rollback_scope(m_rollback,
3160 std::string("player:")+player->getName());
3162 // Check the target node for rollback data; leave others unnoticed
3163 RollbackNode rn_old(&m_env->getMap(), p, this);
3165 m_script->node_on_receive_fields(p, formname, fields,playersao);
3167 // Report rollback data
3168 RollbackNode rn_new(&m_env->getMap(), p, this);
3169 if(rollback() && rn_new != rn_old){
3170 RollbackAction action;
3171 action.setSetNode(p, rn_old, rn_new);
3172 rollback()->reportAction(action);
3175 else if(command == TOSERVER_INVENTORY_FIELDS)
3177 std::string datastring((char*)&data[2], datasize-2);
3178 std::istringstream is(datastring, std::ios_base::binary);
3180 std::string formname = deSerializeString(is);
3181 int num = readU16(is);
3182 std::map<std::string, std::string> fields;
3183 for(int k=0; k<num; k++){
3184 std::string fieldname = deSerializeString(is);
3185 std::string fieldvalue = deSerializeLongString(is);
3186 fields[fieldname] = fieldvalue;
3189 m_script->on_playerReceiveFields(playersao, formname, fields);
3193 infostream<<"Server::ProcessData(): Ignoring "
3194 "unknown command "<<command<<std::endl;
3198 catch(SendFailedException &e)
3200 errorstream<<"Server::ProcessData(): SendFailedException: "
3206 void Server::onMapEditEvent(MapEditEvent *event)
3208 //infostream<<"Server::onMapEditEvent()"<<std::endl;
3209 if(m_ignore_map_edit_events)
3211 if(m_ignore_map_edit_events_area.contains(event->getArea()))
3213 MapEditEvent *e = event->clone();
3214 m_unsent_map_edit_queue.push_back(e);
3217 Inventory* Server::getInventory(const InventoryLocation &loc)
3220 case InventoryLocation::UNDEFINED:
3223 case InventoryLocation::CURRENT_PLAYER:
3226 case InventoryLocation::PLAYER:
3228 Player *player = m_env->getPlayer(loc.name.c_str());
3231 PlayerSAO *playersao = player->getPlayerSAO();
3234 return playersao->getInventory();
3237 case InventoryLocation::NODEMETA:
3239 NodeMetadata *meta = m_env->getMap().getNodeMetadata(loc.p);
3242 return meta->getInventory();
3245 case InventoryLocation::DETACHED:
3247 if(m_detached_inventories.count(loc.name) == 0)
3249 return m_detached_inventories[loc.name];
3257 void Server::setInventoryModified(const InventoryLocation &loc)
3260 case InventoryLocation::UNDEFINED:
3263 case InventoryLocation::PLAYER:
3265 Player *player = m_env->getPlayer(loc.name.c_str());
3268 PlayerSAO *playersao = player->getPlayerSAO();
3271 playersao->m_inventory_not_sent = true;
3272 playersao->m_wielded_item_not_sent = true;
3275 case InventoryLocation::NODEMETA:
3277 v3s16 blockpos = getNodeBlockPos(loc.p);
3279 MapBlock *block = m_env->getMap().getBlockNoCreateNoEx(blockpos);
3281 block->raiseModified(MOD_STATE_WRITE_NEEDED);
3283 setBlockNotSent(blockpos);
3286 case InventoryLocation::DETACHED:
3288 sendDetachedInventoryToAll(loc.name);
3296 //std::list<PlayerInfo> Server::getPlayerInfo()
3298 // DSTACK(__FUNCTION_NAME);
3299 // JMutexAutoLock envlock(m_env_mutex);
3300 // JMutexAutoLock conlock(m_con_mutex);
3302 // std::list<PlayerInfo> list;
3304 // std::list<Player*> players = m_env->getPlayers();
3306 // std::list<Player*>::iterator i;
3307 // for(i = players.begin();
3308 // i != players.end(); ++i)
3312 // Player *player = *i;
3315 // // Copy info from connection to info struct
3316 // info.id = player->peer_id;
3317 // info.address = m_con.GetPeerAddress(player->peer_id);
3318 // info.avg_rtt = m_con.GetPeerAvgRTT(player->peer_id);
3320 // catch(con::PeerNotFoundException &e)
3322 // // Set dummy peer info
3324 // info.address = Address(0,0,0,0,0);
3325 // info.avg_rtt = 0.0;
3328 // snprintf(info.name, PLAYERNAME_SIZE, "%s", player->getName());
3329 // info.position = player->getPosition();
3331 // list.push_back(info);
3338 void Server::peerAdded(con::Peer *peer)
3340 DSTACK(__FUNCTION_NAME);
3341 verbosestream<<"Server::peerAdded(): peer->id="
3342 <<peer->id<<std::endl;
3345 c.type = PEER_ADDED;
3346 c.peer_id = peer->id;
3348 m_peer_change_queue.push_back(c);
3351 void Server::deletingPeer(con::Peer *peer, bool timeout)
3353 DSTACK(__FUNCTION_NAME);
3354 verbosestream<<"Server::deletingPeer(): peer->id="
3355 <<peer->id<<", timeout="<<timeout<<std::endl;
3358 c.type = PEER_REMOVED;
3359 c.peer_id = peer->id;
3360 c.timeout = timeout;
3361 m_peer_change_queue.push_back(c);
3368 void Server::SendMovement(con::Connection &con, u16 peer_id)
3370 DSTACK(__FUNCTION_NAME);
3371 std::ostringstream os(std::ios_base::binary);
3373 writeU16(os, TOCLIENT_MOVEMENT);
3374 writeF1000(os, g_settings->getFloat("movement_acceleration_default"));
3375 writeF1000(os, g_settings->getFloat("movement_acceleration_air"));
3376 writeF1000(os, g_settings->getFloat("movement_acceleration_fast"));
3377 writeF1000(os, g_settings->getFloat("movement_speed_walk"));
3378 writeF1000(os, g_settings->getFloat("movement_speed_crouch"));
3379 writeF1000(os, g_settings->getFloat("movement_speed_fast"));
3380 writeF1000(os, g_settings->getFloat("movement_speed_climb"));
3381 writeF1000(os, g_settings->getFloat("movement_speed_jump"));
3382 writeF1000(os, g_settings->getFloat("movement_liquid_fluidity"));
3383 writeF1000(os, g_settings->getFloat("movement_liquid_fluidity_smooth"));
3384 writeF1000(os, g_settings->getFloat("movement_liquid_sink"));
3385 writeF1000(os, g_settings->getFloat("movement_gravity"));
3388 std::string s = os.str();
3389 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3391 con.Send(peer_id, 0, data, true);
3394 void Server::SendHP(con::Connection &con, u16 peer_id, u8 hp)
3396 DSTACK(__FUNCTION_NAME);
3397 std::ostringstream os(std::ios_base::binary);
3399 writeU16(os, TOCLIENT_HP);
3403 std::string s = os.str();
3404 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3406 con.Send(peer_id, 0, data, true);
3409 void Server::SendBreath(con::Connection &con, u16 peer_id, u16 breath)
3411 DSTACK(__FUNCTION_NAME);
3412 std::ostringstream os(std::ios_base::binary);
3414 writeU16(os, TOCLIENT_BREATH);
3415 writeU16(os, breath);
3418 std::string s = os.str();
3419 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3421 con.Send(peer_id, 0, data, true);
3424 void Server::SendAccessDenied(con::Connection &con, u16 peer_id,
3425 const std::wstring &reason)
3427 DSTACK(__FUNCTION_NAME);
3428 std::ostringstream os(std::ios_base::binary);
3430 writeU16(os, TOCLIENT_ACCESS_DENIED);
3431 os<<serializeWideString(reason);
3434 std::string s = os.str();
3435 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3437 con.Send(peer_id, 0, data, true);
3440 void Server::SendDeathscreen(con::Connection &con, u16 peer_id,
3441 bool set_camera_point_target, v3f camera_point_target)
3443 DSTACK(__FUNCTION_NAME);
3444 std::ostringstream os(std::ios_base::binary);
3446 writeU16(os, TOCLIENT_DEATHSCREEN);
3447 writeU8(os, set_camera_point_target);
3448 writeV3F1000(os, camera_point_target);
3451 std::string s = os.str();
3452 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3454 con.Send(peer_id, 0, data, true);
3457 void Server::SendItemDef(con::Connection &con, u16 peer_id,
3458 IItemDefManager *itemdef, u16 protocol_version)
3460 DSTACK(__FUNCTION_NAME);
3461 std::ostringstream os(std::ios_base::binary);
3465 u32 length of the next item
3466 zlib-compressed serialized ItemDefManager
3468 writeU16(os, TOCLIENT_ITEMDEF);
3469 std::ostringstream tmp_os(std::ios::binary);
3470 itemdef->serialize(tmp_os, protocol_version);
3471 std::ostringstream tmp_os2(std::ios::binary);
3472 compressZlib(tmp_os.str(), tmp_os2);
3473 os<<serializeLongString(tmp_os2.str());
3476 std::string s = os.str();
3477 verbosestream<<"Server: Sending item definitions to id("<<peer_id
3478 <<"): size="<<s.size()<<std::endl;
3479 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3481 con.Send(peer_id, 0, data, true);
3484 void Server::SendNodeDef(con::Connection &con, u16 peer_id,
3485 INodeDefManager *nodedef, u16 protocol_version)
3487 DSTACK(__FUNCTION_NAME);
3488 std::ostringstream os(std::ios_base::binary);
3492 u32 length of the next item
3493 zlib-compressed serialized NodeDefManager
3495 writeU16(os, TOCLIENT_NODEDEF);
3496 std::ostringstream tmp_os(std::ios::binary);
3497 nodedef->serialize(tmp_os, protocol_version);
3498 std::ostringstream tmp_os2(std::ios::binary);
3499 compressZlib(tmp_os.str(), tmp_os2);
3500 os<<serializeLongString(tmp_os2.str());
3503 std::string s = os.str();
3504 verbosestream<<"Server: Sending node definitions to id("<<peer_id
3505 <<"): size="<<s.size()<<std::endl;
3506 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3508 con.Send(peer_id, 0, data, true);
3512 Non-static send methods
3515 void Server::SendInventory(u16 peer_id)
3517 DSTACK(__FUNCTION_NAME);
3519 PlayerSAO *playersao = getPlayerSAO(peer_id);
3522 playersao->m_inventory_not_sent = false;
3528 std::ostringstream os;
3529 playersao->getInventory()->serialize(os);
3531 std::string s = os.str();
3533 SharedBuffer<u8> data(s.size()+2);
3534 writeU16(&data[0], TOCLIENT_INVENTORY);
3535 memcpy(&data[2], s.c_str(), s.size());
3538 m_con.Send(peer_id, 0, data, true);
3541 void Server::SendChatMessage(u16 peer_id, const std::wstring &message)
3543 DSTACK(__FUNCTION_NAME);
3545 std::ostringstream os(std::ios_base::binary);
3549 writeU16(buf, TOCLIENT_CHAT_MESSAGE);
3550 os.write((char*)buf, 2);
3553 writeU16(buf, message.size());
3554 os.write((char*)buf, 2);
3557 for(u32 i=0; i<message.size(); i++)
3561 os.write((char*)buf, 2);
3565 std::string s = os.str();
3566 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3568 m_con.Send(peer_id, 0, data, true);
3571 void Server::SendShowFormspecMessage(u16 peer_id, const std::string formspec,
3572 const std::string formname)
3574 DSTACK(__FUNCTION_NAME);
3576 std::ostringstream os(std::ios_base::binary);
3580 writeU16(buf, TOCLIENT_SHOW_FORMSPEC);
3581 os.write((char*)buf, 2);
3582 os<<serializeLongString(formspec);
3583 os<<serializeString(formname);
3586 std::string s = os.str();
3587 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3589 m_con.Send(peer_id, 0, data, true);
3592 // Spawns a particle on peer with peer_id
3593 void Server::SendSpawnParticle(u16 peer_id, v3f pos, v3f velocity, v3f acceleration,
3594 float expirationtime, float size, bool collisiondetection,
3595 std::string texture)
3597 DSTACK(__FUNCTION_NAME);
3599 std::ostringstream os(std::ios_base::binary);
3600 writeU16(os, TOCLIENT_SPAWN_PARTICLE);
3601 writeV3F1000(os, pos);
3602 writeV3F1000(os, velocity);
3603 writeV3F1000(os, acceleration);
3604 writeF1000(os, expirationtime);
3605 writeF1000(os, size);
3606 writeU8(os, collisiondetection);
3607 os<<serializeLongString(texture);
3610 std::string s = os.str();
3611 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3613 m_con.Send(peer_id, 0, data, true);
3616 // Spawns a particle on all peers
3617 void Server::SendSpawnParticleAll(v3f pos, v3f velocity, v3f acceleration,
3618 float expirationtime, float size, bool collisiondetection,
3619 std::string texture)
3621 for(std::map<u16, RemoteClient*>::iterator
3622 i = m_clients.begin();
3623 i != m_clients.end(); i++)
3625 // Get client and check that it is valid
3626 RemoteClient *client = i->second;
3627 assert(client->peer_id == i->first);
3628 if(client->serialization_version == SER_FMT_VER_INVALID)
3631 SendSpawnParticle(client->peer_id, pos, velocity, acceleration,
3632 expirationtime, size, collisiondetection, texture);
3636 // Adds a ParticleSpawner on peer with peer_id
3637 void Server::SendAddParticleSpawner(u16 peer_id, u16 amount, float spawntime, v3f minpos, v3f maxpos,
3638 v3f minvel, v3f maxvel, v3f minacc, v3f maxacc, float minexptime, float maxexptime,
3639 float minsize, float maxsize, bool collisiondetection, std::string texture, u32 id)
3641 DSTACK(__FUNCTION_NAME);
3643 std::ostringstream os(std::ios_base::binary);
3644 writeU16(os, TOCLIENT_ADD_PARTICLESPAWNER);
3646 writeU16(os, amount);
3647 writeF1000(os, spawntime);
3648 writeV3F1000(os, minpos);
3649 writeV3F1000(os, maxpos);
3650 writeV3F1000(os, minvel);
3651 writeV3F1000(os, maxvel);
3652 writeV3F1000(os, minacc);
3653 writeV3F1000(os, maxacc);
3654 writeF1000(os, minexptime);
3655 writeF1000(os, maxexptime);
3656 writeF1000(os, minsize);
3657 writeF1000(os, maxsize);
3658 writeU8(os, collisiondetection);
3659 os<<serializeLongString(texture);
3663 std::string s = os.str();
3664 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3666 m_con.Send(peer_id, 0, data, true);
3669 // Adds a ParticleSpawner on all peers
3670 void Server::SendAddParticleSpawnerAll(u16 amount, float spawntime, v3f minpos, v3f maxpos,
3671 v3f minvel, v3f maxvel, v3f minacc, v3f maxacc, float minexptime, float maxexptime,
3672 float minsize, float maxsize, bool collisiondetection, std::string texture, u32 id)
3674 for(std::map<u16, RemoteClient*>::iterator
3675 i = m_clients.begin();
3676 i != m_clients.end(); i++)
3678 // Get client and check that it is valid
3679 RemoteClient *client = i->second;
3680 assert(client->peer_id == i->first);
3681 if(client->serialization_version == SER_FMT_VER_INVALID)
3684 SendAddParticleSpawner(client->peer_id, amount, spawntime,
3685 minpos, maxpos, minvel, maxvel, minacc, maxacc,
3686 minexptime, maxexptime, minsize, maxsize, collisiondetection, texture, id);
3690 void Server::SendDeleteParticleSpawner(u16 peer_id, u32 id)
3692 DSTACK(__FUNCTION_NAME);
3694 std::ostringstream os(std::ios_base::binary);
3695 writeU16(os, TOCLIENT_DELETE_PARTICLESPAWNER);
3700 std::string s = os.str();
3701 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3703 m_con.Send(peer_id, 0, data, true);
3706 void Server::SendDeleteParticleSpawnerAll(u32 id)
3708 for(std::map<u16, RemoteClient*>::iterator
3709 i = m_clients.begin();
3710 i != m_clients.end(); i++)
3712 // Get client and check that it is valid
3713 RemoteClient *client = i->second;
3714 assert(client->peer_id == i->first);
3715 if(client->serialization_version == SER_FMT_VER_INVALID)
3718 SendDeleteParticleSpawner(client->peer_id, id);
3722 void Server::SendHUDAdd(u16 peer_id, u32 id, HudElement *form)
3724 std::ostringstream os(std::ios_base::binary);
3727 writeU16(os, TOCLIENT_HUDADD);
3729 writeU8(os, (u8)form->type);
3730 writeV2F1000(os, form->pos);
3731 os << serializeString(form->name);
3732 writeV2F1000(os, form->scale);
3733 os << serializeString(form->text);
3734 writeU32(os, form->number);
3735 writeU32(os, form->item);
3736 writeU32(os, form->dir);
3737 writeV2F1000(os, form->align);
3738 writeV2F1000(os, form->offset);
3741 std::string s = os.str();
3742 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3744 m_con.Send(peer_id, 0, data, true);
3747 void Server::SendHUDRemove(u16 peer_id, u32 id)
3749 std::ostringstream os(std::ios_base::binary);
3752 writeU16(os, TOCLIENT_HUDRM);
3756 std::string s = os.str();
3757 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3759 m_con.Send(peer_id, 0, data, true);
3762 void Server::SendHUDChange(u16 peer_id, u32 id, HudElementStat stat, void *value)
3764 std::ostringstream os(std::ios_base::binary);
3767 writeU16(os, TOCLIENT_HUDCHANGE);
3769 writeU8(os, (u8)stat);
3772 case HUD_STAT_SCALE:
3773 case HUD_STAT_ALIGN:
3774 case HUD_STAT_OFFSET:
3775 writeV2F1000(os, *(v2f *)value);
3779 os << serializeString(*(std::string *)value);
3781 case HUD_STAT_NUMBER:
3785 writeU32(os, *(u32 *)value);
3790 std::string s = os.str();
3791 SharedBuffer<u8> data((u8 *)s.c_str(), s.size());
3793 m_con.Send(peer_id, 0, data, true);
3796 void Server::SendHUDSetFlags(u16 peer_id, u32 flags, u32 mask)
3798 std::ostringstream os(std::ios_base::binary);
3801 writeU16(os, TOCLIENT_HUD_SET_FLAGS);
3802 writeU32(os, flags);
3806 std::string s = os.str();
3807 SharedBuffer<u8> data((u8 *)s.c_str(), s.size());
3809 m_con.Send(peer_id, 0, data, true);
3812 void Server::SendHUDSetParam(u16 peer_id, u16 param, const std::string &value)
3814 std::ostringstream os(std::ios_base::binary);
3817 writeU16(os, TOCLIENT_HUD_SET_PARAM);
3818 writeU16(os, param);
3819 os<<serializeString(value);
3822 std::string s = os.str();
3823 SharedBuffer<u8> data((u8 *)s.c_str(), s.size());
3825 m_con.Send(peer_id, 0, data, true);
3828 void Server::BroadcastChatMessage(const std::wstring &message)
3830 for(std::map<u16, RemoteClient*>::iterator
3831 i = m_clients.begin();
3832 i != m_clients.end(); ++i)
3834 // Get client and check that it is valid
3835 RemoteClient *client = i->second;
3836 assert(client->peer_id == i->first);
3837 if(client->serialization_version == SER_FMT_VER_INVALID)
3840 SendChatMessage(client->peer_id, message);
3844 void Server::SendPlayerHP(u16 peer_id)
3846 DSTACK(__FUNCTION_NAME);
3847 PlayerSAO *playersao = getPlayerSAO(peer_id);
3849 playersao->m_hp_not_sent = false;
3850 SendHP(m_con, peer_id, playersao->getHP());
3853 void Server::SendPlayerBreath(u16 peer_id)
3855 DSTACK(__FUNCTION_NAME);
3856 PlayerSAO *playersao = getPlayerSAO(peer_id);
3858 playersao->m_breath_not_sent = false;
3859 SendBreath(m_con, peer_id, playersao->getBreath());
3862 void Server::SendMovePlayer(u16 peer_id)
3864 DSTACK(__FUNCTION_NAME);
3865 Player *player = m_env->getPlayer(peer_id);
3868 std::ostringstream os(std::ios_base::binary);
3869 writeU16(os, TOCLIENT_MOVE_PLAYER);
3870 writeV3F1000(os, player->getPosition());
3871 writeF1000(os, player->getPitch());
3872 writeF1000(os, player->getYaw());
3875 v3f pos = player->getPosition();
3876 f32 pitch = player->getPitch();
3877 f32 yaw = player->getYaw();
3878 verbosestream<<"Server: Sending TOCLIENT_MOVE_PLAYER"
3879 <<" pos=("<<pos.X<<","<<pos.Y<<","<<pos.Z<<")"
3886 std::string s = os.str();
3887 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3889 m_con.Send(peer_id, 0, data, true);
3892 void Server::SendPlayerPrivileges(u16 peer_id)
3894 Player *player = m_env->getPlayer(peer_id);
3896 if(player->peer_id == PEER_ID_INEXISTENT)
3899 std::set<std::string> privs;
3900 m_script->getAuth(player->getName(), NULL, &privs);
3902 std::ostringstream os(std::ios_base::binary);
3903 writeU16(os, TOCLIENT_PRIVILEGES);
3904 writeU16(os, privs.size());
3905 for(std::set<std::string>::const_iterator i = privs.begin();
3906 i != privs.end(); i++){
3907 os<<serializeString(*i);
3911 std::string s = os.str();
3912 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3914 m_con.Send(peer_id, 0, data, true);
3917 void Server::SendPlayerInventoryFormspec(u16 peer_id)
3919 Player *player = m_env->getPlayer(peer_id);
3921 if(player->peer_id == PEER_ID_INEXISTENT)
3924 std::ostringstream os(std::ios_base::binary);
3925 writeU16(os, TOCLIENT_INVENTORY_FORMSPEC);
3926 os<<serializeLongString(player->inventory_formspec);
3929 std::string s = os.str();
3930 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3932 m_con.Send(peer_id, 0, data, true);
3935 s32 Server::playSound(const SimpleSoundSpec &spec,
3936 const ServerSoundParams ¶ms)
3938 // Find out initial position of sound
3939 bool pos_exists = false;
3940 v3f pos = params.getPos(m_env, &pos_exists);
3941 // If position is not found while it should be, cancel sound
3942 if(pos_exists != (params.type != ServerSoundParams::SSP_LOCAL))
3944 // Filter destination clients
3945 std::set<RemoteClient*> dst_clients;
3946 if(params.to_player != "")
3948 Player *player = m_env->getPlayer(params.to_player.c_str());
3950 infostream<<"Server::playSound: Player \""<<params.to_player
3951 <<"\" not found"<<std::endl;
3954 if(player->peer_id == PEER_ID_INEXISTENT){
3955 infostream<<"Server::playSound: Player \""<<params.to_player
3956 <<"\" not connected"<<std::endl;
3959 RemoteClient *client = getClient(player->peer_id);
3960 dst_clients.insert(client);
3964 for(std::map<u16, RemoteClient*>::iterator
3965 i = m_clients.begin(); i != m_clients.end(); ++i)
3967 RemoteClient *client = i->second;
3968 Player *player = m_env->getPlayer(client->peer_id);
3972 if(player->getPosition().getDistanceFrom(pos) >
3973 params.max_hear_distance)
3976 dst_clients.insert(client);
3979 if(dst_clients.size() == 0)
3982 s32 id = m_next_sound_id++;
3983 // The sound will exist as a reference in m_playing_sounds
3984 m_playing_sounds[id] = ServerPlayingSound();
3985 ServerPlayingSound &psound = m_playing_sounds[id];
3986 psound.params = params;
3987 for(std::set<RemoteClient*>::iterator i = dst_clients.begin();
3988 i != dst_clients.end(); i++)
3989 psound.clients.insert((*i)->peer_id);
3991 std::ostringstream os(std::ios_base::binary);
3992 writeU16(os, TOCLIENT_PLAY_SOUND);
3994 os<<serializeString(spec.name);
3995 writeF1000(os, spec.gain * params.gain);
3996 writeU8(os, params.type);
3997 writeV3F1000(os, pos);
3998 writeU16(os, params.object);
3999 writeU8(os, params.loop);
4001 std::string s = os.str();
4002 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
4004 for(std::set<RemoteClient*>::iterator i = dst_clients.begin();
4005 i != dst_clients.end(); i++){
4007 m_con.Send((*i)->peer_id, 0, data, true);
4011 void Server::stopSound(s32 handle)
4013 // Get sound reference
4014 std::map<s32, ServerPlayingSound>::iterator i =
4015 m_playing_sounds.find(handle);
4016 if(i == m_playing_sounds.end())
4018 ServerPlayingSound &psound = i->second;
4020 std::ostringstream os(std::ios_base::binary);
4021 writeU16(os, TOCLIENT_STOP_SOUND);
4022 writeS32(os, handle);
4024 std::string s = os.str();
4025 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
4027 for(std::set<u16>::iterator i = psound.clients.begin();
4028 i != psound.clients.end(); i++){
4030 m_con.Send(*i, 0, data, true);
4032 // Remove sound reference
4033 m_playing_sounds.erase(i);
4036 void Server::sendRemoveNode(v3s16 p, u16 ignore_id,
4037 std::list<u16> *far_players, float far_d_nodes)
4039 float maxd = far_d_nodes*BS;
4040 v3f p_f = intToFloat(p, BS);
4044 SharedBuffer<u8> reply(replysize);
4045 writeU16(&reply[0], TOCLIENT_REMOVENODE);
4046 writeS16(&reply[2], p.X);
4047 writeS16(&reply[4], p.Y);
4048 writeS16(&reply[6], p.Z);
4050 for(std::map<u16, RemoteClient*>::iterator
4051 i = m_clients.begin();
4052 i != m_clients.end(); ++i)
4054 // Get client and check that it is valid
4055 RemoteClient *client = i->second;
4056 assert(client->peer_id == i->first);
4057 if(client->serialization_version == SER_FMT_VER_INVALID)
4060 // Don't send if it's the same one
4061 if(client->peer_id == ignore_id)
4067 Player *player = m_env->getPlayer(client->peer_id);
4070 // If player is far away, only set modified blocks not sent
4071 v3f player_pos = player->getPosition();
4072 if(player_pos.getDistanceFrom(p_f) > maxd)
4074 far_players->push_back(client->peer_id);
4081 m_con.Send(client->peer_id, 0, reply, true);
4085 void Server::sendAddNode(v3s16 p, MapNode n, u16 ignore_id,
4086 std::list<u16> *far_players, float far_d_nodes)
4088 float maxd = far_d_nodes*BS;
4089 v3f p_f = intToFloat(p, BS);
4091 for(std::map<u16, RemoteClient*>::iterator
4092 i = m_clients.begin();
4093 i != m_clients.end(); ++i)
4095 // Get client and check that it is valid
4096 RemoteClient *client = i->second;
4097 assert(client->peer_id == i->first);
4098 if(client->serialization_version == SER_FMT_VER_INVALID)
4101 // Don't send if it's the same one
4102 if(client->peer_id == ignore_id)
4108 Player *player = m_env->getPlayer(client->peer_id);
4111 // If player is far away, only set modified blocks not sent
4112 v3f player_pos = player->getPosition();
4113 if(player_pos.getDistanceFrom(p_f) > maxd)
4115 far_players->push_back(client->peer_id);
4122 u32 replysize = 8 + MapNode::serializedLength(client->serialization_version);
4123 SharedBuffer<u8> reply(replysize);
4124 writeU16(&reply[0], TOCLIENT_ADDNODE);
4125 writeS16(&reply[2], p.X);
4126 writeS16(&reply[4], p.Y);
4127 writeS16(&reply[6], p.Z);
4128 n.serialize(&reply[8], client->serialization_version);
4131 m_con.Send(client->peer_id, 0, reply, true);
4135 void Server::setBlockNotSent(v3s16 p)
4137 for(std::map<u16, RemoteClient*>::iterator
4138 i = m_clients.begin();
4139 i != m_clients.end(); ++i)
4141 RemoteClient *client = i->second;
4142 client->SetBlockNotSent(p);
4146 void Server::SendBlockNoLock(u16 peer_id, MapBlock *block, u8 ver, u16 net_proto_version)
4148 DSTACK(__FUNCTION_NAME);
4150 v3s16 p = block->getPos();
4154 bool completely_air = true;
4155 for(s16 z0=0; z0<MAP_BLOCKSIZE; z0++)
4156 for(s16 x0=0; x0<MAP_BLOCKSIZE; x0++)
4157 for(s16 y0=0; y0<MAP_BLOCKSIZE; y0++)
4159 if(block->getNodeNoEx(v3s16(x0,y0,z0)).d != CONTENT_AIR)
4161 completely_air = false;
4162 x0 = y0 = z0 = MAP_BLOCKSIZE; // Break out
4167 infostream<<"Server: Sending block ("<<p.X<<","<<p.Y<<","<<p.Z<<"): ";
4169 infostream<<"[completely air] ";
4170 infostream<<std::endl;
4174 Create a packet with the block in the right format
4177 std::ostringstream os(std::ios_base::binary);
4178 block->serialize(os, ver, false);
4179 block->serializeNetworkSpecific(os, net_proto_version);
4180 std::string s = os.str();
4181 SharedBuffer<u8> blockdata((u8*)s.c_str(), s.size());
4183 u32 replysize = 8 + blockdata.getSize();
4184 SharedBuffer<u8> reply(replysize);
4185 writeU16(&reply[0], TOCLIENT_BLOCKDATA);
4186 writeS16(&reply[2], p.X);
4187 writeS16(&reply[4], p.Y);
4188 writeS16(&reply[6], p.Z);
4189 memcpy(&reply[8], *blockdata, blockdata.getSize());
4191 /*infostream<<"Server: Sending block ("<<p.X<<","<<p.Y<<","<<p.Z<<")"
4192 <<": \tpacket size: "<<replysize<<std::endl;*/
4197 m_con.Send(peer_id, 1, reply, true);
4200 void Server::SendBlocks(float dtime)
4202 DSTACK(__FUNCTION_NAME);
4204 JMutexAutoLock envlock(m_env_mutex);
4205 JMutexAutoLock conlock(m_con_mutex);
4207 ScopeProfiler sp(g_profiler, "Server: sel and send blocks to clients");
4209 std::vector<PrioritySortedBlockTransfer> queue;
4211 s32 total_sending = 0;
4214 ScopeProfiler sp(g_profiler, "Server: selecting blocks for sending");
4216 for(std::map<u16, RemoteClient*>::iterator
4217 i = m_clients.begin();
4218 i != m_clients.end(); ++i)
4220 RemoteClient *client = i->second;
4221 assert(client->peer_id == i->first);
4223 // If definitions and textures have not been sent, don't
4224 // send MapBlocks either
4225 if(!client->definitions_sent)
4228 total_sending += client->SendingCount();
4230 if(client->serialization_version == SER_FMT_VER_INVALID)
4233 client->GetNextBlocks(this, dtime, queue);
4238 // Lowest priority number comes first.
4239 // Lowest is most important.
4240 std::sort(queue.begin(), queue.end());
4242 for(u32 i=0; i<queue.size(); i++)
4244 //TODO: Calculate limit dynamically
4245 if(total_sending >= g_settings->getS32
4246 ("max_simultaneous_block_sends_server_total"))
4249 PrioritySortedBlockTransfer q = queue[i];
4251 MapBlock *block = NULL;
4254 block = m_env->getMap().getBlockNoCreate(q.pos);
4256 catch(InvalidPositionException &e)
4261 RemoteClient *client = getClientNoEx(q.peer_id);
4267 SendBlockNoLock(q.peer_id, block, client->serialization_version, client->net_proto_version);
4269 client->SentBlock(q.pos);
4275 void Server::fillMediaCache()
4277 DSTACK(__FUNCTION_NAME);
4279 infostream<<"Server: Calculating media file checksums"<<std::endl;
4281 // Collect all media file paths
4282 std::list<std::string> paths;
4283 for(std::vector<ModSpec>::iterator i = m_mods.begin();
4284 i != m_mods.end(); i++){
4285 const ModSpec &mod = *i;
4286 paths.push_back(mod.path + DIR_DELIM + "textures");
4287 paths.push_back(mod.path + DIR_DELIM + "sounds");
4288 paths.push_back(mod.path + DIR_DELIM + "media");
4289 paths.push_back(mod.path + DIR_DELIM + "models");
4291 paths.push_back(porting::path_user + DIR_DELIM + "textures" + DIR_DELIM + "server");
4293 // Collect media file information from paths into cache
4294 for(std::list<std::string>::iterator i = paths.begin();
4295 i != paths.end(); i++)
4297 std::string mediapath = *i;
4298 std::vector<fs::DirListNode> dirlist = fs::GetDirListing(mediapath);
4299 for(u32 j=0; j<dirlist.size(); j++){
4300 if(dirlist[j].dir) // Ignode dirs
4302 std::string filename = dirlist[j].name;
4303 // If name contains illegal characters, ignore the file
4304 if(!string_allowed(filename, TEXTURENAME_ALLOWED_CHARS)){
4305 infostream<<"Server: ignoring illegal file name: \""
4306 <<filename<<"\""<<std::endl;
4309 // If name is not in a supported format, ignore it
4310 const char *supported_ext[] = {
4311 ".png", ".jpg", ".bmp", ".tga",
4312 ".pcx", ".ppm", ".psd", ".wal", ".rgb",
4314 ".x", ".b3d", ".md2", ".obj",
4317 if(removeStringEnd(filename, supported_ext) == ""){
4318 infostream<<"Server: ignoring unsupported file extension: \""
4319 <<filename<<"\""<<std::endl;
4322 // Ok, attempt to load the file and add to cache
4323 std::string filepath = mediapath + DIR_DELIM + filename;
4325 std::ifstream fis(filepath.c_str(), std::ios_base::binary);
4326 if(fis.good() == false){
4327 errorstream<<"Server::fillMediaCache(): Could not open \""
4328 <<filename<<"\" for reading"<<std::endl;
4331 std::ostringstream tmp_os(std::ios_base::binary);
4335 fis.read(buf, 1024);
4336 std::streamsize len = fis.gcount();
4337 tmp_os.write(buf, len);
4346 errorstream<<"Server::fillMediaCache(): Failed to read \""
4347 <<filename<<"\""<<std::endl;
4350 if(tmp_os.str().length() == 0){
4351 errorstream<<"Server::fillMediaCache(): Empty file \""
4352 <<filepath<<"\""<<std::endl;
4357 sha1.addBytes(tmp_os.str().c_str(), tmp_os.str().length());
4359 unsigned char *digest = sha1.getDigest();
4360 std::string sha1_base64 = base64_encode(digest, 20);
4361 std::string sha1_hex = hex_encode((char*)digest, 20);
4365 this->m_media[filename] = MediaInfo(filepath, sha1_base64);
4366 verbosestream<<"Server: "<<sha1_hex<<" is "<<filename<<std::endl;
4371 struct SendableMediaAnnouncement
4374 std::string sha1_digest;
4376 SendableMediaAnnouncement(const std::string name_="",
4377 const std::string sha1_digest_=""):
4379 sha1_digest(sha1_digest_)
4383 void Server::sendMediaAnnouncement(u16 peer_id)
4385 DSTACK(__FUNCTION_NAME);
4387 verbosestream<<"Server: Announcing files to id("<<peer_id<<")"
4390 std::list<SendableMediaAnnouncement> file_announcements;
4392 for(std::map<std::string, MediaInfo>::iterator i = m_media.begin();
4393 i != m_media.end(); i++){
4395 file_announcements.push_back(
4396 SendableMediaAnnouncement(i->first, i->second.sha1_digest));
4400 std::ostringstream os(std::ios_base::binary);
4408 u16 length of sha1_digest
4413 writeU16(os, TOCLIENT_ANNOUNCE_MEDIA);
4414 writeU16(os, file_announcements.size());
4416 for(std::list<SendableMediaAnnouncement>::iterator
4417 j = file_announcements.begin();
4418 j != file_announcements.end(); ++j){
4419 os<<serializeString(j->name);
4420 os<<serializeString(j->sha1_digest);
4422 os<<serializeString(g_settings->get("remote_media"));
4425 std::string s = os.str();
4426 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
4429 m_con.Send(peer_id, 0, data, true);
4432 struct SendableMedia
4438 SendableMedia(const std::string &name_="", const std::string path_="",
4439 const std::string &data_=""):
4446 void Server::sendRequestedMedia(u16 peer_id,
4447 const std::list<MediaRequest> &tosend)
4449 DSTACK(__FUNCTION_NAME);
4451 verbosestream<<"Server::sendRequestedMedia(): "
4452 <<"Sending files to client"<<std::endl;
4456 // Put 5kB in one bunch (this is not accurate)
4457 u32 bytes_per_bunch = 5000;
4459 std::vector< std::list<SendableMedia> > file_bunches;
4460 file_bunches.push_back(std::list<SendableMedia>());
4462 u32 file_size_bunch_total = 0;
4464 for(std::list<MediaRequest>::const_iterator i = tosend.begin();
4465 i != tosend.end(); ++i)
4467 if(m_media.find(i->name) == m_media.end()){
4468 errorstream<<"Server::sendRequestedMedia(): Client asked for "
4469 <<"unknown file \""<<(i->name)<<"\""<<std::endl;
4473 //TODO get path + name
4474 std::string tpath = m_media[(*i).name].path;
4477 std::ifstream fis(tpath.c_str(), std::ios_base::binary);
4478 if(fis.good() == false){
4479 errorstream<<"Server::sendRequestedMedia(): Could not open \""
4480 <<tpath<<"\" for reading"<<std::endl;
4483 std::ostringstream tmp_os(std::ios_base::binary);
4487 fis.read(buf, 1024);
4488 std::streamsize len = fis.gcount();
4489 tmp_os.write(buf, len);
4490 file_size_bunch_total += len;
4499 errorstream<<"Server::sendRequestedMedia(): Failed to read \""
4500 <<(*i).name<<"\""<<std::endl;
4503 /*infostream<<"Server::sendRequestedMedia(): Loaded \""
4504 <<tname<<"\""<<std::endl;*/
4506 file_bunches[file_bunches.size()-1].push_back(
4507 SendableMedia((*i).name, tpath, tmp_os.str()));
4509 // Start next bunch if got enough data
4510 if(file_size_bunch_total >= bytes_per_bunch){
4511 file_bunches.push_back(std::list<SendableMedia>());
4512 file_size_bunch_total = 0;
4517 /* Create and send packets */
4519 u32 num_bunches = file_bunches.size();
4520 for(u32 i=0; i<num_bunches; i++)
4522 std::ostringstream os(std::ios_base::binary);
4526 u16 total number of texture bunches
4527 u16 index of this bunch
4528 u32 number of files in this bunch
4537 writeU16(os, TOCLIENT_MEDIA);
4538 writeU16(os, num_bunches);
4540 writeU32(os, file_bunches[i].size());
4542 for(std::list<SendableMedia>::iterator
4543 j = file_bunches[i].begin();
4544 j != file_bunches[i].end(); ++j){
4545 os<<serializeString(j->name);
4546 os<<serializeLongString(j->data);
4550 std::string s = os.str();
4551 verbosestream<<"Server::sendRequestedMedia(): bunch "
4552 <<i<<"/"<<num_bunches
4553 <<" files="<<file_bunches[i].size()
4554 <<" size=" <<s.size()<<std::endl;
4555 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
4557 m_con.Send(peer_id, 0, data, true);
4561 void Server::sendDetachedInventory(const std::string &name, u16 peer_id)
4563 if(m_detached_inventories.count(name) == 0){
4564 errorstream<<__FUNCTION_NAME<<": \""<<name<<"\" not found"<<std::endl;
4567 Inventory *inv = m_detached_inventories[name];
4569 std::ostringstream os(std::ios_base::binary);
4570 writeU16(os, TOCLIENT_DETACHED_INVENTORY);
4571 os<<serializeString(name);
4575 std::string s = os.str();
4576 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
4578 m_con.Send(peer_id, 0, data, true);
4581 void Server::sendDetachedInventoryToAll(const std::string &name)
4583 DSTACK(__FUNCTION_NAME);
4585 for(std::map<u16, RemoteClient*>::iterator
4586 i = m_clients.begin();
4587 i != m_clients.end(); ++i){
4588 RemoteClient *client = i->second;
4589 sendDetachedInventory(name, client->peer_id);
4593 void Server::sendDetachedInventories(u16 peer_id)
4595 DSTACK(__FUNCTION_NAME);
4597 for(std::map<std::string, Inventory*>::iterator
4598 i = m_detached_inventories.begin();
4599 i != m_detached_inventories.end(); i++){
4600 const std::string &name = i->first;
4601 //Inventory *inv = i->second;
4602 sendDetachedInventory(name, peer_id);
4610 void Server::DiePlayer(u16 peer_id)
4612 DSTACK(__FUNCTION_NAME);
4614 PlayerSAO *playersao = getPlayerSAO(peer_id);
4617 infostream<<"Server::DiePlayer(): Player "
4618 <<playersao->getPlayer()->getName()
4619 <<" dies"<<std::endl;
4621 playersao->setHP(0);
4623 // Trigger scripted stuff
4624 m_script->on_dieplayer(playersao);
4626 SendPlayerHP(peer_id);
4627 SendDeathscreen(m_con, peer_id, false, v3f(0,0,0));
4630 void Server::RespawnPlayer(u16 peer_id)
4632 DSTACK(__FUNCTION_NAME);
4634 PlayerSAO *playersao = getPlayerSAO(peer_id);
4637 infostream<<"Server::RespawnPlayer(): Player "
4638 <<playersao->getPlayer()->getName()
4639 <<" respawns"<<std::endl;
4641 playersao->setHP(PLAYER_MAX_HP);
4643 bool repositioned = m_script->on_respawnplayer(playersao);
4645 v3f pos = findSpawnPos(m_env->getServerMap());
4646 playersao->setPos(pos);
4650 void Server::DenyAccess(u16 peer_id, const std::wstring &reason)
4652 DSTACK(__FUNCTION_NAME);
4654 SendAccessDenied(m_con, peer_id, reason);
4656 RemoteClient *client = getClientNoEx(peer_id);
4658 client->denied = true;
4660 // If there are way too many clients, get rid of denied new ones immediately
4661 if(m_clients.size() > 2 * g_settings->getU16("max_users")){
4662 verbosestream<<"Server: DenyAccess: Too many clients; getting rid of "
4663 <<"peer_id="<<peer_id<<" immediately"<<std::endl;
4664 // Delete peer to stop sending it data
4665 m_con.DeletePeer(peer_id);
4666 // Delete client also to stop block sends and other stuff
4667 DeleteClient(peer_id, CDR_DENY);
4671 void Server::DeleteClient(u16 peer_id, ClientDeletionReason reason)
4673 DSTACK(__FUNCTION_NAME);
4676 std::map<u16, RemoteClient*>::iterator n;
4677 n = m_clients.find(peer_id);
4678 // The client may not exist; clients are immediately removed if their
4679 // access is denied, and this event occurs later then.
4680 if(n == m_clients.end())
4684 Mark objects to be not known by the client
4686 RemoteClient *client = n->second;
4688 for(std::set<u16>::iterator
4689 i = client->m_known_objects.begin();
4690 i != client->m_known_objects.end(); ++i)
4694 ServerActiveObject* obj = m_env->getActiveObject(id);
4696 if(obj && obj->m_known_by_count > 0)
4697 obj->m_known_by_count--;
4701 Clear references to playing sounds
4703 for(std::map<s32, ServerPlayingSound>::iterator
4704 i = m_playing_sounds.begin();
4705 i != m_playing_sounds.end();)
4707 ServerPlayingSound &psound = i->second;
4708 psound.clients.erase(peer_id);
4709 if(psound.clients.size() == 0)
4710 m_playing_sounds.erase(i++);
4715 Player *player = m_env->getPlayer(peer_id);
4717 // Collect information about leaving in chat
4718 std::wstring message;
4720 if(player != NULL && reason != CDR_DENY)
4722 std::wstring name = narrow_to_wide(player->getName());
4725 message += L" left the game.";
4726 if(reason == CDR_TIMEOUT)
4727 message += L" (timed out)";
4731 /* Run scripts and remove from environment */
4735 PlayerSAO *playersao = player->getPlayerSAO();
4738 m_script->on_leaveplayer(playersao);
4740 playersao->disconnected();
4748 if(player != NULL && reason != CDR_DENY)
4750 std::ostringstream os(std::ios_base::binary);
4751 for(std::map<u16, RemoteClient*>::iterator
4752 i = m_clients.begin();
4753 i != m_clients.end(); ++i)
4755 RemoteClient *client = i->second;
4756 assert(client->peer_id == i->first);
4757 if(client->serialization_version == SER_FMT_VER_INVALID)
4760 Player *player = m_env->getPlayer(client->peer_id);
4763 // Get name of player
4764 os<<player->getName()<<" ";
4767 actionstream<<player->getName()<<" "
4768 <<(reason==CDR_TIMEOUT?"times out.":"leaves game.")
4769 <<" List of players: "<<os.str()<<std::endl;
4774 delete m_clients[peer_id];
4775 m_clients.erase(peer_id);
4777 // Send player info to all remaining clients
4778 //SendPlayerInfos();
4780 // Send leave chat message to all remaining clients
4781 if(message.length() != 0)
4782 BroadcastChatMessage(message);
4785 void Server::UpdateCrafting(u16 peer_id)
4787 DSTACK(__FUNCTION_NAME);
4789 Player* player = m_env->getPlayer(peer_id);
4792 // Get a preview for crafting
4794 getCraftingResult(&player->inventory, preview, false, this);
4796 // Put the new preview in
4797 InventoryList *plist = player->inventory.getList("craftpreview");
4799 assert(plist->getSize() >= 1);
4800 plist->changeItem(0, preview);
4803 RemoteClient* Server::getClient(u16 peer_id)
4805 RemoteClient *client = getClientNoEx(peer_id);
4807 throw ClientNotFoundException("Client not found");
4810 RemoteClient* Server::getClientNoEx(u16 peer_id)
4812 std::map<u16, RemoteClient*>::iterator n;
4813 n = m_clients.find(peer_id);
4814 // The client may not exist; clients are immediately removed if their
4815 // access is denied, and this event occurs later then.
4816 if(n == m_clients.end())
4821 std::wstring Server::getStatusString()
4823 std::wostringstream os(std::ios_base::binary);
4826 os<<L"version="<<narrow_to_wide(VERSION_STRING);
4828 os<<L", uptime="<<m_uptime.get();
4830 os<<L", max_lag="<<m_env->getMaxLagEstimate();
4831 // Information about clients
4832 std::map<u16, RemoteClient*>::iterator i;
4835 for(i = m_clients.begin(), first = true;
4836 i != m_clients.end(); ++i)
4838 // Get client and check that it is valid
4839 RemoteClient *client = i->second;
4840 assert(client->peer_id == i->first);
4841 if(client->serialization_version == SER_FMT_VER_INVALID)
4844 Player *player = m_env->getPlayer(client->peer_id);
4845 // Get name of player
4846 std::wstring name = L"unknown";
4848 name = narrow_to_wide(player->getName());
4849 // Add name to information string
4857 if(((ServerMap*)(&m_env->getMap()))->isSavingEnabled() == false)
4858 os<<std::endl<<L"# Server: "<<" WARNING: Map saving is disabled.";
4859 if(g_settings->get("motd") != "")
4860 os<<std::endl<<L"# Server: "<<narrow_to_wide(g_settings->get("motd"));
4864 std::set<std::string> Server::getPlayerEffectivePrivs(const std::string &name)
4866 std::set<std::string> privs;
4867 m_script->getAuth(name, NULL, &privs);
4871 bool Server::checkPriv(const std::string &name, const std::string &priv)
4873 std::set<std::string> privs = getPlayerEffectivePrivs(name);
4874 return (privs.count(priv) != 0);
4877 void Server::reportPrivsModified(const std::string &name)
4880 for(std::map<u16, RemoteClient*>::iterator
4881 i = m_clients.begin();
4882 i != m_clients.end(); ++i){
4883 RemoteClient *client = i->second;
4884 Player *player = m_env->getPlayer(client->peer_id);
4885 reportPrivsModified(player->getName());
4888 Player *player = m_env->getPlayer(name.c_str());
4891 SendPlayerPrivileges(player->peer_id);
4892 PlayerSAO *sao = player->getPlayerSAO();
4895 sao->updatePrivileges(
4896 getPlayerEffectivePrivs(name),
4901 void Server::reportInventoryFormspecModified(const std::string &name)
4903 Player *player = m_env->getPlayer(name.c_str());
4906 SendPlayerInventoryFormspec(player->peer_id);
4909 // Saves g_settings to configpath given at initialization
4910 void Server::saveConfig()
4912 if(m_path_config != "")
4913 g_settings->updateConfigFile(m_path_config.c_str());
4916 void Server::notifyPlayer(const char *name, const std::wstring msg, const bool prepend = true)
4918 Player *player = m_env->getPlayer(name);
4922 SendChatMessage(player->peer_id, std::wstring(L"Server -!- ")+msg);
4924 SendChatMessage(player->peer_id, msg);
4927 bool Server::showFormspec(const char *playername, const std::string &formspec, const std::string &formname)
4929 Player *player = m_env->getPlayer(playername);
4933 infostream<<"showFormspec: couldn't find player:"<<playername<<std::endl;
4937 SendShowFormspecMessage(player->peer_id, formspec, formname);
4941 u32 Server::hudAdd(Player *player, HudElement *form) {
4945 u32 id = hud_get_free_id(player);
4946 if (id < player->hud.size())
4947 player->hud[id] = form;
4949 player->hud.push_back(form);
4951 SendHUDAdd(player->peer_id, id, form);
4955 bool Server::hudRemove(Player *player, u32 id) {
4956 if (!player || id >= player->hud.size() || !player->hud[id])
4959 delete player->hud[id];
4960 player->hud[id] = NULL;
4962 SendHUDRemove(player->peer_id, id);
4966 bool Server::hudChange(Player *player, u32 id, HudElementStat stat, void *data) {
4970 SendHUDChange(player->peer_id, id, stat, data);
4974 bool Server::hudSetFlags(Player *player, u32 flags, u32 mask) {
4978 SendHUDSetFlags(player->peer_id, flags, mask);
4982 bool Server::hudSetHotbarItemcount(Player *player, s32 hotbar_itemcount) {
4985 if (hotbar_itemcount <= 0 || hotbar_itemcount > HUD_HOTBAR_ITEMCOUNT_MAX)
4988 std::ostringstream os(std::ios::binary);
4989 writeS32(os, hotbar_itemcount);
4990 SendHUDSetParam(player->peer_id, HUD_PARAM_HOTBAR_ITEMCOUNT, os.str());
4994 void Server::notifyPlayers(const std::wstring msg)
4996 BroadcastChatMessage(msg);
4999 void Server::spawnParticle(const char *playername, v3f pos,
5000 v3f velocity, v3f acceleration,
5001 float expirationtime, float size, bool
5002 collisiondetection, std::string texture)
5004 Player *player = m_env->getPlayer(playername);
5007 SendSpawnParticle(player->peer_id, pos, velocity, acceleration,
5008 expirationtime, size, collisiondetection, texture);
5011 void Server::spawnParticleAll(v3f pos, v3f velocity, v3f acceleration,
5012 float expirationtime, float size,
5013 bool collisiondetection, std::string texture)
5015 SendSpawnParticleAll(pos, velocity, acceleration,
5016 expirationtime, size, collisiondetection, texture);
5019 u32 Server::addParticleSpawner(const char *playername,
5020 u16 amount, float spawntime,
5021 v3f minpos, v3f maxpos,
5022 v3f minvel, v3f maxvel,
5023 v3f minacc, v3f maxacc,
5024 float minexptime, float maxexptime,
5025 float minsize, float maxsize,
5026 bool collisiondetection, std::string texture)
5028 Player *player = m_env->getPlayer(playername);
5033 for(;;) // look for unused particlespawner id
5036 if (std::find(m_particlespawner_ids.begin(),
5037 m_particlespawner_ids.end(), id)
5038 == m_particlespawner_ids.end())
5040 m_particlespawner_ids.push_back(id);
5045 SendAddParticleSpawner(player->peer_id, amount, spawntime,
5046 minpos, maxpos, minvel, maxvel, minacc, maxacc,
5047 minexptime, maxexptime, minsize, maxsize,
5048 collisiondetection, texture, id);
5053 u32 Server::addParticleSpawnerAll(u16 amount, float spawntime,
5054 v3f minpos, v3f maxpos,
5055 v3f minvel, v3f maxvel,
5056 v3f minacc, v3f maxacc,
5057 float minexptime, float maxexptime,
5058 float minsize, float maxsize,
5059 bool collisiondetection, std::string texture)
5062 for(;;) // look for unused particlespawner id
5065 if (std::find(m_particlespawner_ids.begin(),
5066 m_particlespawner_ids.end(), id)
5067 == m_particlespawner_ids.end())
5069 m_particlespawner_ids.push_back(id);
5074 SendAddParticleSpawnerAll(amount, spawntime,
5075 minpos, maxpos, minvel, maxvel, minacc, maxacc,
5076 minexptime, maxexptime, minsize, maxsize,
5077 collisiondetection, texture, id);
5082 void Server::deleteParticleSpawner(const char *playername, u32 id)
5084 Player *player = m_env->getPlayer(playername);
5088 m_particlespawner_ids.erase(
5089 std::remove(m_particlespawner_ids.begin(),
5090 m_particlespawner_ids.end(), id),
5091 m_particlespawner_ids.end());
5092 SendDeleteParticleSpawner(player->peer_id, id);
5095 void Server::deleteParticleSpawnerAll(u32 id)
5097 m_particlespawner_ids.erase(
5098 std::remove(m_particlespawner_ids.begin(),
5099 m_particlespawner_ids.end(), id),
5100 m_particlespawner_ids.end());
5101 SendDeleteParticleSpawnerAll(id);
5104 void Server::queueBlockEmerge(v3s16 blockpos, bool allow_generate)
5106 m_emerge->enqueueBlockEmerge(PEER_ID_INEXISTENT, blockpos, allow_generate);
5109 Inventory* Server::createDetachedInventory(const std::string &name)
5111 if(m_detached_inventories.count(name) > 0){
5112 infostream<<"Server clearing detached inventory \""<<name<<"\""<<std::endl;
5113 delete m_detached_inventories[name];
5115 infostream<<"Server creating detached inventory \""<<name<<"\""<<std::endl;
5117 Inventory *inv = new Inventory(m_itemdef);
5119 m_detached_inventories[name] = inv;
5120 sendDetachedInventoryToAll(name);
5127 BoolScopeSet(bool *dst, bool val):
5130 m_orig_state = *m_dst;
5135 *m_dst = m_orig_state;
5142 // actions: time-reversed list
5143 // Return value: success/failure
5144 bool Server::rollbackRevertActions(const std::list<RollbackAction> &actions,
5145 std::list<std::string> *log)
5147 infostream<<"Server::rollbackRevertActions(len="<<actions.size()<<")"<<std::endl;
5148 ServerMap *map = (ServerMap*)(&m_env->getMap());
5149 // Disable rollback report sink while reverting
5150 BoolScopeSet rollback_scope_disable(&m_rollback_sink_enabled, false);
5152 // Fail if no actions to handle
5153 if(actions.empty()){
5154 log->push_back("Nothing to do.");
5161 for(std::list<RollbackAction>::const_iterator
5162 i = actions.begin();
5163 i != actions.end(); i++)
5165 const RollbackAction &action = *i;
5167 bool success = action.applyRevert(map, this, this);
5170 std::ostringstream os;
5171 os<<"Revert of step ("<<num_tried<<") "<<action.toString()<<" failed";
5172 infostream<<"Map::rollbackRevertActions(): "<<os.str()<<std::endl;
5174 log->push_back(os.str());
5176 std::ostringstream os;
5177 os<<"Successfully reverted step ("<<num_tried<<") "<<action.toString();
5178 infostream<<"Map::rollbackRevertActions(): "<<os.str()<<std::endl;
5180 log->push_back(os.str());
5184 infostream<<"Map::rollbackRevertActions(): "<<num_failed<<"/"<<num_tried
5185 <<" failed"<<std::endl;
5187 // Call it done if less than half failed
5188 return num_failed <= num_tried/2;
5191 // IGameDef interface
5193 IItemDefManager* Server::getItemDefManager()
5197 INodeDefManager* Server::getNodeDefManager()
5201 ICraftDefManager* Server::getCraftDefManager()
5205 ITextureSource* Server::getTextureSource()
5209 IShaderSource* Server::getShaderSource()
5213 u16 Server::allocateUnknownNodeId(const std::string &name)
5215 return m_nodedef->allocateDummy(name);
5217 ISoundManager* Server::getSoundManager()
5219 return &dummySoundManager;
5221 MtEventManager* Server::getEventManager()
5225 IRollbackReportSink* Server::getRollbackReportSink()
5227 if(!m_enable_rollback_recording)
5229 if(!m_rollback_sink_enabled)
5234 IWritableItemDefManager* Server::getWritableItemDefManager()
5238 IWritableNodeDefManager* Server::getWritableNodeDefManager()
5242 IWritableCraftDefManager* Server::getWritableCraftDefManager()
5247 const ModSpec* Server::getModSpec(const std::string &modname)
5249 for(std::vector<ModSpec>::iterator i = m_mods.begin();
5250 i != m_mods.end(); i++){
5251 const ModSpec &mod = *i;
5252 if(mod.name == modname)
5257 void Server::getModNames(std::list<std::string> &modlist)
5259 for(std::vector<ModSpec>::iterator i = m_mods.begin(); i != m_mods.end(); i++)
5261 modlist.push_back(i->name);
5264 std::string Server::getBuiltinLuaPath()
5266 return porting::path_share + DIR_DELIM + "builtin";
5269 v3f findSpawnPos(ServerMap &map)
5271 //return v3f(50,50,50)*BS;
5276 nodepos = v2s16(0,0);
5281 s16 water_level = map.m_mgparams->water_level;
5283 // Try to find a good place a few times
5284 for(s32 i=0; i<1000; i++)
5287 // We're going to try to throw the player to this position
5288 v2s16 nodepos2d = v2s16(
5289 -range + (myrand() % (range * 2)),
5290 -range + (myrand() % (range * 2)));
5292 // Get ground height at point
5293 s16 groundheight = map.findGroundLevel(nodepos2d);
5294 if (groundheight <= water_level) // Don't go underwater
5296 if (groundheight > water_level + 6) // Don't go to high places
5299 nodepos = v3s16(nodepos2d.X, groundheight, nodepos2d.Y);
5300 bool is_good = false;
5302 for (s32 i = 0; i < 10; i++) {
5303 v3s16 blockpos = getNodeBlockPos(nodepos);
5304 map.emergeBlock(blockpos, true);
5305 content_t c = map.getNodeNoEx(nodepos).getContent();
5306 if (c == CONTENT_AIR || c == CONTENT_IGNORE) {
5308 if (air_count >= 2){
5316 // Found a good place
5317 //infostream<<"Searched through "<<i<<" places."<<std::endl;
5323 return intToFloat(nodepos, BS);
5326 PlayerSAO* Server::emergePlayer(const char *name, u16 peer_id)
5328 RemotePlayer *player = NULL;
5329 bool newplayer = false;
5332 Try to get an existing player
5334 player = static_cast<RemotePlayer*>(m_env->getPlayer(name));
5336 // If player is already connected, cancel
5337 if(player != NULL && player->peer_id != 0)
5339 infostream<<"emergePlayer(): Player already connected"<<std::endl;
5344 If player with the wanted peer_id already exists, cancel.
5346 if(m_env->getPlayer(peer_id) != NULL)
5348 infostream<<"emergePlayer(): Player with wrong name but same"
5349 " peer_id already exists"<<std::endl;
5354 Create a new player if it doesn't exist yet
5359 player = new RemotePlayer(this);
5360 player->updateName(name);
5362 /* Set player position */
5363 infostream<<"Server: Finding spawn place for player \""
5364 <<name<<"\""<<std::endl;
5365 v3f pos = findSpawnPos(m_env->getServerMap());
5366 player->setPosition(pos);
5368 /* Add player to environment */
5369 m_env->addPlayer(player);
5373 Create a new player active object
5375 PlayerSAO *playersao = new PlayerSAO(m_env, player, peer_id,
5376 getPlayerEffectivePrivs(player->getName()),
5379 /* Clean up old HUD elements from previous sessions */
5380 player->hud.clear();
5382 /* Add object to environment */
5383 m_env->addActiveObject(playersao);
5387 m_script->on_newplayer(playersao);
5389 m_script->on_joinplayer(playersao);
5394 void Server::handlePeerChange(PeerChange &c)
5396 JMutexAutoLock envlock(m_env_mutex);
5397 JMutexAutoLock conlock(m_con_mutex);
5399 if(c.type == PEER_ADDED)
5406 std::map<u16, RemoteClient*>::iterator n;
5407 n = m_clients.find(c.peer_id);
5408 // The client shouldn't already exist
5409 assert(n == m_clients.end());
5412 RemoteClient *client = new RemoteClient();
5413 client->peer_id = c.peer_id;
5414 m_clients[client->peer_id] = client;
5417 else if(c.type == PEER_REMOVED)
5423 DeleteClient(c.peer_id, c.timeout?CDR_TIMEOUT:CDR_LEAVE);
5432 void Server::handlePeerChanges()
5434 while(m_peer_change_queue.size() > 0)
5436 PeerChange c = m_peer_change_queue.pop_front();
5438 verbosestream<<"Server: Handling peer change: "
5439 <<"id="<<c.peer_id<<", timeout="<<c.timeout
5442 handlePeerChange(c);
5446 void dedicated_server_loop(Server &server, bool &kill)
5448 DSTACK(__FUNCTION_NAME);
5450 verbosestream<<"dedicated_server_loop()"<<std::endl;
5452 IntervalLimiter m_profiler_interval;
5456 float steplen = g_settings->getFloat("dedicated_server_step");
5457 // This is kind of a hack but can be done like this
5458 // because server.step() is very light
5460 ScopeProfiler sp(g_profiler, "dedicated server sleep");
5461 sleep_ms((int)(steplen*1000.0));
5463 server.step(steplen);
5465 if(server.getShutdownRequested() || kill)
5467 infostream<<"Dedicated server quitting"<<std::endl;
5469 if(g_settings->getBool("server_announce") == true)
5470 ServerList::sendAnnounce("delete");
5478 float profiler_print_interval =
5479 g_settings->getFloat("profiler_print_interval");
5480 if(profiler_print_interval != 0)
5482 if(m_profiler_interval.step(steplen, profiler_print_interval))
5484 infostream<<"Profiler:"<<std::endl;
5485 g_profiler->print(infostream);
5486 g_profiler->clear();