3 Copyright (C) 2010-2013 celeron55, Perttu Ahola <celeron55@gmail.com>
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU Lesser General Public License as published by
7 the Free Software Foundation; either version 2.1 of the License, or
8 (at your option) any later version.
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU Lesser General Public License for more details.
15 You should have received a copy of the GNU Lesser General Public License along
16 with this program; if not, write to the Free Software Foundation, Inc.,
17 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
24 #include "clientserver.h"
26 #include "jmutexautolock.h"
28 #include "constants.h"
33 #include "serverobject.h"
37 #include "script/cpp_api/scriptapi.h"
44 #include "content_mapnode.h"
45 #include "content_nodemeta.h"
46 #include "content_abm.h"
47 #include "content_sao.h"
52 #include "sound.h" // dummySoundManager
53 #include "event_manager.h"
55 #include "serverlist.h"
56 #include "util/string.h"
57 #include "util/pointedthing.h"
58 #include "util/mathconstants.h"
60 #include "util/serialize.h"
61 #include "defaultsettings.h"
63 class ClientNotFoundException : public BaseException
66 ClientNotFoundException(const char *s):
71 void * ServerThread::Thread()
75 log_register_thread("ServerThread");
77 DSTACK(__FUNCTION_NAME);
79 BEGIN_DEBUG_EXCEPTION_HANDLER
84 //TimeTaker timer("AsyncRunStep() + Receive()");
87 //TimeTaker timer("AsyncRunStep()");
88 m_server->AsyncRunStep();
91 //infostream<<"Running m_server->Receive()"<<std::endl;
94 catch(con::NoIncomingDataException &e)
97 catch(con::PeerNotFoundException &e)
99 infostream<<"Server: PeerNotFoundException"<<std::endl;
101 catch(ClientNotFoundException &e)
104 catch(con::ConnectionBindFailed &e)
106 m_server->setAsyncFatalError(e.what());
110 m_server->setAsyncFatalError(e.what());
114 END_DEBUG_EXCEPTION_HANDLER(errorstream)
119 v3f ServerSoundParams::getPos(ServerEnvironment *env, bool *pos_exists) const
121 if(pos_exists) *pos_exists = false;
126 if(pos_exists) *pos_exists = true;
131 ServerActiveObject *sao = env->getActiveObject(object);
134 if(pos_exists) *pos_exists = true;
135 return sao->getBasePosition(); }
140 void RemoteClient::GetNextBlocks(Server *server, float dtime,
141 std::vector<PrioritySortedBlockTransfer> &dest)
143 DSTACK(__FUNCTION_NAME);
146 TimeTaker timer("RemoteClient::GetNextBlocks", &timer_result);*/
149 m_nothing_to_send_pause_timer -= dtime;
150 m_nearest_unsent_reset_timer += dtime;
152 if(m_nothing_to_send_pause_timer >= 0)
155 Player *player = server->m_env->getPlayer(peer_id);
156 // This can happen sometimes; clients and players are not in perfect sync.
160 // Won't send anything if already sending
161 if(m_blocks_sending.size() >= g_settings->getU16
162 ("max_simultaneous_block_sends_per_client"))
164 //infostream<<"Not sending any blocks, Queue full."<<std::endl;
168 //TimeTaker timer("RemoteClient::GetNextBlocks");
170 v3f playerpos = player->getPosition();
171 v3f playerspeed = player->getSpeed();
172 v3f playerspeeddir(0,0,0);
173 if(playerspeed.getLength() > 1.0*BS)
174 playerspeeddir = playerspeed / playerspeed.getLength();
175 // Predict to next block
176 v3f playerpos_predicted = playerpos + playerspeeddir*MAP_BLOCKSIZE*BS;
178 v3s16 center_nodepos = floatToInt(playerpos_predicted, BS);
180 v3s16 center = getNodeBlockPos(center_nodepos);
182 // Camera position and direction
183 v3f camera_pos = player->getEyePosition();
184 v3f camera_dir = v3f(0,0,1);
185 camera_dir.rotateYZBy(player->getPitch());
186 camera_dir.rotateXZBy(player->getYaw());
188 /*infostream<<"camera_dir=("<<camera_dir.X<<","<<camera_dir.Y<<","
189 <<camera_dir.Z<<")"<<std::endl;*/
192 Get the starting value of the block finder radius.
195 if(m_last_center != center)
197 m_nearest_unsent_d = 0;
198 m_last_center = center;
201 /*infostream<<"m_nearest_unsent_reset_timer="
202 <<m_nearest_unsent_reset_timer<<std::endl;*/
204 // Reset periodically to workaround for some bugs or stuff
205 if(m_nearest_unsent_reset_timer > 20.0)
207 m_nearest_unsent_reset_timer = 0;
208 m_nearest_unsent_d = 0;
209 //infostream<<"Resetting m_nearest_unsent_d for "
210 // <<server->getPlayerName(peer_id)<<std::endl;
213 //s16 last_nearest_unsent_d = m_nearest_unsent_d;
214 s16 d_start = m_nearest_unsent_d;
216 //infostream<<"d_start="<<d_start<<std::endl;
218 u16 max_simul_sends_setting = g_settings->getU16
219 ("max_simultaneous_block_sends_per_client");
220 u16 max_simul_sends_usually = max_simul_sends_setting;
223 Check the time from last addNode/removeNode.
225 Decrease send rate if player is building stuff.
227 m_time_from_building += dtime;
228 if(m_time_from_building < g_settings->getFloat(
229 "full_block_send_enable_min_time_from_building"))
231 max_simul_sends_usually
232 = LIMITED_MAX_SIMULTANEOUS_BLOCK_SENDS;
236 Number of blocks sending + number of blocks selected for sending
238 u32 num_blocks_selected = m_blocks_sending.size();
241 next time d will be continued from the d from which the nearest
242 unsent block was found this time.
244 This is because not necessarily any of the blocks found this
245 time are actually sent.
247 s32 new_nearest_unsent_d = -1;
249 s16 d_max = g_settings->getS16("max_block_send_distance");
250 s16 d_max_gen = g_settings->getS16("max_block_generate_distance");
252 // Don't loop very much at a time
253 s16 max_d_increment_at_time = 2;
254 if(d_max > d_start + max_d_increment_at_time)
255 d_max = d_start + max_d_increment_at_time;
256 /*if(d_max_gen > d_start+2)
257 d_max_gen = d_start+2;*/
259 //infostream<<"Starting from "<<d_start<<std::endl;
261 s32 nearest_emerged_d = -1;
262 s32 nearest_emergefull_d = -1;
263 s32 nearest_sent_d = -1;
264 bool queue_is_full = false;
267 for(d = d_start; d <= d_max; d++)
269 /*errorstream<<"checking d="<<d<<" for "
270 <<server->getPlayerName(peer_id)<<std::endl;*/
271 //infostream<<"RemoteClient::SendBlocks(): d="<<d<<std::endl;
274 If m_nearest_unsent_d was changed by the EmergeThread
275 (it can change it to 0 through SetBlockNotSent),
277 Else update m_nearest_unsent_d
279 /*if(m_nearest_unsent_d != last_nearest_unsent_d)
281 d = m_nearest_unsent_d;
282 last_nearest_unsent_d = m_nearest_unsent_d;
286 Get the border/face dot coordinates of a "d-radiused"
289 std::list<v3s16> list;
290 getFacePositions(list, d);
292 std::list<v3s16>::iterator li;
293 for(li=list.begin(); li!=list.end(); ++li)
295 v3s16 p = *li + center;
299 - Don't allow too many simultaneous transfers
300 - EXCEPT when the blocks are very close
302 Also, don't send blocks that are already flying.
305 // Start with the usual maximum
306 u16 max_simul_dynamic = max_simul_sends_usually;
308 // If block is very close, allow full maximum
309 if(d <= BLOCK_SEND_DISABLE_LIMITS_MAX_D)
310 max_simul_dynamic = max_simul_sends_setting;
312 // Don't select too many blocks for sending
313 if(num_blocks_selected >= max_simul_dynamic)
315 queue_is_full = true;
316 goto queue_full_break;
319 // Don't send blocks that are currently being transferred
320 if(m_blocks_sending.find(p) != m_blocks_sending.end())
326 if(p.X < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
327 || p.X > MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
328 || p.Y < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
329 || p.Y > MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
330 || p.Z < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
331 || p.Z > MAP_GENERATION_LIMIT / MAP_BLOCKSIZE)
334 // If this is true, inexistent block will be made from scratch
335 bool generate = d <= d_max_gen;
338 /*// Limit the generating area vertically to 2/3
339 if(abs(p.Y - center.Y) > d_max_gen - d_max_gen / 3)
342 // Limit the send area vertically to 1/2
343 if(abs(p.Y - center.Y) > d_max / 2)
349 If block is far away, don't generate it unless it is
355 // Block center y in nodes
356 f32 y = (f32)(p.Y * MAP_BLOCKSIZE + MAP_BLOCKSIZE/2);
357 // Don't generate if it's very high or very low
358 if(y < -64 || y > 64)
362 v2s16 p2d_nodes_center(
366 // Get ground height in nodes
367 s16 gh = server->m_env->getServerMap().findGroundLevel(
370 // If differs a lot, don't generate
371 if(fabs(gh - y) > MAP_BLOCKSIZE*2)
373 // Actually, don't even send it
379 //infostream<<"d="<<d<<std::endl;
382 Don't generate or send if not in sight
383 FIXME This only works if the client uses a small enough
384 FOV setting. The default of 72 degrees is fine.
387 float camera_fov = (72.0*M_PI/180) * 4./3.;
388 if(isBlockInSight(p, camera_pos, camera_dir, camera_fov, 10000*BS) == false)
394 Don't send already sent blocks
397 if(m_blocks_sent.find(p) != m_blocks_sent.end())
404 Check if map has this block
406 MapBlock *block = server->m_env->getMap().getBlockNoCreateNoEx(p);
408 bool surely_not_found_on_disk = false;
409 bool block_is_invalid = false;
412 // Reset usage timer, this block will be of use in the future.
413 block->resetUsageTimer();
415 // Block is dummy if data doesn't exist.
416 // It means it has been not found from disk and not generated
419 surely_not_found_on_disk = true;
422 // Block is valid if lighting is up-to-date and data exists
423 if(block->isValid() == false)
425 block_is_invalid = true;
428 /*if(block->isFullyGenerated() == false)
430 block_is_invalid = true;
435 ServerMap *map = (ServerMap*)(&server->m_env->getMap());
436 v2s16 chunkpos = map->sector_to_chunk(p2d);
437 if(map->chunkNonVolatile(chunkpos) == false)
438 block_is_invalid = true;
440 if(block->isGenerated() == false)
441 block_is_invalid = true;
444 If block is not close, don't send it unless it is near
447 Block is near ground level if night-time mesh
448 differs from day-time mesh.
452 if(block->getDayNightDiff() == false)
459 If block has been marked to not exist on disk (dummy)
460 and generating new ones is not wanted, skip block.
462 if(generate == false && surely_not_found_on_disk == true)
469 Add inexistent block to emerge queue.
471 if(block == NULL || surely_not_found_on_disk || block_is_invalid)
473 /* //TODO: Get value from somewhere
474 // Allow only one block in emerge queue
475 //if(server->m_emerge_queue.peerItemCount(peer_id) < 1)
476 // Allow two blocks in queue per client
477 //if(server->m_emerge_queue.peerItemCount(peer_id) < 2)
479 // Make it more responsive when needing to generate stuff
480 if(surely_not_found_on_disk)
482 if(server->m_emerge_queue.peerItemCount(peer_id) < max_emerge)
484 //infostream<<"Adding block to emerge queue"<<std::endl;
486 // Add it to the emerge queue and trigger the thread
489 if(generate == false)
490 flags |= BLOCK_EMERGE_FLAG_FROMDISK;
492 server->m_emerge_queue.addBlock(peer_id, p, flags);
493 server->m_emergethread.trigger();
495 if(nearest_emerged_d == -1)
496 nearest_emerged_d = d;
498 if(nearest_emergefull_d == -1)
499 nearest_emergefull_d = d;
500 goto queue_full_break;
504 if (server->m_emerge->enqueueBlockEmerge(peer_id, p, generate)) {
505 if (nearest_emerged_d == -1)
506 nearest_emerged_d = d;
508 if (nearest_emergefull_d == -1)
509 nearest_emergefull_d = d;
510 goto queue_full_break;
517 if(nearest_sent_d == -1)
521 Add block to send queue
524 /*errorstream<<"sending from d="<<d<<" to "
525 <<server->getPlayerName(peer_id)<<std::endl;*/
527 PrioritySortedBlockTransfer q((float)d, p, peer_id);
531 num_blocks_selected += 1;
536 //infostream<<"Stopped at "<<d<<std::endl;
538 // If nothing was found for sending and nothing was queued for
539 // emerging, continue next time browsing from here
540 if(nearest_emerged_d != -1){
541 new_nearest_unsent_d = nearest_emerged_d;
542 } else if(nearest_emergefull_d != -1){
543 new_nearest_unsent_d = nearest_emergefull_d;
545 if(d > g_settings->getS16("max_block_send_distance")){
546 new_nearest_unsent_d = 0;
547 m_nothing_to_send_pause_timer = 2.0;
548 /*infostream<<"GetNextBlocks(): d wrapped around for "
549 <<server->getPlayerName(peer_id)
550 <<"; setting to 0 and pausing"<<std::endl;*/
552 if(nearest_sent_d != -1)
553 new_nearest_unsent_d = nearest_sent_d;
555 new_nearest_unsent_d = d;
559 if(new_nearest_unsent_d != -1)
560 m_nearest_unsent_d = new_nearest_unsent_d;
562 /*timer_result = timer.stop(true);
563 if(timer_result != 0)
564 infostream<<"GetNextBlocks timeout: "<<timer_result<<" (!=0)"<<std::endl;*/
567 void RemoteClient::GotBlock(v3s16 p)
569 if(m_blocks_sending.find(p) != m_blocks_sending.end())
570 m_blocks_sending.erase(p);
573 /*infostream<<"RemoteClient::GotBlock(): Didn't find in"
574 " m_blocks_sending"<<std::endl;*/
575 m_excess_gotblocks++;
577 m_blocks_sent.insert(p);
580 void RemoteClient::SentBlock(v3s16 p)
582 if(m_blocks_sending.find(p) == m_blocks_sending.end())
583 m_blocks_sending[p] = 0.0;
585 infostream<<"RemoteClient::SentBlock(): Sent block"
586 " already in m_blocks_sending"<<std::endl;
589 void RemoteClient::SetBlockNotSent(v3s16 p)
591 m_nearest_unsent_d = 0;
593 if(m_blocks_sending.find(p) != m_blocks_sending.end())
594 m_blocks_sending.erase(p);
595 if(m_blocks_sent.find(p) != m_blocks_sent.end())
596 m_blocks_sent.erase(p);
599 void RemoteClient::SetBlocksNotSent(std::map<v3s16, MapBlock*> &blocks)
601 m_nearest_unsent_d = 0;
603 for(std::map<v3s16, MapBlock*>::iterator
605 i != blocks.end(); ++i)
609 if(m_blocks_sending.find(p) != m_blocks_sending.end())
610 m_blocks_sending.erase(p);
611 if(m_blocks_sent.find(p) != m_blocks_sent.end())
612 m_blocks_sent.erase(p);
620 PlayerInfo::PlayerInfo()
626 void PlayerInfo::PrintLine(std::ostream *s)
629 (*s)<<"\""<<name<<"\" ("
630 <<(position.X/10)<<","<<(position.Y/10)
631 <<","<<(position.Z/10)<<") ";
633 (*s)<<" avg_rtt="<<avg_rtt;
642 const std::string &path_world,
643 const std::string &path_config,
644 const SubgameSpec &gamespec,
645 bool simple_singleplayer_mode
647 m_path_world(path_world),
648 m_path_config(path_config),
649 m_gamespec(gamespec),
650 m_simple_singleplayer_mode(simple_singleplayer_mode),
651 m_async_fatal_error(""),
653 m_con(PROTOCOL_ID, 512, CONNECTION_TIMEOUT,
654 g_settings->getBool("enable_ipv6") && g_settings->getBool("ipv6_server"), this),
655 m_banmanager(path_world+DIR_DELIM+"ipban.txt"),
657 m_rollback_sink_enabled(true),
658 m_enable_rollback_recording(false),
661 m_itemdef(createItemDefManager()),
662 m_nodedef(createNodeDefManager()),
663 m_craftdef(createCraftDefManager()),
664 m_event(new EventManager()),
666 m_time_of_day_send_timer(0),
668 m_shutdown_requested(false),
669 m_ignore_map_edit_events(false),
670 m_ignore_map_edit_events_peer_id(0)
672 m_liquid_transform_timer = 0.0;
673 m_liquid_transform_every = 1.0;
674 m_print_info_timer = 0.0;
675 m_masterserver_timer = 0.0;
676 m_objectdata_timer = 0.0;
677 m_emergethread_trigger_timer = 0.0;
678 m_savemap_timer = 0.0;
679 m_clients_number = 0;
683 m_step_dtime_mutex.Init();
687 throw ServerError("Supplied empty world path");
689 if(!gamespec.isValid())
690 throw ServerError("Supplied invalid gamespec");
692 infostream<<"Server created for gameid \""<<m_gamespec.id<<"\"";
693 if(m_simple_singleplayer_mode)
694 infostream<<" in simple singleplayer mode"<<std::endl;
696 infostream<<std::endl;
697 infostream<<"- world: "<<m_path_world<<std::endl;
698 infostream<<"- config: "<<m_path_config<<std::endl;
699 infostream<<"- game: "<<m_gamespec.path<<std::endl;
701 // Initialize default settings and override defaults with those provided
703 set_default_settings(g_settings);
704 Settings gamedefaults;
705 getGameMinetestConfig(gamespec.path, gamedefaults);
706 override_default_settings(g_settings, &gamedefaults);
708 // Create emerge manager
709 m_emerge = new EmergeManager(this);
711 // Create rollback manager
712 std::string rollback_path = m_path_world+DIR_DELIM+"rollback.txt";
713 m_rollback = createRollbackManager(rollback_path, this);
715 // Create world if it doesn't exist
716 if(!initializeWorld(m_path_world, m_gamespec.id))
717 throw ServerError("Failed to initialize world");
719 ModConfiguration modconf(m_path_world);
720 m_mods = modconf.getMods();
721 std::vector<ModSpec> unsatisfied_mods = modconf.getUnsatisfiedMods();
722 // complain about mods with unsatisfied dependencies
723 if(!modconf.isConsistent())
725 for(std::vector<ModSpec>::iterator it = unsatisfied_mods.begin();
726 it != unsatisfied_mods.end(); ++it)
729 errorstream << "mod \"" << mod.name << "\" has unsatisfied dependencies: ";
730 for(std::set<std::string>::iterator dep_it = mod.unsatisfied_depends.begin();
731 dep_it != mod.unsatisfied_depends.end(); ++dep_it)
732 errorstream << " \"" << *dep_it << "\"";
733 errorstream << std::endl;
737 Settings worldmt_settings;
738 std::string worldmt = m_path_world + DIR_DELIM + "world.mt";
739 worldmt_settings.readConfigFile(worldmt.c_str());
740 std::vector<std::string> names = worldmt_settings.getNames();
741 std::set<std::string> load_mod_names;
742 for(std::vector<std::string>::iterator it = names.begin();
743 it != names.end(); ++it)
745 std::string name = *it;
746 if(name.compare(0,9,"load_mod_")==0 && worldmt_settings.getBool(name))
747 load_mod_names.insert(name.substr(9));
749 // complain about mods declared to be loaded, but not found
750 for(std::vector<ModSpec>::iterator it = m_mods.begin();
751 it != m_mods.end(); ++it)
752 load_mod_names.erase((*it).name);
753 for(std::vector<ModSpec>::iterator it = unsatisfied_mods.begin();
754 it != unsatisfied_mods.end(); ++it)
755 load_mod_names.erase((*it).name);
756 if(!load_mod_names.empty())
758 errorstream << "The following mods could not be found:";
759 for(std::set<std::string>::iterator it = load_mod_names.begin();
760 it != load_mod_names.end(); ++it)
761 errorstream << " \"" << (*it) << "\"";
762 errorstream << std::endl;
765 // Path to builtin.lua
766 std::string builtinpath = getBuiltinLuaPath() + DIR_DELIM + "builtin.lua";
769 JMutexAutoLock envlock(m_env_mutex);
770 JMutexAutoLock conlock(m_con_mutex);
772 // Initialize scripting
774 infostream<<"Server: Initializing Lua"<<std::endl;
776 m_script = new ScriptApi(this);
779 // Load and run builtin.lua
780 infostream<<"Server: Loading builtin.lua [\""
781 <<builtinpath<<"\"]"<<std::endl;
782 bool success = m_script->loadMod(builtinpath, "__builtin");
784 errorstream<<"Server: Failed to load and run "
785 <<builtinpath<<std::endl;
786 throw ModError("Failed to load and run "+builtinpath);
789 infostream<<"Server: Loading mods: ";
790 for(std::vector<ModSpec>::iterator i = m_mods.begin();
791 i != m_mods.end(); i++){
792 const ModSpec &mod = *i;
793 infostream<<mod.name<<" ";
795 infostream<<std::endl;
796 // Load and run "mod" scripts
797 for(std::vector<ModSpec>::iterator i = m_mods.begin();
798 i != m_mods.end(); i++){
799 const ModSpec &mod = *i;
800 std::string scriptpath = mod.path + DIR_DELIM + "init.lua";
801 infostream<<" ["<<padStringRight(mod.name, 12)<<"] [\""
802 <<scriptpath<<"\"]"<<std::endl;
803 bool success = m_script->loadMod(scriptpath, mod.name);
805 errorstream<<"Server: Failed to load and run "
806 <<scriptpath<<std::endl;
807 throw ModError("Failed to load and run "+scriptpath);
811 // Read Textures and calculate sha1 sums
814 // Apply item aliases in the node definition manager
815 m_nodedef->updateAliases(m_itemdef);
817 // Initialize Environment
818 ServerMap *servermap = new ServerMap(path_world, this, m_emerge);
819 m_env = new ServerEnvironment(servermap, m_script, this, this);
821 // Run some callbacks after the MG params have been set up but before activation
822 MapgenParams *mgparams = servermap->getMapgenParams();
823 m_script->environment_OnMapgenInit(mgparams);
825 // Initialize mapgens
826 m_emerge->initMapgens(mgparams);
828 // Give environment reference to scripting api
829 m_script->initializeEnvironment(m_env);
831 // Register us to receive map edit events
832 servermap->addEventReceiver(this);
834 // If file exists, load environment metadata
835 if(fs::PathExists(m_path_world+DIR_DELIM+"env_meta.txt"))
837 infostream<<"Server: Loading environment metadata"<<std::endl;
838 m_env->loadMeta(m_path_world);
842 infostream<<"Server: Loading players"<<std::endl;
843 m_env->deSerializePlayers(m_path_world);
846 Add some test ActiveBlockModifiers to environment
848 add_legacy_abms(m_env, m_nodedef);
850 m_liquid_transform_every = g_settings->getFloat("liquid_update");
855 infostream<<"Server destructing"<<std::endl;
858 Send shutdown message
861 JMutexAutoLock conlock(m_con_mutex);
863 std::wstring line = L"*** Server shutting down";
866 Send the message to clients
868 for(std::map<u16, RemoteClient*>::iterator
869 i = m_clients.begin();
870 i != m_clients.end(); ++i)
872 // Get client and check that it is valid
873 RemoteClient *client = i->second;
874 assert(client->peer_id == i->first);
875 if(client->serialization_version == SER_FMT_VER_INVALID)
879 SendChatMessage(client->peer_id, line);
881 catch(con::PeerNotFoundException &e)
887 JMutexAutoLock envlock(m_env_mutex);
888 JMutexAutoLock conlock(m_con_mutex);
891 Execute script shutdown hooks
893 m_script->on_shutdown();
897 JMutexAutoLock envlock(m_env_mutex);
902 infostream<<"Server: Saving players"<<std::endl;
903 m_env->serializePlayers(m_path_world);
906 Save environment metadata
908 infostream<<"Server: Saving environment metadata"<<std::endl;
909 m_env->saveMeta(m_path_world);
917 //shutdown all emerge threads first!
924 JMutexAutoLock clientslock(m_con_mutex);
926 for(std::map<u16, RemoteClient*>::iterator
927 i = m_clients.begin();
928 i != m_clients.end(); ++i)
936 // Delete things in the reverse order of creation
944 // Deinitialize scripting
945 infostream<<"Server: Deinitializing scripting"<<std::endl;
948 // Delete detached inventories
950 for(std::map<std::string, Inventory*>::iterator
951 i = m_detached_inventories.begin();
952 i != m_detached_inventories.end(); i++){
958 void Server::start(unsigned short port)
960 DSTACK(__FUNCTION_NAME);
961 infostream<<"Starting server on port "<<port<<"..."<<std::endl;
963 // Stop thread if already running
966 // Initialize connection
967 m_con.SetTimeoutMs(30);
971 m_thread.setRun(true);
974 // ASCII art for the win!
976 <<" .__ __ __ "<<std::endl
977 <<" _____ |__| ____ _____/ |_ ____ _______/ |_ "<<std::endl
978 <<" / \\| |/ \\_/ __ \\ __\\/ __ \\ / ___/\\ __\\"<<std::endl
979 <<"| Y Y \\ | | \\ ___/| | \\ ___/ \\___ \\ | | "<<std::endl
980 <<"|__|_| /__|___| /\\___ >__| \\___ >____ > |__| "<<std::endl
981 <<" \\/ \\/ \\/ \\/ \\/ "<<std::endl;
982 actionstream<<"World at ["<<m_path_world<<"]"<<std::endl;
983 actionstream<<"Server for gameid=\""<<m_gamespec.id
984 <<"\" listening on port "<<port<<"."<<std::endl;
989 DSTACK(__FUNCTION_NAME);
991 infostream<<"Server: Stopping and waiting threads"<<std::endl;
993 // Stop threads (set run=false first so both start stopping)
994 m_thread.setRun(false);
995 //m_emergethread.setRun(false);
997 //m_emergethread.stop();
999 infostream<<"Server: Threads stopped"<<std::endl;
1002 void Server::step(float dtime)
1004 DSTACK(__FUNCTION_NAME);
1009 JMutexAutoLock lock(m_step_dtime_mutex);
1010 m_step_dtime += dtime;
1012 // Throw if fatal error occurred in thread
1013 std::string async_err = m_async_fatal_error.get();
1014 if(async_err != ""){
1015 throw ServerError(async_err);
1019 void Server::AsyncRunStep()
1021 DSTACK(__FUNCTION_NAME);
1023 g_profiler->add("Server::AsyncRunStep (num)", 1);
1027 JMutexAutoLock lock1(m_step_dtime_mutex);
1028 dtime = m_step_dtime;
1032 // Send blocks to clients
1039 g_profiler->add("Server::AsyncRunStep with dtime (num)", 1);
1041 //infostream<<"Server steps "<<dtime<<std::endl;
1042 //infostream<<"Server::AsyncRunStep(): dtime="<<dtime<<std::endl;
1045 JMutexAutoLock lock1(m_step_dtime_mutex);
1046 m_step_dtime -= dtime;
1053 m_uptime.set(m_uptime.get() + dtime);
1057 // Process connection's timeouts
1058 JMutexAutoLock lock2(m_con_mutex);
1059 ScopeProfiler sp(g_profiler, "Server: connection timeout processing");
1060 m_con.RunTimeouts(dtime);
1064 // This has to be called so that the client list gets synced
1065 // with the peer list of the connection
1066 handlePeerChanges();
1070 Update time of day and overall game time
1073 JMutexAutoLock envlock(m_env_mutex);
1075 m_env->setTimeOfDaySpeed(g_settings->getFloat("time_speed"));
1078 Send to clients at constant intervals
1081 m_time_of_day_send_timer -= dtime;
1082 if(m_time_of_day_send_timer < 0.0)
1084 m_time_of_day_send_timer = g_settings->getFloat("time_send_interval");
1086 //JMutexAutoLock envlock(m_env_mutex);
1087 JMutexAutoLock conlock(m_con_mutex);
1089 for(std::map<u16, RemoteClient*>::iterator
1090 i = m_clients.begin();
1091 i != m_clients.end(); ++i)
1093 RemoteClient *client = i->second;
1094 SharedBuffer<u8> data = makePacket_TOCLIENT_TIME_OF_DAY(
1095 m_env->getTimeOfDay(), g_settings->getFloat("time_speed"));
1097 m_con.Send(client->peer_id, 0, data, true);
1103 JMutexAutoLock lock(m_env_mutex);
1104 // Figure out and report maximum lag to environment
1105 float max_lag = m_env->getMaxLagEstimate();
1106 max_lag *= 0.9998; // Decrease slowly (about half per 5 minutes)
1107 if(dtime > max_lag){
1108 if(dtime > 0.1 && dtime > max_lag * 2.0)
1109 infostream<<"Server: Maximum lag peaked to "<<dtime
1113 m_env->reportMaxLagEstimate(max_lag);
1115 ScopeProfiler sp(g_profiler, "SEnv step");
1116 ScopeProfiler sp2(g_profiler, "SEnv step avg", SPT_AVG);
1120 const float map_timer_and_unload_dtime = 2.92;
1121 if(m_map_timer_and_unload_interval.step(dtime, map_timer_and_unload_dtime))
1123 JMutexAutoLock lock(m_env_mutex);
1124 // Run Map's timers and unload unused data
1125 ScopeProfiler sp(g_profiler, "Server: map timer and unload");
1126 m_env->getMap().timerUpdate(map_timer_and_unload_dtime,
1127 g_settings->getFloat("server_unload_unused_data_timeout"));
1138 JMutexAutoLock lock(m_env_mutex);
1139 JMutexAutoLock lock2(m_con_mutex);
1141 ScopeProfiler sp(g_profiler, "Server: handle players");
1143 for(std::map<u16, RemoteClient*>::iterator
1144 i = m_clients.begin();
1145 i != m_clients.end(); ++i)
1147 RemoteClient *client = i->second;
1148 PlayerSAO *playersao = getPlayerSAO(client->peer_id);
1149 if(playersao == NULL)
1153 Handle player HPs (die if hp=0)
1155 if(playersao->m_hp_not_sent && g_settings->getBool("enable_damage"))
1157 if(playersao->getHP() == 0)
1158 DiePlayer(client->peer_id);
1160 SendPlayerHP(client->peer_id);
1164 Send player breath if changed
1166 if(playersao->m_breath_not_sent){
1167 SendPlayerBreath(client->peer_id);
1171 Send player inventories if necessary
1173 if(playersao->m_moved){
1174 SendMovePlayer(client->peer_id);
1175 playersao->m_moved = false;
1177 if(playersao->m_inventory_not_sent){
1178 UpdateCrafting(client->peer_id);
1179 SendInventory(client->peer_id);
1184 /* Transform liquids */
1185 m_liquid_transform_timer += dtime;
1186 if(m_liquid_transform_timer >= m_liquid_transform_every)
1188 m_liquid_transform_timer -= m_liquid_transform_every;
1190 JMutexAutoLock lock(m_env_mutex);
1192 ScopeProfiler sp(g_profiler, "Server: liquid transform");
1194 std::map<v3s16, MapBlock*> modified_blocks;
1195 m_env->getMap().transformLiquids(modified_blocks);
1200 core::map<v3s16, MapBlock*> lighting_modified_blocks;
1201 ServerMap &map = ((ServerMap&)m_env->getMap());
1202 map.updateLighting(modified_blocks, lighting_modified_blocks);
1204 // Add blocks modified by lighting to modified_blocks
1205 for(core::map<v3s16, MapBlock*>::Iterator
1206 i = lighting_modified_blocks.getIterator();
1207 i.atEnd() == false; i++)
1209 MapBlock *block = i.getNode()->getValue();
1210 modified_blocks.insert(block->getPos(), block);
1214 Set the modified blocks unsent for all the clients
1217 JMutexAutoLock lock2(m_con_mutex);
1219 for(std::map<u16, RemoteClient*>::iterator
1220 i = m_clients.begin();
1221 i != m_clients.end(); ++i)
1223 RemoteClient *client = i->second;
1225 if(modified_blocks.size() > 0)
1227 // Remove block from sent history
1228 client->SetBlocksNotSent(modified_blocks);
1233 // Periodically print some info
1235 float &counter = m_print_info_timer;
1241 JMutexAutoLock lock2(m_con_mutex);
1242 m_clients_number = 0;
1243 if(m_clients.size() != 0)
1244 infostream<<"Players:"<<std::endl;
1245 for(std::map<u16, RemoteClient*>::iterator
1246 i = m_clients.begin();
1247 i != m_clients.end(); ++i)
1249 //u16 peer_id = i.getNode()->getKey();
1250 RemoteClient *client = i->second;
1251 Player *player = m_env->getPlayer(client->peer_id);
1254 infostream<<"* "<<player->getName()<<"\t";
1255 client->PrintInfo(infostream);
1263 // send masterserver announce
1265 float &counter = m_masterserver_timer;
1266 if(!isSingleplayer() && (!counter || counter >= 300.0) && g_settings->getBool("server_announce") == true)
1268 ServerList::sendAnnounce(!counter ? "start" : "update", m_clients_number, m_uptime.get(), m_gamespec.id, m_mods);
1275 //if(g_settings->getBool("enable_experimental"))
1279 Check added and deleted active objects
1282 //infostream<<"Server: Checking added and deleted active objects"<<std::endl;
1283 JMutexAutoLock envlock(m_env_mutex);
1284 JMutexAutoLock conlock(m_con_mutex);
1286 ScopeProfiler sp(g_profiler, "Server: checking added and deleted objs");
1288 // Radius inside which objects are active
1289 s16 radius = g_settings->getS16("active_object_send_range_blocks");
1290 radius *= MAP_BLOCKSIZE;
1292 for(std::map<u16, RemoteClient*>::iterator
1293 i = m_clients.begin();
1294 i != m_clients.end(); ++i)
1296 RemoteClient *client = i->second;
1298 // If definitions and textures have not been sent, don't
1299 // send objects either
1300 if(!client->definitions_sent)
1303 Player *player = m_env->getPlayer(client->peer_id);
1306 // This can happen if the client timeouts somehow
1307 /*infostream<<"WARNING: "<<__FUNCTION_NAME<<": Client "
1309 <<" has no associated player"<<std::endl;*/
1312 v3s16 pos = floatToInt(player->getPosition(), BS);
1314 std::set<u16> removed_objects;
1315 std::set<u16> added_objects;
1316 m_env->getRemovedActiveObjects(pos, radius,
1317 client->m_known_objects, removed_objects);
1318 m_env->getAddedActiveObjects(pos, radius,
1319 client->m_known_objects, added_objects);
1321 // Ignore if nothing happened
1322 if(removed_objects.size() == 0 && added_objects.size() == 0)
1324 //infostream<<"active objects: none changed"<<std::endl;
1328 std::string data_buffer;
1332 // Handle removed objects
1333 writeU16((u8*)buf, removed_objects.size());
1334 data_buffer.append(buf, 2);
1335 for(std::set<u16>::iterator
1336 i = removed_objects.begin();
1337 i != removed_objects.end(); ++i)
1341 ServerActiveObject* obj = m_env->getActiveObject(id);
1343 // Add to data buffer for sending
1344 writeU16((u8*)buf, id);
1345 data_buffer.append(buf, 2);
1347 // Remove from known objects
1348 client->m_known_objects.erase(id);
1350 if(obj && obj->m_known_by_count > 0)
1351 obj->m_known_by_count--;
1354 // Handle added objects
1355 writeU16((u8*)buf, added_objects.size());
1356 data_buffer.append(buf, 2);
1357 for(std::set<u16>::iterator
1358 i = added_objects.begin();
1359 i != added_objects.end(); ++i)
1363 ServerActiveObject* obj = m_env->getActiveObject(id);
1366 u8 type = ACTIVEOBJECT_TYPE_INVALID;
1368 infostream<<"WARNING: "<<__FUNCTION_NAME
1369 <<": NULL object"<<std::endl;
1371 type = obj->getSendType();
1373 // Add to data buffer for sending
1374 writeU16((u8*)buf, id);
1375 data_buffer.append(buf, 2);
1376 writeU8((u8*)buf, type);
1377 data_buffer.append(buf, 1);
1380 data_buffer.append(serializeLongString(
1381 obj->getClientInitializationData(client->net_proto_version)));
1383 data_buffer.append(serializeLongString(""));
1385 // Add to known objects
1386 client->m_known_objects.insert(id);
1389 obj->m_known_by_count++;
1393 SharedBuffer<u8> reply(2 + data_buffer.size());
1394 writeU16(&reply[0], TOCLIENT_ACTIVE_OBJECT_REMOVE_ADD);
1395 memcpy((char*)&reply[2], data_buffer.c_str(),
1396 data_buffer.size());
1398 m_con.Send(client->peer_id, 0, reply, true);
1400 verbosestream<<"Server: Sent object remove/add: "
1401 <<removed_objects.size()<<" removed, "
1402 <<added_objects.size()<<" added, "
1403 <<"packet size is "<<reply.getSize()<<std::endl;
1408 Collect a list of all the objects known by the clients
1409 and report it back to the environment.
1412 core::map<u16, bool> all_known_objects;
1414 for(core::map<u16, RemoteClient*>::Iterator
1415 i = m_clients.getIterator();
1416 i.atEnd() == false; i++)
1418 RemoteClient *client = i.getNode()->getValue();
1419 // Go through all known objects of client
1420 for(core::map<u16, bool>::Iterator
1421 i = client->m_known_objects.getIterator();
1422 i.atEnd()==false; i++)
1424 u16 id = i.getNode()->getKey();
1425 all_known_objects[id] = true;
1429 m_env->setKnownActiveObjects(whatever);
1435 Send object messages
1438 JMutexAutoLock envlock(m_env_mutex);
1439 JMutexAutoLock conlock(m_con_mutex);
1441 ScopeProfiler sp(g_profiler, "Server: sending object messages");
1444 // Value = data sent by object
1445 std::map<u16, std::list<ActiveObjectMessage>* > buffered_messages;
1447 // Get active object messages from environment
1450 ActiveObjectMessage aom = m_env->getActiveObjectMessage();
1454 std::list<ActiveObjectMessage>* message_list = NULL;
1455 std::map<u16, std::list<ActiveObjectMessage>* >::iterator n;
1456 n = buffered_messages.find(aom.id);
1457 if(n == buffered_messages.end())
1459 message_list = new std::list<ActiveObjectMessage>;
1460 buffered_messages[aom.id] = message_list;
1464 message_list = n->second;
1466 message_list->push_back(aom);
1469 // Route data to every client
1470 for(std::map<u16, RemoteClient*>::iterator
1471 i = m_clients.begin();
1472 i != m_clients.end(); ++i)
1474 RemoteClient *client = i->second;
1475 std::string reliable_data;
1476 std::string unreliable_data;
1477 // Go through all objects in message buffer
1478 for(std::map<u16, std::list<ActiveObjectMessage>* >::iterator
1479 j = buffered_messages.begin();
1480 j != buffered_messages.end(); ++j)
1482 // If object is not known by client, skip it
1484 if(client->m_known_objects.find(id) == client->m_known_objects.end())
1486 // Get message list of object
1487 std::list<ActiveObjectMessage>* list = j->second;
1488 // Go through every message
1489 for(std::list<ActiveObjectMessage>::iterator
1490 k = list->begin(); k != list->end(); ++k)
1492 // Compose the full new data with header
1493 ActiveObjectMessage aom = *k;
1494 std::string new_data;
1497 writeU16((u8*)&buf[0], aom.id);
1498 new_data.append(buf, 2);
1500 new_data += serializeString(aom.datastring);
1501 // Add data to buffer
1503 reliable_data += new_data;
1505 unreliable_data += new_data;
1509 reliable_data and unreliable_data are now ready.
1512 if(reliable_data.size() > 0)
1514 SharedBuffer<u8> reply(2 + reliable_data.size());
1515 writeU16(&reply[0], TOCLIENT_ACTIVE_OBJECT_MESSAGES);
1516 memcpy((char*)&reply[2], reliable_data.c_str(),
1517 reliable_data.size());
1519 m_con.Send(client->peer_id, 0, reply, true);
1521 if(unreliable_data.size() > 0)
1523 SharedBuffer<u8> reply(2 + unreliable_data.size());
1524 writeU16(&reply[0], TOCLIENT_ACTIVE_OBJECT_MESSAGES);
1525 memcpy((char*)&reply[2], unreliable_data.c_str(),
1526 unreliable_data.size());
1527 // Send as unreliable
1528 m_con.Send(client->peer_id, 0, reply, false);
1531 /*if(reliable_data.size() > 0 || unreliable_data.size() > 0)
1533 infostream<<"Server: Size of object message data: "
1534 <<"reliable: "<<reliable_data.size()
1535 <<", unreliable: "<<unreliable_data.size()
1540 // Clear buffered_messages
1541 for(std::map<u16, std::list<ActiveObjectMessage>* >::iterator
1542 i = buffered_messages.begin();
1543 i != buffered_messages.end(); ++i)
1549 } // enable_experimental
1552 Send queued-for-sending map edit events.
1555 // We will be accessing the environment and the connection
1556 JMutexAutoLock lock(m_env_mutex);
1557 JMutexAutoLock conlock(m_con_mutex);
1559 // Don't send too many at a time
1562 // Single change sending is disabled if queue size is not small
1563 bool disable_single_change_sending = false;
1564 if(m_unsent_map_edit_queue.size() >= 4)
1565 disable_single_change_sending = true;
1567 int event_count = m_unsent_map_edit_queue.size();
1569 // We'll log the amount of each
1572 while(m_unsent_map_edit_queue.size() != 0)
1574 MapEditEvent* event = m_unsent_map_edit_queue.pop_front();
1576 // Players far away from the change are stored here.
1577 // Instead of sending the changes, MapBlocks are set not sent
1579 std::list<u16> far_players;
1581 if(event->type == MEET_ADDNODE)
1583 //infostream<<"Server: MEET_ADDNODE"<<std::endl;
1584 prof.add("MEET_ADDNODE", 1);
1585 if(disable_single_change_sending)
1586 sendAddNode(event->p, event->n, event->already_known_by_peer,
1589 sendAddNode(event->p, event->n, event->already_known_by_peer,
1592 else if(event->type == MEET_REMOVENODE)
1594 //infostream<<"Server: MEET_REMOVENODE"<<std::endl;
1595 prof.add("MEET_REMOVENODE", 1);
1596 if(disable_single_change_sending)
1597 sendRemoveNode(event->p, event->already_known_by_peer,
1600 sendRemoveNode(event->p, event->already_known_by_peer,
1603 else if(event->type == MEET_BLOCK_NODE_METADATA_CHANGED)
1605 infostream<<"Server: MEET_BLOCK_NODE_METADATA_CHANGED"<<std::endl;
1606 prof.add("MEET_BLOCK_NODE_METADATA_CHANGED", 1);
1607 setBlockNotSent(event->p);
1609 else if(event->type == MEET_OTHER)
1611 infostream<<"Server: MEET_OTHER"<<std::endl;
1612 prof.add("MEET_OTHER", 1);
1613 for(std::set<v3s16>::iterator
1614 i = event->modified_blocks.begin();
1615 i != event->modified_blocks.end(); ++i)
1617 setBlockNotSent(*i);
1622 prof.add("unknown", 1);
1623 infostream<<"WARNING: Server: Unknown MapEditEvent "
1624 <<((u32)event->type)<<std::endl;
1628 Set blocks not sent to far players
1630 if(far_players.size() > 0)
1632 // Convert list format to that wanted by SetBlocksNotSent
1633 std::map<v3s16, MapBlock*> modified_blocks2;
1634 for(std::set<v3s16>::iterator
1635 i = event->modified_blocks.begin();
1636 i != event->modified_blocks.end(); ++i)
1638 modified_blocks2[*i] =
1639 m_env->getMap().getBlockNoCreateNoEx(*i);
1641 // Set blocks not sent
1642 for(std::list<u16>::iterator
1643 i = far_players.begin();
1644 i != far_players.end(); ++i)
1647 RemoteClient *client = getClient(peer_id);
1650 client->SetBlocksNotSent(modified_blocks2);
1656 /*// Don't send too many at a time
1658 if(count >= 1 && m_unsent_map_edit_queue.size() < 100)
1662 if(event_count >= 5){
1663 infostream<<"Server: MapEditEvents:"<<std::endl;
1664 prof.print(infostream);
1665 } else if(event_count != 0){
1666 verbosestream<<"Server: MapEditEvents:"<<std::endl;
1667 prof.print(verbosestream);
1673 Trigger emergethread (it somehow gets to a non-triggered but
1674 bysy state sometimes)
1677 float &counter = m_emergethread_trigger_timer;
1683 for (unsigned int i = 0; i != m_emerge->emergethread.size(); i++)
1684 m_emerge->emergethread[i]->trigger();
1686 // Update m_enable_rollback_recording here too
1687 m_enable_rollback_recording =
1688 g_settings->getBool("enable_rollback_recording");
1692 // Save map, players and auth stuff
1694 float &counter = m_savemap_timer;
1696 if(counter >= g_settings->getFloat("server_map_save_interval"))
1699 JMutexAutoLock lock(m_env_mutex);
1701 ScopeProfiler sp(g_profiler, "Server: saving stuff");
1704 if(m_banmanager.isModified())
1705 m_banmanager.save();
1707 // Save changed parts of map
1708 m_env->getMap().save(MOD_STATE_WRITE_NEEDED);
1711 m_env->serializePlayers(m_path_world);
1713 // Save environment metadata
1714 m_env->saveMeta(m_path_world);
1719 void Server::Receive()
1721 DSTACK(__FUNCTION_NAME);
1722 SharedBuffer<u8> data;
1727 JMutexAutoLock conlock(m_con_mutex);
1728 datasize = m_con.Receive(peer_id, data);
1731 // This has to be called so that the client list gets synced
1732 // with the peer list of the connection
1733 handlePeerChanges();
1735 ProcessData(*data, datasize, peer_id);
1737 catch(con::InvalidIncomingDataException &e)
1739 infostream<<"Server::Receive(): "
1740 "InvalidIncomingDataException: what()="
1741 <<e.what()<<std::endl;
1743 catch(con::PeerNotFoundException &e)
1745 //NOTE: This is not needed anymore
1747 // The peer has been disconnected.
1748 // Find the associated player and remove it.
1750 /*JMutexAutoLock envlock(m_env_mutex);
1752 infostream<<"ServerThread: peer_id="<<peer_id
1753 <<" has apparently closed connection. "
1754 <<"Removing player."<<std::endl;
1756 m_env->removePlayer(peer_id);*/
1760 void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
1762 DSTACK(__FUNCTION_NAME);
1763 // Environment is locked first.
1764 JMutexAutoLock envlock(m_env_mutex);
1765 JMutexAutoLock conlock(m_con_mutex);
1767 ScopeProfiler sp(g_profiler, "Server::ProcessData");
1771 Address address = m_con.GetPeerAddress(peer_id);
1772 addr_s = address.serializeString();
1774 // drop player if is ip is banned
1775 if(m_banmanager.isIpBanned(addr_s)){
1776 infostream<<"Server: A banned client tried to connect from "
1777 <<addr_s<<"; banned name was "
1778 <<m_banmanager.getBanName(addr_s)<<std::endl;
1779 // This actually doesn't seem to transfer to the client
1780 DenyAccess(peer_id, L"Your ip is banned. Banned name was "
1781 +narrow_to_wide(m_banmanager.getBanName(addr_s)));
1782 m_con.DeletePeer(peer_id);
1786 catch(con::PeerNotFoundException &e)
1788 infostream<<"Server::ProcessData(): Cancelling: peer "
1789 <<peer_id<<" not found"<<std::endl;
1793 u8 peer_ser_ver = getClient(peer_id)->serialization_version;
1801 ToServerCommand command = (ToServerCommand)readU16(&data[0]);
1803 if(command == TOSERVER_INIT)
1805 // [0] u16 TOSERVER_INIT
1806 // [2] u8 SER_FMT_VER_HIGHEST_READ
1807 // [3] u8[20] player_name
1808 // [23] u8[28] password <--- can be sent without this, from old versions
1810 if(datasize < 2+1+PLAYERNAME_SIZE)
1813 verbosestream<<"Server: Got TOSERVER_INIT from "
1814 <<peer_id<<std::endl;
1816 // Do not allow multiple players in simple singleplayer mode.
1817 // This isn't a perfect way to do it, but will suffice for now.
1818 if(m_simple_singleplayer_mode && m_clients.size() > 1){
1819 infostream<<"Server: Not allowing another client to connect in"
1820 <<" simple singleplayer mode"<<std::endl;
1821 DenyAccess(peer_id, L"Running in simple singleplayer mode.");
1825 // First byte after command is maximum supported
1826 // serialization version
1827 u8 client_max = data[2];
1828 u8 our_max = SER_FMT_VER_HIGHEST_READ;
1829 // Use the highest version supported by both
1830 u8 deployed = std::min(client_max, our_max);
1831 // If it's lower than the lowest supported, give up.
1832 if(deployed < SER_FMT_VER_LOWEST)
1833 deployed = SER_FMT_VER_INVALID;
1835 //peer->serialization_version = deployed;
1836 getClient(peer_id)->pending_serialization_version = deployed;
1838 if(deployed == SER_FMT_VER_INVALID)
1840 actionstream<<"Server: A mismatched client tried to connect from "
1841 <<addr_s<<std::endl;
1842 infostream<<"Server: Cannot negotiate "
1843 "serialization version with peer "
1844 <<peer_id<<std::endl;
1845 DenyAccess(peer_id, std::wstring(
1846 L"Your client's version is not supported.\n"
1847 L"Server version is ")
1848 + narrow_to_wide(VERSION_STRING) + L"."
1854 Read and check network protocol version
1857 u16 min_net_proto_version = 0;
1858 if(datasize >= 2+1+PLAYERNAME_SIZE+PASSWORD_SIZE+2)
1859 min_net_proto_version = readU16(&data[2+1+PLAYERNAME_SIZE+PASSWORD_SIZE]);
1861 // Use same version as minimum and maximum if maximum version field
1862 // doesn't exist (backwards compatibility)
1863 u16 max_net_proto_version = min_net_proto_version;
1864 if(datasize >= 2+1+PLAYERNAME_SIZE+PASSWORD_SIZE+2+2)
1865 max_net_proto_version = readU16(&data[2+1+PLAYERNAME_SIZE+PASSWORD_SIZE+2]);
1867 // Start with client's maximum version
1868 u16 net_proto_version = max_net_proto_version;
1870 // Figure out a working version if it is possible at all
1871 if(max_net_proto_version >= SERVER_PROTOCOL_VERSION_MIN ||
1872 min_net_proto_version <= SERVER_PROTOCOL_VERSION_MAX)
1874 // If maximum is larger than our maximum, go with our maximum
1875 if(max_net_proto_version > SERVER_PROTOCOL_VERSION_MAX)
1876 net_proto_version = SERVER_PROTOCOL_VERSION_MAX;
1877 // Else go with client's maximum
1879 net_proto_version = max_net_proto_version;
1882 verbosestream<<"Server: "<<peer_id<<" Protocol version: min: "
1883 <<min_net_proto_version<<", max: "<<max_net_proto_version
1884 <<", chosen: "<<net_proto_version<<std::endl;
1886 getClient(peer_id)->net_proto_version = net_proto_version;
1888 if(net_proto_version < SERVER_PROTOCOL_VERSION_MIN ||
1889 net_proto_version > SERVER_PROTOCOL_VERSION_MAX)
1891 actionstream<<"Server: A mismatched client tried to connect from "<<addr_s
1893 DenyAccess(peer_id, std::wstring(
1894 L"Your client's version is not supported.\n"
1895 L"Server version is ")
1896 + narrow_to_wide(VERSION_STRING) + L",\n"
1897 + L"server's PROTOCOL_VERSION is "
1898 + narrow_to_wide(itos(SERVER_PROTOCOL_VERSION_MIN))
1900 + narrow_to_wide(itos(SERVER_PROTOCOL_VERSION_MAX))
1901 + L", client's PROTOCOL_VERSION is "
1902 + narrow_to_wide(itos(min_net_proto_version))
1904 + narrow_to_wide(itos(max_net_proto_version))
1909 if(g_settings->getBool("strict_protocol_version_checking"))
1911 if(net_proto_version != LATEST_PROTOCOL_VERSION)
1913 actionstream<<"Server: A mismatched (strict) client tried to "
1914 <<"connect from "<<addr_s<<std::endl;
1915 DenyAccess(peer_id, std::wstring(
1916 L"Your client's version is not supported.\n"
1917 L"Server version is ")
1918 + narrow_to_wide(VERSION_STRING) + L",\n"
1919 + L"server's PROTOCOL_VERSION (strict) is "
1920 + narrow_to_wide(itos(LATEST_PROTOCOL_VERSION))
1921 + L", client's PROTOCOL_VERSION is "
1922 + narrow_to_wide(itos(min_net_proto_version))
1924 + narrow_to_wide(itos(max_net_proto_version))
1935 char playername[PLAYERNAME_SIZE];
1936 for(u32 i=0; i<PLAYERNAME_SIZE-1; i++)
1938 playername[i] = data[3+i];
1940 playername[PLAYERNAME_SIZE-1] = 0;
1942 if(playername[0]=='\0')
1944 actionstream<<"Server: Player with an empty name "
1945 <<"tried to connect from "<<addr_s<<std::endl;
1946 DenyAccess(peer_id, L"Empty name");
1950 if(string_allowed(playername, PLAYERNAME_ALLOWED_CHARS)==false)
1952 actionstream<<"Server: Player with an invalid name "
1953 <<"tried to connect from "<<addr_s<<std::endl;
1954 DenyAccess(peer_id, L"Name contains unallowed characters");
1958 if(!isSingleplayer() && strcasecmp(playername, "singleplayer") == 0)
1960 actionstream<<"Server: Player with an invalid name "
1961 <<"tried to connect from "<<addr_s<<std::endl;
1962 DenyAccess(peer_id, L"Name is not allowed");
1966 infostream<<"Server: New connection: \""<<playername<<"\" from "
1967 <<m_con.GetPeerAddress(peer_id).serializeString()<<std::endl;
1970 char given_password[PASSWORD_SIZE];
1971 if(datasize < 2+1+PLAYERNAME_SIZE+PASSWORD_SIZE)
1973 // old version - assume blank password
1974 given_password[0] = 0;
1978 for(u32 i=0; i<PASSWORD_SIZE-1; i++)
1980 given_password[i] = data[23+i];
1982 given_password[PASSWORD_SIZE-1] = 0;
1985 if(!base64_is_valid(given_password)){
1986 actionstream<<"Server: "<<playername
1987 <<" supplied invalid password hash"<<std::endl;
1988 DenyAccess(peer_id, L"Invalid password hash");
1992 // Enforce user limit.
1993 // Don't enforce for users that have some admin right
1994 if(m_clients.size() >= g_settings->getU16("max_users") &&
1995 !checkPriv(playername, "server") &&
1996 !checkPriv(playername, "ban") &&
1997 !checkPriv(playername, "privs") &&
1998 !checkPriv(playername, "password") &&
1999 playername != g_settings->get("name"))
2001 actionstream<<"Server: "<<playername<<" tried to join, but there"
2002 <<" are already max_users="
2003 <<g_settings->getU16("max_users")<<" players."<<std::endl;
2004 DenyAccess(peer_id, L"Too many users.");
2008 std::string checkpwd; // Password hash to check against
2009 bool has_auth = m_script->getAuth(playername, &checkpwd, NULL);
2011 // If no authentication info exists for user, create it
2013 if(!isSingleplayer() &&
2014 g_settings->getBool("disallow_empty_password") &&
2015 std::string(given_password) == ""){
2016 actionstream<<"Server: "<<playername
2017 <<" supplied empty password"<<std::endl;
2018 DenyAccess(peer_id, L"Empty passwords are "
2019 L"disallowed. Set a password and try again.");
2022 std::wstring raw_default_password =
2023 narrow_to_wide(g_settings->get("default_password"));
2024 std::string initial_password =
2025 translatePassword(playername, raw_default_password);
2027 // If default_password is empty, allow any initial password
2028 if (raw_default_password.length() == 0)
2029 initial_password = given_password;
2031 m_script->createAuth(playername, initial_password);
2034 has_auth = m_script->getAuth(playername, &checkpwd, NULL);
2037 actionstream<<"Server: "<<playername<<" cannot be authenticated"
2038 <<" (auth handler does not work?)"<<std::endl;
2039 DenyAccess(peer_id, L"Not allowed to login");
2043 if(given_password != checkpwd){
2044 actionstream<<"Server: "<<playername<<" supplied invalid password"
2045 <<" (peer_id="<<peer_id<<")"<<std::endl;
2046 DenyAccess(peer_id, L"Invalid password");
2051 PlayerSAO *playersao = emergePlayer(playername, peer_id);
2053 // If failed, cancel
2054 if(playersao == NULL)
2056 errorstream<<"Server: peer_id="<<peer_id
2057 <<": failed to emerge player"<<std::endl;
2058 DenyAccess(peer_id, L"Could not allocate player. You"
2059 " may need to wait for a timeout.");
2064 Answer with a TOCLIENT_INIT
2067 SharedBuffer<u8> reply(2+1+6+8+4);
2068 writeU16(&reply[0], TOCLIENT_INIT);
2069 writeU8(&reply[2], deployed);
2070 writeV3S16(&reply[2+1], floatToInt(playersao->getPlayer()->getPosition()+v3f(0,BS/2,0), BS));
2071 writeU64(&reply[2+1+6], m_env->getServerMap().getSeed());
2072 writeF1000(&reply[2+1+6+8], g_settings->getFloat("dedicated_server_step"));
2075 m_con.Send(peer_id, 0, reply, true);
2079 Send complete position information
2081 SendMovePlayer(peer_id);
2086 if(command == TOSERVER_INIT2)
2088 verbosestream<<"Server: Got TOSERVER_INIT2 from "
2089 <<peer_id<<std::endl;
2091 Player *player = m_env->getPlayer(peer_id);
2093 verbosestream<<"Server: TOSERVER_INIT2: "
2094 <<"Player not found; ignoring."<<std::endl;
2098 RemoteClient *client = getClient(peer_id);
2099 client->serialization_version =
2100 getClient(peer_id)->pending_serialization_version;
2103 Send some initialization data
2106 infostream<<"Server: Sending content to "
2107 <<getPlayerName(peer_id)<<std::endl;
2109 // Send player movement settings
2110 SendMovement(m_con, peer_id);
2112 // Send item definitions
2113 SendItemDef(m_con, peer_id, m_itemdef, client->net_proto_version);
2115 // Send node definitions
2116 SendNodeDef(m_con, peer_id, m_nodedef, client->net_proto_version);
2118 // Send media announcement
2119 sendMediaAnnouncement(peer_id);
2122 SendPlayerPrivileges(peer_id);
2124 // Send inventory formspec
2125 SendPlayerInventoryFormspec(peer_id);
2128 UpdateCrafting(peer_id);
2129 SendInventory(peer_id);
2132 if(g_settings->getBool("enable_damage"))
2133 SendPlayerHP(peer_id);
2136 SendPlayerBreath(peer_id);
2138 // Send detached inventories
2139 sendDetachedInventories(peer_id);
2141 // Show death screen if necessary
2143 SendDeathscreen(m_con, peer_id, false, v3f(0,0,0));
2147 SharedBuffer<u8> data = makePacket_TOCLIENT_TIME_OF_DAY(
2148 m_env->getTimeOfDay(), g_settings->getFloat("time_speed"));
2149 m_con.Send(peer_id, 0, data, true);
2152 // Note things in chat if not in simple singleplayer mode
2153 if(!m_simple_singleplayer_mode)
2155 // Send information about server to player in chat
2156 SendChatMessage(peer_id, getStatusString());
2158 // Send information about joining in chat
2160 std::wstring name = L"unknown";
2161 Player *player = m_env->getPlayer(peer_id);
2163 name = narrow_to_wide(player->getName());
2165 std::wstring message;
2168 message += L" joined the game.";
2169 BroadcastChatMessage(message);
2173 // Warnings about protocol version can be issued here
2174 if(getClient(peer_id)->net_proto_version < LATEST_PROTOCOL_VERSION)
2176 SendChatMessage(peer_id, L"# Server: WARNING: YOUR CLIENT'S "
2177 L"VERSION MAY NOT BE FULLY COMPATIBLE WITH THIS SERVER!");
2184 std::ostringstream os(std::ios_base::binary);
2185 for(std::map<u16, RemoteClient*>::iterator
2186 i = m_clients.begin();
2187 i != m_clients.end(); ++i)
2189 RemoteClient *client = i->second;
2190 assert(client->peer_id == i->first);
2191 if(client->serialization_version == SER_FMT_VER_INVALID)
2194 Player *player = m_env->getPlayer(client->peer_id);
2197 // Get name of player
2198 os<<player->getName()<<" ";
2201 actionstream<<player->getName()<<" ["<<addr_s<<"] "<<"joins game. List of players: "
2202 <<os.str()<<std::endl;
2208 if(peer_ser_ver == SER_FMT_VER_INVALID)
2210 infostream<<"Server::ProcessData(): Cancelling: Peer"
2211 " serialization format invalid or not initialized."
2212 " Skipping incoming command="<<command<<std::endl;
2216 Player *player = m_env->getPlayer(peer_id);
2218 infostream<<"Server::ProcessData(): Cancelling: "
2219 "No player for peer_id="<<peer_id
2224 PlayerSAO *playersao = player->getPlayerSAO();
2225 if(playersao == NULL){
2226 infostream<<"Server::ProcessData(): Cancelling: "
2227 "No player object for peer_id="<<peer_id
2232 if(command == TOSERVER_PLAYERPOS)
2234 if(datasize < 2+12+12+4+4)
2238 v3s32 ps = readV3S32(&data[start+2]);
2239 v3s32 ss = readV3S32(&data[start+2+12]);
2240 f32 pitch = (f32)readS32(&data[2+12+12]) / 100.0;
2241 f32 yaw = (f32)readS32(&data[2+12+12+4]) / 100.0;
2243 if(datasize >= 2+12+12+4+4+4)
2244 keyPressed = (u32)readU32(&data[2+12+12+4+4]);
2245 v3f position((f32)ps.X/100., (f32)ps.Y/100., (f32)ps.Z/100.);
2246 v3f speed((f32)ss.X/100., (f32)ss.Y/100., (f32)ss.Z/100.);
2247 pitch = wrapDegrees(pitch);
2248 yaw = wrapDegrees(yaw);
2250 player->setPosition(position);
2251 player->setSpeed(speed);
2252 player->setPitch(pitch);
2253 player->setYaw(yaw);
2254 player->keyPressed=keyPressed;
2255 player->control.up = (bool)(keyPressed&1);
2256 player->control.down = (bool)(keyPressed&2);
2257 player->control.left = (bool)(keyPressed&4);
2258 player->control.right = (bool)(keyPressed&8);
2259 player->control.jump = (bool)(keyPressed&16);
2260 player->control.aux1 = (bool)(keyPressed&32);
2261 player->control.sneak = (bool)(keyPressed&64);
2262 player->control.LMB = (bool)(keyPressed&128);
2263 player->control.RMB = (bool)(keyPressed&256);
2265 bool cheated = playersao->checkMovementCheat();
2268 m_script->on_cheat(playersao, "moved_too_fast");
2271 /*infostream<<"Server::ProcessData(): Moved player "<<peer_id<<" to "
2272 <<"("<<position.X<<","<<position.Y<<","<<position.Z<<")"
2273 <<" pitch="<<pitch<<" yaw="<<yaw<<std::endl;*/
2275 else if(command == TOSERVER_GOTBLOCKS)
2288 u16 count = data[2];
2289 for(u16 i=0; i<count; i++)
2291 if((s16)datasize < 2+1+(i+1)*6)
2292 throw con::InvalidIncomingDataException
2293 ("GOTBLOCKS length is too short");
2294 v3s16 p = readV3S16(&data[2+1+i*6]);
2295 /*infostream<<"Server: GOTBLOCKS ("
2296 <<p.X<<","<<p.Y<<","<<p.Z<<")"<<std::endl;*/
2297 RemoteClient *client = getClient(peer_id);
2298 client->GotBlock(p);
2301 else if(command == TOSERVER_DELETEDBLOCKS)
2314 u16 count = data[2];
2315 for(u16 i=0; i<count; i++)
2317 if((s16)datasize < 2+1+(i+1)*6)
2318 throw con::InvalidIncomingDataException
2319 ("DELETEDBLOCKS length is too short");
2320 v3s16 p = readV3S16(&data[2+1+i*6]);
2321 /*infostream<<"Server: DELETEDBLOCKS ("
2322 <<p.X<<","<<p.Y<<","<<p.Z<<")"<<std::endl;*/
2323 RemoteClient *client = getClient(peer_id);
2324 client->SetBlockNotSent(p);
2327 else if(command == TOSERVER_CLICK_OBJECT)
2329 infostream<<"Server: CLICK_OBJECT not supported anymore"<<std::endl;
2332 else if(command == TOSERVER_CLICK_ACTIVEOBJECT)
2334 infostream<<"Server: CLICK_ACTIVEOBJECT not supported anymore"<<std::endl;
2337 else if(command == TOSERVER_GROUND_ACTION)
2339 infostream<<"Server: GROUND_ACTION not supported anymore"<<std::endl;
2343 else if(command == TOSERVER_RELEASE)
2345 infostream<<"Server: RELEASE not supported anymore"<<std::endl;
2348 else if(command == TOSERVER_SIGNTEXT)
2350 infostream<<"Server: SIGNTEXT not supported anymore"
2354 else if(command == TOSERVER_SIGNNODETEXT)
2356 infostream<<"Server: SIGNNODETEXT not supported anymore"
2360 else if(command == TOSERVER_INVENTORY_ACTION)
2362 // Strip command and create a stream
2363 std::string datastring((char*)&data[2], datasize-2);
2364 verbosestream<<"TOSERVER_INVENTORY_ACTION: data="<<datastring<<std::endl;
2365 std::istringstream is(datastring, std::ios_base::binary);
2367 InventoryAction *a = InventoryAction::deSerialize(is);
2370 infostream<<"TOSERVER_INVENTORY_ACTION: "
2371 <<"InventoryAction::deSerialize() returned NULL"
2376 // If something goes wrong, this player is to blame
2377 RollbackScopeActor rollback_scope(m_rollback,
2378 std::string("player:")+player->getName());
2381 Note: Always set inventory not sent, to repair cases
2382 where the client made a bad prediction.
2386 Handle restrictions and special cases of the move action
2388 if(a->getType() == IACTION_MOVE)
2390 IMoveAction *ma = (IMoveAction*)a;
2392 ma->from_inv.applyCurrentPlayer(player->getName());
2393 ma->to_inv.applyCurrentPlayer(player->getName());
2395 setInventoryModified(ma->from_inv);
2396 setInventoryModified(ma->to_inv);
2398 bool from_inv_is_current_player =
2399 (ma->from_inv.type == InventoryLocation::PLAYER) &&
2400 (ma->from_inv.name == player->getName());
2402 bool to_inv_is_current_player =
2403 (ma->to_inv.type == InventoryLocation::PLAYER) &&
2404 (ma->to_inv.name == player->getName());
2407 Disable moving items out of craftpreview
2409 if(ma->from_list == "craftpreview")
2411 infostream<<"Ignoring IMoveAction from "
2412 <<(ma->from_inv.dump())<<":"<<ma->from_list
2413 <<" to "<<(ma->to_inv.dump())<<":"<<ma->to_list
2414 <<" because src is "<<ma->from_list<<std::endl;
2420 Disable moving items into craftresult and craftpreview
2422 if(ma->to_list == "craftpreview" || ma->to_list == "craftresult")
2424 infostream<<"Ignoring IMoveAction from "
2425 <<(ma->from_inv.dump())<<":"<<ma->from_list
2426 <<" to "<<(ma->to_inv.dump())<<":"<<ma->to_list
2427 <<" because dst is "<<ma->to_list<<std::endl;
2432 // Disallow moving items in elsewhere than player's inventory
2433 // if not allowed to interact
2434 if(!checkPriv(player->getName(), "interact") &&
2435 (!from_inv_is_current_player ||
2436 !to_inv_is_current_player))
2438 infostream<<"Cannot move outside of player's inventory: "
2439 <<"No interact privilege"<<std::endl;
2445 Handle restrictions and special cases of the drop action
2447 else if(a->getType() == IACTION_DROP)
2449 IDropAction *da = (IDropAction*)a;
2451 da->from_inv.applyCurrentPlayer(player->getName());
2453 setInventoryModified(da->from_inv);
2456 Disable dropping items out of craftpreview
2458 if(da->from_list == "craftpreview")
2460 infostream<<"Ignoring IDropAction from "
2461 <<(da->from_inv.dump())<<":"<<da->from_list
2462 <<" because src is "<<da->from_list<<std::endl;
2467 // Disallow dropping items if not allowed to interact
2468 if(!checkPriv(player->getName(), "interact"))
2475 Handle restrictions and special cases of the craft action
2477 else if(a->getType() == IACTION_CRAFT)
2479 ICraftAction *ca = (ICraftAction*)a;
2481 ca->craft_inv.applyCurrentPlayer(player->getName());
2483 setInventoryModified(ca->craft_inv);
2485 //bool craft_inv_is_current_player =
2486 // (ca->craft_inv.type == InventoryLocation::PLAYER) &&
2487 // (ca->craft_inv.name == player->getName());
2489 // Disallow crafting if not allowed to interact
2490 if(!checkPriv(player->getName(), "interact"))
2492 infostream<<"Cannot craft: "
2493 <<"No interact privilege"<<std::endl;
2500 a->apply(this, playersao, this);
2504 else if(command == TOSERVER_CHAT_MESSAGE)
2512 std::string datastring((char*)&data[2], datasize-2);
2513 std::istringstream is(datastring, std::ios_base::binary);
2516 is.read((char*)buf, 2);
2517 u16 len = readU16(buf);
2519 std::wstring message;
2520 for(u16 i=0; i<len; i++)
2522 is.read((char*)buf, 2);
2523 message += (wchar_t)readU16(buf);
2526 // If something goes wrong, this player is to blame
2527 RollbackScopeActor rollback_scope(m_rollback,
2528 std::string("player:")+player->getName());
2530 // Get player name of this client
2531 std::wstring name = narrow_to_wide(player->getName());
2534 bool ate = m_script->on_chat_message(player->getName(),
2535 wide_to_narrow(message));
2536 // If script ate the message, don't proceed
2540 // Line to send to players
2542 // Whether to send to the player that sent the line
2543 bool send_to_sender = false;
2544 // Whether to send to other players
2545 bool send_to_others = false;
2547 // Commands are implemented in Lua, so only catch invalid
2548 // commands that were not "eaten" and send an error back
2549 if(message[0] == L'/')
2551 message = message.substr(1);
2552 send_to_sender = true;
2553 if(message.length() == 0)
2554 line += L"-!- Empty command";
2556 line += L"-!- Invalid command: " + str_split(message, L' ')[0];
2560 if(checkPriv(player->getName(), "shout")){
2565 send_to_others = true;
2567 line += L"-!- You don't have permission to shout.";
2568 send_to_sender = true;
2575 actionstream<<"CHAT: "<<wide_to_narrow(line)<<std::endl;
2578 Send the message to clients
2580 for(std::map<u16, RemoteClient*>::iterator
2581 i = m_clients.begin();
2582 i != m_clients.end(); ++i)
2584 // Get client and check that it is valid
2585 RemoteClient *client = i->second;
2586 assert(client->peer_id == i->first);
2587 if(client->serialization_version == SER_FMT_VER_INVALID)
2591 bool sender_selected = (peer_id == client->peer_id);
2592 if(sender_selected == true && send_to_sender == false)
2594 if(sender_selected == false && send_to_others == false)
2597 SendChatMessage(client->peer_id, line);
2601 else if(command == TOSERVER_DAMAGE)
2603 std::string datastring((char*)&data[2], datasize-2);
2604 std::istringstream is(datastring, std::ios_base::binary);
2605 u8 damage = readU8(is);
2607 if(g_settings->getBool("enable_damage"))
2609 actionstream<<player->getName()<<" damaged by "
2610 <<(int)damage<<" hp at "<<PP(player->getPosition()/BS)
2613 playersao->setHP(playersao->getHP() - damage);
2615 if(playersao->getHP() == 0 && playersao->m_hp_not_sent)
2618 if(playersao->m_hp_not_sent)
2619 SendPlayerHP(peer_id);
2622 else if(command == TOSERVER_BREATH)
2624 std::string datastring((char*)&data[2], datasize-2);
2625 std::istringstream is(datastring, std::ios_base::binary);
2626 u16 breath = readU16(is);
2627 playersao->setBreath(breath);
2629 else if(command == TOSERVER_PASSWORD)
2632 [0] u16 TOSERVER_PASSWORD
2633 [2] u8[28] old password
2634 [30] u8[28] new password
2637 if(datasize != 2+PASSWORD_SIZE*2)
2639 /*char password[PASSWORD_SIZE];
2640 for(u32 i=0; i<PASSWORD_SIZE-1; i++)
2641 password[i] = data[2+i];
2642 password[PASSWORD_SIZE-1] = 0;*/
2644 for(u32 i=0; i<PASSWORD_SIZE-1; i++)
2652 for(u32 i=0; i<PASSWORD_SIZE-1; i++)
2654 char c = data[2+PASSWORD_SIZE+i];
2660 if(!base64_is_valid(newpwd)){
2661 infostream<<"Server: "<<player->getName()<<" supplied invalid password hash"<<std::endl;
2662 // Wrong old password supplied!!
2663 SendChatMessage(peer_id, L"Invalid new password hash supplied. Password NOT changed.");
2667 infostream<<"Server: Client requests a password change from "
2668 <<"'"<<oldpwd<<"' to '"<<newpwd<<"'"<<std::endl;
2670 std::string playername = player->getName();
2672 std::string checkpwd;
2673 m_script->getAuth(playername, &checkpwd, NULL);
2675 if(oldpwd != checkpwd)
2677 infostream<<"Server: invalid old password"<<std::endl;
2678 // Wrong old password supplied!!
2679 SendChatMessage(peer_id, L"Invalid old password supplied. Password NOT changed.");
2683 bool success = m_script->setPassword(playername, newpwd);
2685 actionstream<<player->getName()<<" changes password"<<std::endl;
2686 SendChatMessage(peer_id, L"Password change successful.");
2688 actionstream<<player->getName()<<" tries to change password but "
2689 <<"it fails"<<std::endl;
2690 SendChatMessage(peer_id, L"Password change failed or inavailable.");
2693 else if(command == TOSERVER_PLAYERITEM)
2698 u16 item = readU16(&data[2]);
2699 playersao->setWieldIndex(item);
2701 else if(command == TOSERVER_RESPAWN)
2703 if(player->hp != 0 || !g_settings->getBool("enable_damage"))
2706 RespawnPlayer(peer_id);
2708 actionstream<<player->getName()<<" respawns at "
2709 <<PP(player->getPosition()/BS)<<std::endl;
2711 // ActiveObject is added to environment in AsyncRunStep after
2712 // the previous addition has been succesfully removed
2714 else if(command == TOSERVER_REQUEST_MEDIA) {
2715 std::string datastring((char*)&data[2], datasize-2);
2716 std::istringstream is(datastring, std::ios_base::binary);
2718 std::list<MediaRequest> tosend;
2719 u16 numfiles = readU16(is);
2721 infostream<<"Sending "<<numfiles<<" files to "
2722 <<getPlayerName(peer_id)<<std::endl;
2723 verbosestream<<"TOSERVER_REQUEST_MEDIA: "<<std::endl;
2725 for(int i = 0; i < numfiles; i++) {
2726 std::string name = deSerializeString(is);
2727 tosend.push_back(MediaRequest(name));
2728 verbosestream<<"TOSERVER_REQUEST_MEDIA: requested file "
2732 sendRequestedMedia(peer_id, tosend);
2734 // Now the client should know about everything
2735 // (definitions and files)
2736 getClient(peer_id)->definitions_sent = true;
2738 else if(command == TOSERVER_RECEIVED_MEDIA) {
2739 getClient(peer_id)->definitions_sent = true;
2741 else if(command == TOSERVER_INTERACT)
2743 std::string datastring((char*)&data[2], datasize-2);
2744 std::istringstream is(datastring, std::ios_base::binary);
2750 [5] u32 length of the next item
2751 [9] serialized PointedThing
2753 0: start digging (from undersurface) or use
2754 1: stop digging (all parameters ignored)
2755 2: digging completed
2756 3: place block or item (to abovesurface)
2759 u8 action = readU8(is);
2760 u16 item_i = readU16(is);
2761 std::istringstream tmp_is(deSerializeLongString(is), std::ios::binary);
2762 PointedThing pointed;
2763 pointed.deSerialize(tmp_is);
2765 verbosestream<<"TOSERVER_INTERACT: action="<<(int)action<<", item="
2766 <<item_i<<", pointed="<<pointed.dump()<<std::endl;
2770 verbosestream<<"TOSERVER_INTERACT: "<<player->getName()
2771 <<" tried to interact, but is dead!"<<std::endl;
2775 v3f player_pos = playersao->getLastGoodPosition();
2777 // Update wielded item
2778 playersao->setWieldIndex(item_i);
2780 // Get pointed to node (undefined if not POINTEDTYPE_NODE)
2781 v3s16 p_under = pointed.node_undersurface;
2782 v3s16 p_above = pointed.node_abovesurface;
2784 // Get pointed to object (NULL if not POINTEDTYPE_OBJECT)
2785 ServerActiveObject *pointed_object = NULL;
2786 if(pointed.type == POINTEDTHING_OBJECT)
2788 pointed_object = m_env->getActiveObject(pointed.object_id);
2789 if(pointed_object == NULL)
2791 verbosestream<<"TOSERVER_INTERACT: "
2792 "pointed object is NULL"<<std::endl;
2798 v3f pointed_pos_under = player_pos;
2799 v3f pointed_pos_above = player_pos;
2800 if(pointed.type == POINTEDTHING_NODE)
2802 pointed_pos_under = intToFloat(p_under, BS);
2803 pointed_pos_above = intToFloat(p_above, BS);
2805 else if(pointed.type == POINTEDTHING_OBJECT)
2807 pointed_pos_under = pointed_object->getBasePosition();
2808 pointed_pos_above = pointed_pos_under;
2812 Check that target is reasonably close
2813 (only when digging or placing things)
2815 if(action == 0 || action == 2 || action == 3)
2817 float d = player_pos.getDistanceFrom(pointed_pos_under);
2818 float max_d = BS * 14; // Just some large enough value
2820 actionstream<<"Player "<<player->getName()
2821 <<" tried to access "<<pointed.dump()
2823 <<"d="<<d<<", max_d="<<max_d
2824 <<". ignoring."<<std::endl;
2825 // Re-send block to revert change on client-side
2826 RemoteClient *client = getClient(peer_id);
2827 v3s16 blockpos = getNodeBlockPos(floatToInt(pointed_pos_under, BS));
2828 client->SetBlockNotSent(blockpos);
2830 m_script->on_cheat(playersao, "interacted_too_far");
2837 Make sure the player is allowed to do it
2839 if(!checkPriv(player->getName(), "interact"))
2841 actionstream<<player->getName()<<" attempted to interact with "
2842 <<pointed.dump()<<" without 'interact' privilege"
2844 // Re-send block to revert change on client-side
2845 RemoteClient *client = getClient(peer_id);
2846 // Digging completed -> under
2848 v3s16 blockpos = getNodeBlockPos(floatToInt(pointed_pos_under, BS));
2849 client->SetBlockNotSent(blockpos);
2851 // Placement -> above
2853 v3s16 blockpos = getNodeBlockPos(floatToInt(pointed_pos_above, BS));
2854 client->SetBlockNotSent(blockpos);
2860 If something goes wrong, this player is to blame
2862 RollbackScopeActor rollback_scope(m_rollback,
2863 std::string("player:")+player->getName());
2866 0: start digging or punch object
2870 if(pointed.type == POINTEDTHING_NODE)
2873 NOTE: This can be used in the future to check if
2874 somebody is cheating, by checking the timing.
2876 MapNode n(CONTENT_IGNORE);
2879 n = m_env->getMap().getNode(p_under);
2881 catch(InvalidPositionException &e)
2883 infostream<<"Server: Not punching: Node not found."
2884 <<" Adding block to emerge queue."
2886 m_emerge->enqueueBlockEmerge(peer_id, getNodeBlockPos(p_above), false);
2888 if(n.getContent() != CONTENT_IGNORE)
2889 m_script->node_on_punch(p_under, n, playersao);
2891 playersao->noCheatDigStart(p_under);
2893 else if(pointed.type == POINTEDTHING_OBJECT)
2895 // Skip if object has been removed
2896 if(pointed_object->m_removed)
2899 actionstream<<player->getName()<<" punches object "
2900 <<pointed.object_id<<": "
2901 <<pointed_object->getDescription()<<std::endl;
2903 ItemStack punchitem = playersao->getWieldedItem();
2904 ToolCapabilities toolcap =
2905 punchitem.getToolCapabilities(m_itemdef);
2906 v3f dir = (pointed_object->getBasePosition() -
2907 (player->getPosition() + player->getEyeOffset())
2909 float time_from_last_punch =
2910 playersao->resetTimeFromLastPunch();
2911 pointed_object->punch(dir, &toolcap, playersao,
2912 time_from_last_punch);
2920 else if(action == 1)
2925 2: Digging completed
2927 else if(action == 2)
2929 // Only digging of nodes
2930 if(pointed.type == POINTEDTHING_NODE)
2932 MapNode n(CONTENT_IGNORE);
2935 n = m_env->getMap().getNode(p_under);
2937 catch(InvalidPositionException &e)
2939 infostream<<"Server: Not finishing digging: Node not found."
2940 <<" Adding block to emerge queue."
2942 m_emerge->enqueueBlockEmerge(peer_id, getNodeBlockPos(p_above), false);
2945 /* Cheat prevention */
2946 bool is_valid_dig = true;
2947 if(!isSingleplayer() && !g_settings->getBool("disable_anticheat"))
2949 v3s16 nocheat_p = playersao->getNoCheatDigPos();
2950 float nocheat_t = playersao->getNoCheatDigTime();
2951 playersao->noCheatDigEnd();
2952 // If player didn't start digging this, ignore dig
2953 if(nocheat_p != p_under){
2954 infostream<<"Server: NoCheat: "<<player->getName()
2955 <<" started digging "
2956 <<PP(nocheat_p)<<" and completed digging "
2957 <<PP(p_under)<<"; not digging."<<std::endl;
2958 is_valid_dig = false;
2960 m_script->on_cheat(playersao, "finished_unknown_dig");
2962 // Get player's wielded item
2963 ItemStack playeritem;
2964 InventoryList *mlist = playersao->getInventory()->getList("main");
2966 playeritem = mlist->getItem(playersao->getWieldIndex());
2967 ToolCapabilities playeritem_toolcap =
2968 playeritem.getToolCapabilities(m_itemdef);
2969 // Get diggability and expected digging time
2970 DigParams params = getDigParams(m_nodedef->get(n).groups,
2971 &playeritem_toolcap);
2972 // If can't dig, try hand
2973 if(!params.diggable){
2974 const ItemDefinition &hand = m_itemdef->get("");
2975 const ToolCapabilities *tp = hand.tool_capabilities;
2977 params = getDigParams(m_nodedef->get(n).groups, tp);
2979 // If can't dig, ignore dig
2980 if(!params.diggable){
2981 infostream<<"Server: NoCheat: "<<player->getName()
2982 <<" completed digging "<<PP(p_under)
2983 <<", which is not diggable with tool. not digging."
2985 is_valid_dig = false;
2987 m_script->on_cheat(playersao, "dug_unbreakable");
2989 // Check digging time
2990 // If already invalidated, we don't have to
2992 // Well not our problem then
2994 // Clean and long dig
2995 else if(params.time > 2.0 && nocheat_t * 1.2 > params.time){
2996 // All is good, but grab time from pool; don't care if
2997 // it's actually available
2998 playersao->getDigPool().grab(params.time);
3000 // Short or laggy dig
3001 // Try getting the time from pool
3002 else if(playersao->getDigPool().grab(params.time)){
3007 infostream<<"Server: NoCheat: "<<player->getName()
3008 <<" completed digging "<<PP(p_under)
3009 <<"too fast; not digging."<<std::endl;
3010 is_valid_dig = false;
3012 m_script->on_cheat(playersao, "dug_too_fast");
3016 /* Actually dig node */
3018 if(is_valid_dig && n.getContent() != CONTENT_IGNORE)
3019 m_script->node_on_dig(p_under, n, playersao);
3021 // Send unusual result (that is, node not being removed)
3022 if(m_env->getMap().getNodeNoEx(p_under).getContent() != CONTENT_AIR)
3024 // Re-send block to revert change on client-side
3025 RemoteClient *client = getClient(peer_id);
3026 v3s16 blockpos = getNodeBlockPos(floatToInt(pointed_pos_under, BS));
3027 client->SetBlockNotSent(blockpos);
3033 3: place block or right-click object
3035 else if(action == 3)
3037 ItemStack item = playersao->getWieldedItem();
3039 // Reset build time counter
3040 if(pointed.type == POINTEDTHING_NODE &&
3041 item.getDefinition(m_itemdef).type == ITEM_NODE)
3042 getClient(peer_id)->m_time_from_building = 0.0;
3044 if(pointed.type == POINTEDTHING_OBJECT)
3046 // Right click object
3048 // Skip if object has been removed
3049 if(pointed_object->m_removed)
3052 actionstream<<player->getName()<<" right-clicks object "
3053 <<pointed.object_id<<": "
3054 <<pointed_object->getDescription()<<std::endl;
3057 pointed_object->rightClick(playersao);
3059 else if(m_script->item_OnPlace(
3060 item, playersao, pointed))
3062 // Placement was handled in lua
3064 // Apply returned ItemStack
3065 playersao->setWieldedItem(item);
3068 // If item has node placement prediction, always send the
3069 // blocks to make sure the client knows what exactly happened
3070 if(item.getDefinition(m_itemdef).node_placement_prediction != ""){
3071 RemoteClient *client = getClient(peer_id);
3072 v3s16 blockpos = getNodeBlockPos(floatToInt(pointed_pos_above, BS));
3073 client->SetBlockNotSent(blockpos);
3074 v3s16 blockpos2 = getNodeBlockPos(floatToInt(pointed_pos_under, BS));
3075 if(blockpos2 != blockpos){
3076 client->SetBlockNotSent(blockpos2);
3084 else if(action == 4)
3086 ItemStack item = playersao->getWieldedItem();
3088 actionstream<<player->getName()<<" uses "<<item.name
3089 <<", pointing at "<<pointed.dump()<<std::endl;
3091 if(m_script->item_OnUse(
3092 item, playersao, pointed))
3094 // Apply returned ItemStack
3095 playersao->setWieldedItem(item);
3102 Catch invalid actions
3106 infostream<<"WARNING: Server: Invalid action "
3107 <<action<<std::endl;
3110 else if(command == TOSERVER_REMOVED_SOUNDS)
3112 std::string datastring((char*)&data[2], datasize-2);
3113 std::istringstream is(datastring, std::ios_base::binary);
3115 int num = readU16(is);
3116 for(int k=0; k<num; k++){
3117 s32 id = readS32(is);
3118 std::map<s32, ServerPlayingSound>::iterator i =
3119 m_playing_sounds.find(id);
3120 if(i == m_playing_sounds.end())
3122 ServerPlayingSound &psound = i->second;
3123 psound.clients.erase(peer_id);
3124 if(psound.clients.size() == 0)
3125 m_playing_sounds.erase(i++);
3128 else if(command == TOSERVER_NODEMETA_FIELDS)
3130 std::string datastring((char*)&data[2], datasize-2);
3131 std::istringstream is(datastring, std::ios_base::binary);
3133 v3s16 p = readV3S16(is);
3134 std::string formname = deSerializeString(is);
3135 int num = readU16(is);
3136 std::map<std::string, std::string> fields;
3137 for(int k=0; k<num; k++){
3138 std::string fieldname = deSerializeString(is);
3139 std::string fieldvalue = deSerializeLongString(is);
3140 fields[fieldname] = fieldvalue;
3143 // If something goes wrong, this player is to blame
3144 RollbackScopeActor rollback_scope(m_rollback,
3145 std::string("player:")+player->getName());
3147 // Check the target node for rollback data; leave others unnoticed
3148 RollbackNode rn_old(&m_env->getMap(), p, this);
3150 m_script->node_on_receive_fields(p, formname, fields,playersao);
3152 // Report rollback data
3153 RollbackNode rn_new(&m_env->getMap(), p, this);
3154 if(rollback() && rn_new != rn_old){
3155 RollbackAction action;
3156 action.setSetNode(p, rn_old, rn_new);
3157 rollback()->reportAction(action);
3160 else if(command == TOSERVER_INVENTORY_FIELDS)
3162 std::string datastring((char*)&data[2], datasize-2);
3163 std::istringstream is(datastring, std::ios_base::binary);
3165 std::string formname = deSerializeString(is);
3166 int num = readU16(is);
3167 std::map<std::string, std::string> fields;
3168 for(int k=0; k<num; k++){
3169 std::string fieldname = deSerializeString(is);
3170 std::string fieldvalue = deSerializeLongString(is);
3171 fields[fieldname] = fieldvalue;
3174 m_script->on_playerReceiveFields(playersao, formname, fields);
3178 infostream<<"Server::ProcessData(): Ignoring "
3179 "unknown command "<<command<<std::endl;
3183 catch(SendFailedException &e)
3185 errorstream<<"Server::ProcessData(): SendFailedException: "
3191 void Server::onMapEditEvent(MapEditEvent *event)
3193 //infostream<<"Server::onMapEditEvent()"<<std::endl;
3194 if(m_ignore_map_edit_events)
3196 if(m_ignore_map_edit_events_area.contains(event->getArea()))
3198 MapEditEvent *e = event->clone();
3199 m_unsent_map_edit_queue.push_back(e);
3202 Inventory* Server::getInventory(const InventoryLocation &loc)
3205 case InventoryLocation::UNDEFINED:
3208 case InventoryLocation::CURRENT_PLAYER:
3211 case InventoryLocation::PLAYER:
3213 Player *player = m_env->getPlayer(loc.name.c_str());
3216 PlayerSAO *playersao = player->getPlayerSAO();
3219 return playersao->getInventory();
3222 case InventoryLocation::NODEMETA:
3224 NodeMetadata *meta = m_env->getMap().getNodeMetadata(loc.p);
3227 return meta->getInventory();
3230 case InventoryLocation::DETACHED:
3232 if(m_detached_inventories.count(loc.name) == 0)
3234 return m_detached_inventories[loc.name];
3242 void Server::setInventoryModified(const InventoryLocation &loc)
3245 case InventoryLocation::UNDEFINED:
3248 case InventoryLocation::PLAYER:
3250 Player *player = m_env->getPlayer(loc.name.c_str());
3253 PlayerSAO *playersao = player->getPlayerSAO();
3256 playersao->m_inventory_not_sent = true;
3257 playersao->m_wielded_item_not_sent = true;
3260 case InventoryLocation::NODEMETA:
3262 v3s16 blockpos = getNodeBlockPos(loc.p);
3264 MapBlock *block = m_env->getMap().getBlockNoCreateNoEx(blockpos);
3266 block->raiseModified(MOD_STATE_WRITE_NEEDED);
3268 setBlockNotSent(blockpos);
3271 case InventoryLocation::DETACHED:
3273 sendDetachedInventoryToAll(loc.name);
3281 //std::list<PlayerInfo> Server::getPlayerInfo()
3283 // DSTACK(__FUNCTION_NAME);
3284 // JMutexAutoLock envlock(m_env_mutex);
3285 // JMutexAutoLock conlock(m_con_mutex);
3287 // std::list<PlayerInfo> list;
3289 // std::list<Player*> players = m_env->getPlayers();
3291 // std::list<Player*>::iterator i;
3292 // for(i = players.begin();
3293 // i != players.end(); ++i)
3297 // Player *player = *i;
3300 // // Copy info from connection to info struct
3301 // info.id = player->peer_id;
3302 // info.address = m_con.GetPeerAddress(player->peer_id);
3303 // info.avg_rtt = m_con.GetPeerAvgRTT(player->peer_id);
3305 // catch(con::PeerNotFoundException &e)
3307 // // Set dummy peer info
3309 // info.address = Address(0,0,0,0,0);
3310 // info.avg_rtt = 0.0;
3313 // snprintf(info.name, PLAYERNAME_SIZE, "%s", player->getName());
3314 // info.position = player->getPosition();
3316 // list.push_back(info);
3323 void Server::peerAdded(con::Peer *peer)
3325 DSTACK(__FUNCTION_NAME);
3326 verbosestream<<"Server::peerAdded(): peer->id="
3327 <<peer->id<<std::endl;
3330 c.type = PEER_ADDED;
3331 c.peer_id = peer->id;
3333 m_peer_change_queue.push_back(c);
3336 void Server::deletingPeer(con::Peer *peer, bool timeout)
3338 DSTACK(__FUNCTION_NAME);
3339 verbosestream<<"Server::deletingPeer(): peer->id="
3340 <<peer->id<<", timeout="<<timeout<<std::endl;
3343 c.type = PEER_REMOVED;
3344 c.peer_id = peer->id;
3345 c.timeout = timeout;
3346 m_peer_change_queue.push_back(c);
3353 void Server::SendMovement(con::Connection &con, u16 peer_id)
3355 DSTACK(__FUNCTION_NAME);
3356 std::ostringstream os(std::ios_base::binary);
3358 writeU16(os, TOCLIENT_MOVEMENT);
3359 writeF1000(os, g_settings->getFloat("movement_acceleration_default"));
3360 writeF1000(os, g_settings->getFloat("movement_acceleration_air"));
3361 writeF1000(os, g_settings->getFloat("movement_acceleration_fast"));
3362 writeF1000(os, g_settings->getFloat("movement_speed_walk"));
3363 writeF1000(os, g_settings->getFloat("movement_speed_crouch"));
3364 writeF1000(os, g_settings->getFloat("movement_speed_fast"));
3365 writeF1000(os, g_settings->getFloat("movement_speed_climb"));
3366 writeF1000(os, g_settings->getFloat("movement_speed_jump"));
3367 writeF1000(os, g_settings->getFloat("movement_liquid_fluidity"));
3368 writeF1000(os, g_settings->getFloat("movement_liquid_fluidity_smooth"));
3369 writeF1000(os, g_settings->getFloat("movement_liquid_sink"));
3370 writeF1000(os, g_settings->getFloat("movement_gravity"));
3373 std::string s = os.str();
3374 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3376 con.Send(peer_id, 0, data, true);
3379 void Server::SendHP(con::Connection &con, u16 peer_id, u8 hp)
3381 DSTACK(__FUNCTION_NAME);
3382 std::ostringstream os(std::ios_base::binary);
3384 writeU16(os, TOCLIENT_HP);
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::SendBreath(con::Connection &con, u16 peer_id, u16 breath)
3396 DSTACK(__FUNCTION_NAME);
3397 std::ostringstream os(std::ios_base::binary);
3399 writeU16(os, TOCLIENT_BREATH);
3400 writeU16(os, breath);
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::SendAccessDenied(con::Connection &con, u16 peer_id,
3410 const std::wstring &reason)
3412 DSTACK(__FUNCTION_NAME);
3413 std::ostringstream os(std::ios_base::binary);
3415 writeU16(os, TOCLIENT_ACCESS_DENIED);
3416 os<<serializeWideString(reason);
3419 std::string s = os.str();
3420 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3422 con.Send(peer_id, 0, data, true);
3425 void Server::SendDeathscreen(con::Connection &con, u16 peer_id,
3426 bool set_camera_point_target, v3f camera_point_target)
3428 DSTACK(__FUNCTION_NAME);
3429 std::ostringstream os(std::ios_base::binary);
3431 writeU16(os, TOCLIENT_DEATHSCREEN);
3432 writeU8(os, set_camera_point_target);
3433 writeV3F1000(os, camera_point_target);
3436 std::string s = os.str();
3437 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3439 con.Send(peer_id, 0, data, true);
3442 void Server::SendItemDef(con::Connection &con, u16 peer_id,
3443 IItemDefManager *itemdef, u16 protocol_version)
3445 DSTACK(__FUNCTION_NAME);
3446 std::ostringstream os(std::ios_base::binary);
3450 u32 length of the next item
3451 zlib-compressed serialized ItemDefManager
3453 writeU16(os, TOCLIENT_ITEMDEF);
3454 std::ostringstream tmp_os(std::ios::binary);
3455 itemdef->serialize(tmp_os, protocol_version);
3456 std::ostringstream tmp_os2(std::ios::binary);
3457 compressZlib(tmp_os.str(), tmp_os2);
3458 os<<serializeLongString(tmp_os2.str());
3461 std::string s = os.str();
3462 verbosestream<<"Server: Sending item definitions to id("<<peer_id
3463 <<"): size="<<s.size()<<std::endl;
3464 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3466 con.Send(peer_id, 0, data, true);
3469 void Server::SendNodeDef(con::Connection &con, u16 peer_id,
3470 INodeDefManager *nodedef, u16 protocol_version)
3472 DSTACK(__FUNCTION_NAME);
3473 std::ostringstream os(std::ios_base::binary);
3477 u32 length of the next item
3478 zlib-compressed serialized NodeDefManager
3480 writeU16(os, TOCLIENT_NODEDEF);
3481 std::ostringstream tmp_os(std::ios::binary);
3482 nodedef->serialize(tmp_os, protocol_version);
3483 std::ostringstream tmp_os2(std::ios::binary);
3484 compressZlib(tmp_os.str(), tmp_os2);
3485 os<<serializeLongString(tmp_os2.str());
3488 std::string s = os.str();
3489 verbosestream<<"Server: Sending node definitions to id("<<peer_id
3490 <<"): size="<<s.size()<<std::endl;
3491 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3493 con.Send(peer_id, 0, data, true);
3497 Non-static send methods
3500 void Server::SendInventory(u16 peer_id)
3502 DSTACK(__FUNCTION_NAME);
3504 PlayerSAO *playersao = getPlayerSAO(peer_id);
3507 playersao->m_inventory_not_sent = false;
3513 std::ostringstream os;
3514 playersao->getInventory()->serialize(os);
3516 std::string s = os.str();
3518 SharedBuffer<u8> data(s.size()+2);
3519 writeU16(&data[0], TOCLIENT_INVENTORY);
3520 memcpy(&data[2], s.c_str(), s.size());
3523 m_con.Send(peer_id, 0, data, true);
3526 void Server::SendChatMessage(u16 peer_id, const std::wstring &message)
3528 DSTACK(__FUNCTION_NAME);
3530 std::ostringstream os(std::ios_base::binary);
3534 writeU16(buf, TOCLIENT_CHAT_MESSAGE);
3535 os.write((char*)buf, 2);
3538 writeU16(buf, message.size());
3539 os.write((char*)buf, 2);
3542 for(u32 i=0; i<message.size(); i++)
3546 os.write((char*)buf, 2);
3550 std::string s = os.str();
3551 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3553 m_con.Send(peer_id, 0, data, true);
3556 void Server::SendShowFormspecMessage(u16 peer_id, const std::string formspec,
3557 const std::string formname)
3559 DSTACK(__FUNCTION_NAME);
3561 std::ostringstream os(std::ios_base::binary);
3565 writeU16(buf, TOCLIENT_SHOW_FORMSPEC);
3566 os.write((char*)buf, 2);
3567 os<<serializeLongString(formspec);
3568 os<<serializeString(formname);
3571 std::string s = os.str();
3572 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3574 m_con.Send(peer_id, 0, data, true);
3577 // Spawns a particle on peer with peer_id
3578 void Server::SendSpawnParticle(u16 peer_id, v3f pos, v3f velocity, v3f acceleration,
3579 float expirationtime, float size, bool collisiondetection,
3580 std::string texture)
3582 DSTACK(__FUNCTION_NAME);
3584 std::ostringstream os(std::ios_base::binary);
3585 writeU16(os, TOCLIENT_SPAWN_PARTICLE);
3586 writeV3F1000(os, pos);
3587 writeV3F1000(os, velocity);
3588 writeV3F1000(os, acceleration);
3589 writeF1000(os, expirationtime);
3590 writeF1000(os, size);
3591 writeU8(os, collisiondetection);
3592 os<<serializeLongString(texture);
3595 std::string s = os.str();
3596 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3598 m_con.Send(peer_id, 0, data, true);
3601 // Spawns a particle on all peers
3602 void Server::SendSpawnParticleAll(v3f pos, v3f velocity, v3f acceleration,
3603 float expirationtime, float size, bool collisiondetection,
3604 std::string texture)
3606 for(std::map<u16, RemoteClient*>::iterator
3607 i = m_clients.begin();
3608 i != m_clients.end(); i++)
3610 // Get client and check that it is valid
3611 RemoteClient *client = i->second;
3612 assert(client->peer_id == i->first);
3613 if(client->serialization_version == SER_FMT_VER_INVALID)
3616 SendSpawnParticle(client->peer_id, pos, velocity, acceleration,
3617 expirationtime, size, collisiondetection, texture);
3621 // Adds a ParticleSpawner on peer with peer_id
3622 void Server::SendAddParticleSpawner(u16 peer_id, u16 amount, float spawntime, v3f minpos, v3f maxpos,
3623 v3f minvel, v3f maxvel, v3f minacc, v3f maxacc, float minexptime, float maxexptime,
3624 float minsize, float maxsize, bool collisiondetection, std::string texture, u32 id)
3626 DSTACK(__FUNCTION_NAME);
3628 std::ostringstream os(std::ios_base::binary);
3629 writeU16(os, TOCLIENT_ADD_PARTICLESPAWNER);
3631 writeU16(os, amount);
3632 writeF1000(os, spawntime);
3633 writeV3F1000(os, minpos);
3634 writeV3F1000(os, maxpos);
3635 writeV3F1000(os, minvel);
3636 writeV3F1000(os, maxvel);
3637 writeV3F1000(os, minacc);
3638 writeV3F1000(os, maxacc);
3639 writeF1000(os, minexptime);
3640 writeF1000(os, maxexptime);
3641 writeF1000(os, minsize);
3642 writeF1000(os, maxsize);
3643 writeU8(os, collisiondetection);
3644 os<<serializeLongString(texture);
3648 std::string s = os.str();
3649 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3651 m_con.Send(peer_id, 0, data, true);
3654 // Adds a ParticleSpawner on all peers
3655 void Server::SendAddParticleSpawnerAll(u16 amount, float spawntime, v3f minpos, v3f maxpos,
3656 v3f minvel, v3f maxvel, v3f minacc, v3f maxacc, float minexptime, float maxexptime,
3657 float minsize, float maxsize, bool collisiondetection, std::string texture, u32 id)
3659 for(std::map<u16, RemoteClient*>::iterator
3660 i = m_clients.begin();
3661 i != m_clients.end(); i++)
3663 // Get client and check that it is valid
3664 RemoteClient *client = i->second;
3665 assert(client->peer_id == i->first);
3666 if(client->serialization_version == SER_FMT_VER_INVALID)
3669 SendAddParticleSpawner(client->peer_id, amount, spawntime,
3670 minpos, maxpos, minvel, maxvel, minacc, maxacc,
3671 minexptime, maxexptime, minsize, maxsize, collisiondetection, texture, id);
3675 void Server::SendDeleteParticleSpawner(u16 peer_id, u32 id)
3677 DSTACK(__FUNCTION_NAME);
3679 std::ostringstream os(std::ios_base::binary);
3680 writeU16(os, TOCLIENT_DELETE_PARTICLESPAWNER);
3685 std::string s = os.str();
3686 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3688 m_con.Send(peer_id, 0, data, true);
3691 void Server::SendDeleteParticleSpawnerAll(u32 id)
3693 for(std::map<u16, RemoteClient*>::iterator
3694 i = m_clients.begin();
3695 i != m_clients.end(); i++)
3697 // Get client and check that it is valid
3698 RemoteClient *client = i->second;
3699 assert(client->peer_id == i->first);
3700 if(client->serialization_version == SER_FMT_VER_INVALID)
3703 SendDeleteParticleSpawner(client->peer_id, id);
3707 void Server::SendHUDAdd(u16 peer_id, u32 id, HudElement *form)
3709 std::ostringstream os(std::ios_base::binary);
3712 writeU16(os, TOCLIENT_HUDADD);
3714 writeU8(os, (u8)form->type);
3715 writeV2F1000(os, form->pos);
3716 os << serializeString(form->name);
3717 writeV2F1000(os, form->scale);
3718 os << serializeString(form->text);
3719 writeU32(os, form->number);
3720 writeU32(os, form->item);
3721 writeU32(os, form->dir);
3722 writeV2F1000(os, form->align);
3723 writeV2F1000(os, form->offset);
3726 std::string s = os.str();
3727 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3729 m_con.Send(peer_id, 0, data, true);
3732 void Server::SendHUDRemove(u16 peer_id, u32 id)
3734 std::ostringstream os(std::ios_base::binary);
3737 writeU16(os, TOCLIENT_HUDRM);
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::SendHUDChange(u16 peer_id, u32 id, HudElementStat stat, void *value)
3749 std::ostringstream os(std::ios_base::binary);
3752 writeU16(os, TOCLIENT_HUDCHANGE);
3754 writeU8(os, (u8)stat);
3757 case HUD_STAT_SCALE:
3758 case HUD_STAT_ALIGN:
3759 case HUD_STAT_OFFSET:
3760 writeV2F1000(os, *(v2f *)value);
3764 os << serializeString(*(std::string *)value);
3766 case HUD_STAT_NUMBER:
3770 writeU32(os, *(u32 *)value);
3775 std::string s = os.str();
3776 SharedBuffer<u8> data((u8 *)s.c_str(), s.size());
3778 m_con.Send(peer_id, 0, data, true);
3781 void Server::SendHUDSetFlags(u16 peer_id, u32 flags, u32 mask)
3783 std::ostringstream os(std::ios_base::binary);
3786 writeU16(os, TOCLIENT_HUD_SET_FLAGS);
3787 writeU32(os, flags);
3791 std::string s = os.str();
3792 SharedBuffer<u8> data((u8 *)s.c_str(), s.size());
3794 m_con.Send(peer_id, 0, data, true);
3797 void Server::SendHUDSetParam(u16 peer_id, u16 param, const std::string &value)
3799 std::ostringstream os(std::ios_base::binary);
3802 writeU16(os, TOCLIENT_HUD_SET_PARAM);
3803 writeU16(os, param);
3804 os<<serializeString(value);
3807 std::string s = os.str();
3808 SharedBuffer<u8> data((u8 *)s.c_str(), s.size());
3810 m_con.Send(peer_id, 0, data, true);
3813 void Server::BroadcastChatMessage(const std::wstring &message)
3815 for(std::map<u16, RemoteClient*>::iterator
3816 i = m_clients.begin();
3817 i != m_clients.end(); ++i)
3819 // Get client and check that it is valid
3820 RemoteClient *client = i->second;
3821 assert(client->peer_id == i->first);
3822 if(client->serialization_version == SER_FMT_VER_INVALID)
3825 SendChatMessage(client->peer_id, message);
3829 void Server::SendPlayerHP(u16 peer_id)
3831 DSTACK(__FUNCTION_NAME);
3832 PlayerSAO *playersao = getPlayerSAO(peer_id);
3834 playersao->m_hp_not_sent = false;
3835 SendHP(m_con, peer_id, playersao->getHP());
3838 void Server::SendPlayerBreath(u16 peer_id)
3840 DSTACK(__FUNCTION_NAME);
3841 PlayerSAO *playersao = getPlayerSAO(peer_id);
3843 playersao->m_breath_not_sent = false;
3844 SendBreath(m_con, peer_id, playersao->getBreath());
3847 void Server::SendMovePlayer(u16 peer_id)
3849 DSTACK(__FUNCTION_NAME);
3850 Player *player = m_env->getPlayer(peer_id);
3853 std::ostringstream os(std::ios_base::binary);
3854 writeU16(os, TOCLIENT_MOVE_PLAYER);
3855 writeV3F1000(os, player->getPosition());
3856 writeF1000(os, player->getPitch());
3857 writeF1000(os, player->getYaw());
3860 v3f pos = player->getPosition();
3861 f32 pitch = player->getPitch();
3862 f32 yaw = player->getYaw();
3863 verbosestream<<"Server: Sending TOCLIENT_MOVE_PLAYER"
3864 <<" pos=("<<pos.X<<","<<pos.Y<<","<<pos.Z<<")"
3871 std::string s = os.str();
3872 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3874 m_con.Send(peer_id, 0, data, true);
3877 void Server::SendPlayerPrivileges(u16 peer_id)
3879 Player *player = m_env->getPlayer(peer_id);
3881 if(player->peer_id == PEER_ID_INEXISTENT)
3884 std::set<std::string> privs;
3885 m_script->getAuth(player->getName(), NULL, &privs);
3887 std::ostringstream os(std::ios_base::binary);
3888 writeU16(os, TOCLIENT_PRIVILEGES);
3889 writeU16(os, privs.size());
3890 for(std::set<std::string>::const_iterator i = privs.begin();
3891 i != privs.end(); i++){
3892 os<<serializeString(*i);
3896 std::string s = os.str();
3897 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3899 m_con.Send(peer_id, 0, data, true);
3902 void Server::SendPlayerInventoryFormspec(u16 peer_id)
3904 Player *player = m_env->getPlayer(peer_id);
3906 if(player->peer_id == PEER_ID_INEXISTENT)
3909 std::ostringstream os(std::ios_base::binary);
3910 writeU16(os, TOCLIENT_INVENTORY_FORMSPEC);
3911 os<<serializeLongString(player->inventory_formspec);
3914 std::string s = os.str();
3915 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3917 m_con.Send(peer_id, 0, data, true);
3920 s32 Server::playSound(const SimpleSoundSpec &spec,
3921 const ServerSoundParams ¶ms)
3923 // Find out initial position of sound
3924 bool pos_exists = false;
3925 v3f pos = params.getPos(m_env, &pos_exists);
3926 // If position is not found while it should be, cancel sound
3927 if(pos_exists != (params.type != ServerSoundParams::SSP_LOCAL))
3929 // Filter destination clients
3930 std::set<RemoteClient*> dst_clients;
3931 if(params.to_player != "")
3933 Player *player = m_env->getPlayer(params.to_player.c_str());
3935 infostream<<"Server::playSound: Player \""<<params.to_player
3936 <<"\" not found"<<std::endl;
3939 if(player->peer_id == PEER_ID_INEXISTENT){
3940 infostream<<"Server::playSound: Player \""<<params.to_player
3941 <<"\" not connected"<<std::endl;
3944 RemoteClient *client = getClient(player->peer_id);
3945 dst_clients.insert(client);
3949 for(std::map<u16, RemoteClient*>::iterator
3950 i = m_clients.begin(); i != m_clients.end(); ++i)
3952 RemoteClient *client = i->second;
3953 Player *player = m_env->getPlayer(client->peer_id);
3957 if(player->getPosition().getDistanceFrom(pos) >
3958 params.max_hear_distance)
3961 dst_clients.insert(client);
3964 if(dst_clients.size() == 0)
3967 s32 id = m_next_sound_id++;
3968 // The sound will exist as a reference in m_playing_sounds
3969 m_playing_sounds[id] = ServerPlayingSound();
3970 ServerPlayingSound &psound = m_playing_sounds[id];
3971 psound.params = params;
3972 for(std::set<RemoteClient*>::iterator i = dst_clients.begin();
3973 i != dst_clients.end(); i++)
3974 psound.clients.insert((*i)->peer_id);
3976 std::ostringstream os(std::ios_base::binary);
3977 writeU16(os, TOCLIENT_PLAY_SOUND);
3979 os<<serializeString(spec.name);
3980 writeF1000(os, spec.gain * params.gain);
3981 writeU8(os, params.type);
3982 writeV3F1000(os, pos);
3983 writeU16(os, params.object);
3984 writeU8(os, params.loop);
3986 std::string s = os.str();
3987 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3989 for(std::set<RemoteClient*>::iterator i = dst_clients.begin();
3990 i != dst_clients.end(); i++){
3992 m_con.Send((*i)->peer_id, 0, data, true);
3996 void Server::stopSound(s32 handle)
3998 // Get sound reference
3999 std::map<s32, ServerPlayingSound>::iterator i =
4000 m_playing_sounds.find(handle);
4001 if(i == m_playing_sounds.end())
4003 ServerPlayingSound &psound = i->second;
4005 std::ostringstream os(std::ios_base::binary);
4006 writeU16(os, TOCLIENT_STOP_SOUND);
4007 writeS32(os, handle);
4009 std::string s = os.str();
4010 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
4012 for(std::set<u16>::iterator i = psound.clients.begin();
4013 i != psound.clients.end(); i++){
4015 m_con.Send(*i, 0, data, true);
4017 // Remove sound reference
4018 m_playing_sounds.erase(i);
4021 void Server::sendRemoveNode(v3s16 p, u16 ignore_id,
4022 std::list<u16> *far_players, float far_d_nodes)
4024 float maxd = far_d_nodes*BS;
4025 v3f p_f = intToFloat(p, BS);
4029 SharedBuffer<u8> reply(replysize);
4030 writeU16(&reply[0], TOCLIENT_REMOVENODE);
4031 writeS16(&reply[2], p.X);
4032 writeS16(&reply[4], p.Y);
4033 writeS16(&reply[6], p.Z);
4035 for(std::map<u16, RemoteClient*>::iterator
4036 i = m_clients.begin();
4037 i != m_clients.end(); ++i)
4039 // Get client and check that it is valid
4040 RemoteClient *client = i->second;
4041 assert(client->peer_id == i->first);
4042 if(client->serialization_version == SER_FMT_VER_INVALID)
4045 // Don't send if it's the same one
4046 if(client->peer_id == ignore_id)
4052 Player *player = m_env->getPlayer(client->peer_id);
4055 // If player is far away, only set modified blocks not sent
4056 v3f player_pos = player->getPosition();
4057 if(player_pos.getDistanceFrom(p_f) > maxd)
4059 far_players->push_back(client->peer_id);
4066 m_con.Send(client->peer_id, 0, reply, true);
4070 void Server::sendAddNode(v3s16 p, MapNode n, u16 ignore_id,
4071 std::list<u16> *far_players, float far_d_nodes)
4073 float maxd = far_d_nodes*BS;
4074 v3f p_f = intToFloat(p, BS);
4076 for(std::map<u16, RemoteClient*>::iterator
4077 i = m_clients.begin();
4078 i != m_clients.end(); ++i)
4080 // Get client and check that it is valid
4081 RemoteClient *client = i->second;
4082 assert(client->peer_id == i->first);
4083 if(client->serialization_version == SER_FMT_VER_INVALID)
4086 // Don't send if it's the same one
4087 if(client->peer_id == ignore_id)
4093 Player *player = m_env->getPlayer(client->peer_id);
4096 // If player is far away, only set modified blocks not sent
4097 v3f player_pos = player->getPosition();
4098 if(player_pos.getDistanceFrom(p_f) > maxd)
4100 far_players->push_back(client->peer_id);
4107 u32 replysize = 8 + MapNode::serializedLength(client->serialization_version);
4108 SharedBuffer<u8> reply(replysize);
4109 writeU16(&reply[0], TOCLIENT_ADDNODE);
4110 writeS16(&reply[2], p.X);
4111 writeS16(&reply[4], p.Y);
4112 writeS16(&reply[6], p.Z);
4113 n.serialize(&reply[8], client->serialization_version);
4116 m_con.Send(client->peer_id, 0, reply, true);
4120 void Server::setBlockNotSent(v3s16 p)
4122 for(std::map<u16, RemoteClient*>::iterator
4123 i = m_clients.begin();
4124 i != m_clients.end(); ++i)
4126 RemoteClient *client = i->second;
4127 client->SetBlockNotSent(p);
4131 void Server::SendBlockNoLock(u16 peer_id, MapBlock *block, u8 ver, u16 net_proto_version)
4133 DSTACK(__FUNCTION_NAME);
4135 v3s16 p = block->getPos();
4139 bool completely_air = true;
4140 for(s16 z0=0; z0<MAP_BLOCKSIZE; z0++)
4141 for(s16 x0=0; x0<MAP_BLOCKSIZE; x0++)
4142 for(s16 y0=0; y0<MAP_BLOCKSIZE; y0++)
4144 if(block->getNodeNoEx(v3s16(x0,y0,z0)).d != CONTENT_AIR)
4146 completely_air = false;
4147 x0 = y0 = z0 = MAP_BLOCKSIZE; // Break out
4152 infostream<<"Server: Sending block ("<<p.X<<","<<p.Y<<","<<p.Z<<"): ";
4154 infostream<<"[completely air] ";
4155 infostream<<std::endl;
4159 Create a packet with the block in the right format
4162 std::ostringstream os(std::ios_base::binary);
4163 block->serialize(os, ver, false);
4164 block->serializeNetworkSpecific(os, net_proto_version);
4165 std::string s = os.str();
4166 SharedBuffer<u8> blockdata((u8*)s.c_str(), s.size());
4168 u32 replysize = 8 + blockdata.getSize();
4169 SharedBuffer<u8> reply(replysize);
4170 writeU16(&reply[0], TOCLIENT_BLOCKDATA);
4171 writeS16(&reply[2], p.X);
4172 writeS16(&reply[4], p.Y);
4173 writeS16(&reply[6], p.Z);
4174 memcpy(&reply[8], *blockdata, blockdata.getSize());
4176 /*infostream<<"Server: Sending block ("<<p.X<<","<<p.Y<<","<<p.Z<<")"
4177 <<": \tpacket size: "<<replysize<<std::endl;*/
4182 m_con.Send(peer_id, 1, reply, true);
4185 void Server::SendBlocks(float dtime)
4187 DSTACK(__FUNCTION_NAME);
4189 JMutexAutoLock envlock(m_env_mutex);
4190 JMutexAutoLock conlock(m_con_mutex);
4192 ScopeProfiler sp(g_profiler, "Server: sel and send blocks to clients");
4194 std::vector<PrioritySortedBlockTransfer> queue;
4196 s32 total_sending = 0;
4199 ScopeProfiler sp(g_profiler, "Server: selecting blocks for sending");
4201 for(std::map<u16, RemoteClient*>::iterator
4202 i = m_clients.begin();
4203 i != m_clients.end(); ++i)
4205 RemoteClient *client = i->second;
4206 assert(client->peer_id == i->first);
4208 // If definitions and textures have not been sent, don't
4209 // send MapBlocks either
4210 if(!client->definitions_sent)
4213 total_sending += client->SendingCount();
4215 if(client->serialization_version == SER_FMT_VER_INVALID)
4218 client->GetNextBlocks(this, dtime, queue);
4223 // Lowest priority number comes first.
4224 // Lowest is most important.
4225 std::sort(queue.begin(), queue.end());
4227 for(u32 i=0; i<queue.size(); i++)
4229 //TODO: Calculate limit dynamically
4230 if(total_sending >= g_settings->getS32
4231 ("max_simultaneous_block_sends_server_total"))
4234 PrioritySortedBlockTransfer q = queue[i];
4236 MapBlock *block = NULL;
4239 block = m_env->getMap().getBlockNoCreate(q.pos);
4241 catch(InvalidPositionException &e)
4246 RemoteClient *client = getClientNoEx(q.peer_id);
4252 SendBlockNoLock(q.peer_id, block, client->serialization_version, client->net_proto_version);
4254 client->SentBlock(q.pos);
4260 void Server::fillMediaCache()
4262 DSTACK(__FUNCTION_NAME);
4264 infostream<<"Server: Calculating media file checksums"<<std::endl;
4266 // Collect all media file paths
4267 std::list<std::string> paths;
4268 for(std::vector<ModSpec>::iterator i = m_mods.begin();
4269 i != m_mods.end(); i++){
4270 const ModSpec &mod = *i;
4271 paths.push_back(mod.path + DIR_DELIM + "textures");
4272 paths.push_back(mod.path + DIR_DELIM + "sounds");
4273 paths.push_back(mod.path + DIR_DELIM + "media");
4274 paths.push_back(mod.path + DIR_DELIM + "models");
4276 std::string path_all = "textures";
4277 paths.push_back(path_all + DIR_DELIM + "all");
4279 // Collect media file information from paths into cache
4280 for(std::list<std::string>::iterator i = paths.begin();
4281 i != paths.end(); i++)
4283 std::string mediapath = *i;
4284 std::vector<fs::DirListNode> dirlist = fs::GetDirListing(mediapath);
4285 for(u32 j=0; j<dirlist.size(); j++){
4286 if(dirlist[j].dir) // Ignode dirs
4288 std::string filename = dirlist[j].name;
4289 // If name contains illegal characters, ignore the file
4290 if(!string_allowed(filename, TEXTURENAME_ALLOWED_CHARS)){
4291 infostream<<"Server: ignoring illegal file name: \""
4292 <<filename<<"\""<<std::endl;
4295 // If name is not in a supported format, ignore it
4296 const char *supported_ext[] = {
4297 ".png", ".jpg", ".bmp", ".tga",
4298 ".pcx", ".ppm", ".psd", ".wal", ".rgb",
4300 ".x", ".b3d", ".md2", ".obj",
4303 if(removeStringEnd(filename, supported_ext) == ""){
4304 infostream<<"Server: ignoring unsupported file extension: \""
4305 <<filename<<"\""<<std::endl;
4308 // Ok, attempt to load the file and add to cache
4309 std::string filepath = mediapath + DIR_DELIM + filename;
4311 std::ifstream fis(filepath.c_str(), std::ios_base::binary);
4312 if(fis.good() == false){
4313 errorstream<<"Server::fillMediaCache(): Could not open \""
4314 <<filename<<"\" for reading"<<std::endl;
4317 std::ostringstream tmp_os(std::ios_base::binary);
4321 fis.read(buf, 1024);
4322 std::streamsize len = fis.gcount();
4323 tmp_os.write(buf, len);
4332 errorstream<<"Server::fillMediaCache(): Failed to read \""
4333 <<filename<<"\""<<std::endl;
4336 if(tmp_os.str().length() == 0){
4337 errorstream<<"Server::fillMediaCache(): Empty file \""
4338 <<filepath<<"\""<<std::endl;
4343 sha1.addBytes(tmp_os.str().c_str(), tmp_os.str().length());
4345 unsigned char *digest = sha1.getDigest();
4346 std::string sha1_base64 = base64_encode(digest, 20);
4347 std::string sha1_hex = hex_encode((char*)digest, 20);
4351 this->m_media[filename] = MediaInfo(filepath, sha1_base64);
4352 verbosestream<<"Server: "<<sha1_hex<<" is "<<filename<<std::endl;
4357 struct SendableMediaAnnouncement
4360 std::string sha1_digest;
4362 SendableMediaAnnouncement(const std::string name_="",
4363 const std::string sha1_digest_=""):
4365 sha1_digest(sha1_digest_)
4369 void Server::sendMediaAnnouncement(u16 peer_id)
4371 DSTACK(__FUNCTION_NAME);
4373 verbosestream<<"Server: Announcing files to id("<<peer_id<<")"
4376 std::list<SendableMediaAnnouncement> file_announcements;
4378 for(std::map<std::string, MediaInfo>::iterator i = m_media.begin();
4379 i != m_media.end(); i++){
4381 file_announcements.push_back(
4382 SendableMediaAnnouncement(i->first, i->second.sha1_digest));
4386 std::ostringstream os(std::ios_base::binary);
4394 u16 length of sha1_digest
4399 writeU16(os, TOCLIENT_ANNOUNCE_MEDIA);
4400 writeU16(os, file_announcements.size());
4402 for(std::list<SendableMediaAnnouncement>::iterator
4403 j = file_announcements.begin();
4404 j != file_announcements.end(); ++j){
4405 os<<serializeString(j->name);
4406 os<<serializeString(j->sha1_digest);
4408 os<<serializeString(g_settings->get("remote_media"));
4411 std::string s = os.str();
4412 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
4415 m_con.Send(peer_id, 0, data, true);
4418 struct SendableMedia
4424 SendableMedia(const std::string &name_="", const std::string path_="",
4425 const std::string &data_=""):
4432 void Server::sendRequestedMedia(u16 peer_id,
4433 const std::list<MediaRequest> &tosend)
4435 DSTACK(__FUNCTION_NAME);
4437 verbosestream<<"Server::sendRequestedMedia(): "
4438 <<"Sending files to client"<<std::endl;
4442 // Put 5kB in one bunch (this is not accurate)
4443 u32 bytes_per_bunch = 5000;
4445 std::vector< std::list<SendableMedia> > file_bunches;
4446 file_bunches.push_back(std::list<SendableMedia>());
4448 u32 file_size_bunch_total = 0;
4450 for(std::list<MediaRequest>::const_iterator i = tosend.begin();
4451 i != tosend.end(); ++i)
4453 if(m_media.find(i->name) == m_media.end()){
4454 errorstream<<"Server::sendRequestedMedia(): Client asked for "
4455 <<"unknown file \""<<(i->name)<<"\""<<std::endl;
4459 //TODO get path + name
4460 std::string tpath = m_media[(*i).name].path;
4463 std::ifstream fis(tpath.c_str(), std::ios_base::binary);
4464 if(fis.good() == false){
4465 errorstream<<"Server::sendRequestedMedia(): Could not open \""
4466 <<tpath<<"\" for reading"<<std::endl;
4469 std::ostringstream tmp_os(std::ios_base::binary);
4473 fis.read(buf, 1024);
4474 std::streamsize len = fis.gcount();
4475 tmp_os.write(buf, len);
4476 file_size_bunch_total += len;
4485 errorstream<<"Server::sendRequestedMedia(): Failed to read \""
4486 <<(*i).name<<"\""<<std::endl;
4489 /*infostream<<"Server::sendRequestedMedia(): Loaded \""
4490 <<tname<<"\""<<std::endl;*/
4492 file_bunches[file_bunches.size()-1].push_back(
4493 SendableMedia((*i).name, tpath, tmp_os.str()));
4495 // Start next bunch if got enough data
4496 if(file_size_bunch_total >= bytes_per_bunch){
4497 file_bunches.push_back(std::list<SendableMedia>());
4498 file_size_bunch_total = 0;
4503 /* Create and send packets */
4505 u32 num_bunches = file_bunches.size();
4506 for(u32 i=0; i<num_bunches; i++)
4508 std::ostringstream os(std::ios_base::binary);
4512 u16 total number of texture bunches
4513 u16 index of this bunch
4514 u32 number of files in this bunch
4523 writeU16(os, TOCLIENT_MEDIA);
4524 writeU16(os, num_bunches);
4526 writeU32(os, file_bunches[i].size());
4528 for(std::list<SendableMedia>::iterator
4529 j = file_bunches[i].begin();
4530 j != file_bunches[i].end(); ++j){
4531 os<<serializeString(j->name);
4532 os<<serializeLongString(j->data);
4536 std::string s = os.str();
4537 verbosestream<<"Server::sendRequestedMedia(): bunch "
4538 <<i<<"/"<<num_bunches
4539 <<" files="<<file_bunches[i].size()
4540 <<" size=" <<s.size()<<std::endl;
4541 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
4543 m_con.Send(peer_id, 0, data, true);
4547 void Server::sendDetachedInventory(const std::string &name, u16 peer_id)
4549 if(m_detached_inventories.count(name) == 0){
4550 errorstream<<__FUNCTION_NAME<<": \""<<name<<"\" not found"<<std::endl;
4553 Inventory *inv = m_detached_inventories[name];
4555 std::ostringstream os(std::ios_base::binary);
4556 writeU16(os, TOCLIENT_DETACHED_INVENTORY);
4557 os<<serializeString(name);
4561 std::string s = os.str();
4562 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
4564 m_con.Send(peer_id, 0, data, true);
4567 void Server::sendDetachedInventoryToAll(const std::string &name)
4569 DSTACK(__FUNCTION_NAME);
4571 for(std::map<u16, RemoteClient*>::iterator
4572 i = m_clients.begin();
4573 i != m_clients.end(); ++i){
4574 RemoteClient *client = i->second;
4575 sendDetachedInventory(name, client->peer_id);
4579 void Server::sendDetachedInventories(u16 peer_id)
4581 DSTACK(__FUNCTION_NAME);
4583 for(std::map<std::string, Inventory*>::iterator
4584 i = m_detached_inventories.begin();
4585 i != m_detached_inventories.end(); i++){
4586 const std::string &name = i->first;
4587 //Inventory *inv = i->second;
4588 sendDetachedInventory(name, peer_id);
4596 void Server::DiePlayer(u16 peer_id)
4598 DSTACK(__FUNCTION_NAME);
4600 PlayerSAO *playersao = getPlayerSAO(peer_id);
4603 infostream<<"Server::DiePlayer(): Player "
4604 <<playersao->getPlayer()->getName()
4605 <<" dies"<<std::endl;
4607 playersao->setHP(0);
4609 // Trigger scripted stuff
4610 m_script->on_dieplayer(playersao);
4612 SendPlayerHP(peer_id);
4613 SendDeathscreen(m_con, peer_id, false, v3f(0,0,0));
4616 void Server::RespawnPlayer(u16 peer_id)
4618 DSTACK(__FUNCTION_NAME);
4620 PlayerSAO *playersao = getPlayerSAO(peer_id);
4623 infostream<<"Server::RespawnPlayer(): Player "
4624 <<playersao->getPlayer()->getName()
4625 <<" respawns"<<std::endl;
4627 playersao->setHP(PLAYER_MAX_HP);
4629 bool repositioned = m_script->on_respawnplayer(playersao);
4631 v3f pos = findSpawnPos(m_env->getServerMap());
4632 playersao->setPos(pos);
4636 void Server::DenyAccess(u16 peer_id, const std::wstring &reason)
4638 DSTACK(__FUNCTION_NAME);
4640 SendAccessDenied(m_con, peer_id, reason);
4642 RemoteClient *client = getClientNoEx(peer_id);
4644 client->denied = true;
4646 // If there are way too many clients, get rid of denied new ones immediately
4647 if(m_clients.size() > 2 * g_settings->getU16("max_users")){
4648 // Delete peer to stop sending it data
4649 m_con.DeletePeer(peer_id);
4650 // Delete client also to stop block sends and other stuff
4651 DeleteClient(peer_id, CDR_DENY);
4655 void Server::DeleteClient(u16 peer_id, ClientDeletionReason reason)
4657 DSTACK(__FUNCTION_NAME);
4660 std::map<u16, RemoteClient*>::iterator n;
4661 n = m_clients.find(peer_id);
4662 // The client may not exist; clients are immediately removed if their
4663 // access is denied, and this event occurs later then.
4664 if(n == m_clients.end())
4668 Mark objects to be not known by the client
4670 RemoteClient *client = n->second;
4672 for(std::set<u16>::iterator
4673 i = client->m_known_objects.begin();
4674 i != client->m_known_objects.end(); ++i)
4678 ServerActiveObject* obj = m_env->getActiveObject(id);
4680 if(obj && obj->m_known_by_count > 0)
4681 obj->m_known_by_count--;
4685 Clear references to playing sounds
4687 for(std::map<s32, ServerPlayingSound>::iterator
4688 i = m_playing_sounds.begin();
4689 i != m_playing_sounds.end();)
4691 ServerPlayingSound &psound = i->second;
4692 psound.clients.erase(peer_id);
4693 if(psound.clients.size() == 0)
4694 m_playing_sounds.erase(i++);
4699 Player *player = m_env->getPlayer(peer_id);
4701 // Collect information about leaving in chat
4702 std::wstring message;
4704 if(player != NULL && reason != CDR_DENY)
4706 std::wstring name = narrow_to_wide(player->getName());
4709 message += L" left the game.";
4710 if(reason == CDR_TIMEOUT)
4711 message += L" (timed out)";
4715 /* Run scripts and remove from environment */
4719 PlayerSAO *playersao = player->getPlayerSAO();
4722 m_script->on_leaveplayer(playersao);
4724 playersao->disconnected();
4732 if(player != NULL && reason != CDR_DENY)
4734 std::ostringstream os(std::ios_base::binary);
4735 for(std::map<u16, RemoteClient*>::iterator
4736 i = m_clients.begin();
4737 i != m_clients.end(); ++i)
4739 RemoteClient *client = i->second;
4740 assert(client->peer_id == i->first);
4741 if(client->serialization_version == SER_FMT_VER_INVALID)
4744 Player *player = m_env->getPlayer(client->peer_id);
4747 // Get name of player
4748 os<<player->getName()<<" ";
4751 actionstream<<player->getName()<<" "
4752 <<(reason==CDR_TIMEOUT?"times out.":"leaves game.")
4753 <<" List of players: "<<os.str()<<std::endl;
4758 delete m_clients[peer_id];
4759 m_clients.erase(peer_id);
4761 // Send player info to all remaining clients
4762 //SendPlayerInfos();
4764 // Send leave chat message to all remaining clients
4765 if(message.length() != 0)
4766 BroadcastChatMessage(message);
4769 void Server::UpdateCrafting(u16 peer_id)
4771 DSTACK(__FUNCTION_NAME);
4773 Player* player = m_env->getPlayer(peer_id);
4776 // Get a preview for crafting
4778 getCraftingResult(&player->inventory, preview, false, this);
4780 // Put the new preview in
4781 InventoryList *plist = player->inventory.getList("craftpreview");
4783 assert(plist->getSize() >= 1);
4784 plist->changeItem(0, preview);
4787 RemoteClient* Server::getClient(u16 peer_id)
4789 RemoteClient *client = getClientNoEx(peer_id);
4791 throw ClientNotFoundException("Client not found");
4794 RemoteClient* Server::getClientNoEx(u16 peer_id)
4796 std::map<u16, RemoteClient*>::iterator n;
4797 n = m_clients.find(peer_id);
4798 // The client may not exist; clients are immediately removed if their
4799 // access is denied, and this event occurs later then.
4800 if(n == m_clients.end())
4805 std::wstring Server::getStatusString()
4807 std::wostringstream os(std::ios_base::binary);
4810 os<<L"version="<<narrow_to_wide(VERSION_STRING);
4812 os<<L", uptime="<<m_uptime.get();
4814 os<<L", max_lag="<<m_env->getMaxLagEstimate();
4815 // Information about clients
4816 std::map<u16, RemoteClient*>::iterator i;
4819 for(i = m_clients.begin(), first = true;
4820 i != m_clients.end(); ++i)
4822 // Get client and check that it is valid
4823 RemoteClient *client = i->second;
4824 assert(client->peer_id == i->first);
4825 if(client->serialization_version == SER_FMT_VER_INVALID)
4828 Player *player = m_env->getPlayer(client->peer_id);
4829 // Get name of player
4830 std::wstring name = L"unknown";
4832 name = narrow_to_wide(player->getName());
4833 // Add name to information string
4841 if(((ServerMap*)(&m_env->getMap()))->isSavingEnabled() == false)
4842 os<<std::endl<<L"# Server: "<<" WARNING: Map saving is disabled.";
4843 if(g_settings->get("motd") != "")
4844 os<<std::endl<<L"# Server: "<<narrow_to_wide(g_settings->get("motd"));
4848 std::set<std::string> Server::getPlayerEffectivePrivs(const std::string &name)
4850 std::set<std::string> privs;
4851 m_script->getAuth(name, NULL, &privs);
4855 bool Server::checkPriv(const std::string &name, const std::string &priv)
4857 std::set<std::string> privs = getPlayerEffectivePrivs(name);
4858 return (privs.count(priv) != 0);
4861 void Server::reportPrivsModified(const std::string &name)
4864 for(std::map<u16, RemoteClient*>::iterator
4865 i = m_clients.begin();
4866 i != m_clients.end(); ++i){
4867 RemoteClient *client = i->second;
4868 Player *player = m_env->getPlayer(client->peer_id);
4869 reportPrivsModified(player->getName());
4872 Player *player = m_env->getPlayer(name.c_str());
4875 SendPlayerPrivileges(player->peer_id);
4876 PlayerSAO *sao = player->getPlayerSAO();
4879 sao->updatePrivileges(
4880 getPlayerEffectivePrivs(name),
4885 void Server::reportInventoryFormspecModified(const std::string &name)
4887 Player *player = m_env->getPlayer(name.c_str());
4890 SendPlayerInventoryFormspec(player->peer_id);
4893 // Saves g_settings to configpath given at initialization
4894 void Server::saveConfig()
4896 if(m_path_config != "")
4897 g_settings->updateConfigFile(m_path_config.c_str());
4900 void Server::notifyPlayer(const char *name, const std::wstring msg, const bool prepend = true)
4902 Player *player = m_env->getPlayer(name);
4906 SendChatMessage(player->peer_id, std::wstring(L"Server -!- ")+msg);
4908 SendChatMessage(player->peer_id, msg);
4911 bool Server::showFormspec(const char *playername, const std::string &formspec, const std::string &formname)
4913 Player *player = m_env->getPlayer(playername);
4917 infostream<<"showFormspec: couldn't find player:"<<playername<<std::endl;
4921 SendShowFormspecMessage(player->peer_id, formspec, formname);
4925 u32 Server::hudAdd(Player *player, HudElement *form) {
4929 u32 id = hud_get_free_id(player);
4930 if (id < player->hud.size())
4931 player->hud[id] = form;
4933 player->hud.push_back(form);
4935 SendHUDAdd(player->peer_id, id, form);
4939 bool Server::hudRemove(Player *player, u32 id) {
4940 if (!player || id >= player->hud.size() || !player->hud[id])
4943 delete player->hud[id];
4944 player->hud[id] = NULL;
4946 SendHUDRemove(player->peer_id, id);
4950 bool Server::hudChange(Player *player, u32 id, HudElementStat stat, void *data) {
4954 SendHUDChange(player->peer_id, id, stat, data);
4958 bool Server::hudSetFlags(Player *player, u32 flags, u32 mask) {
4962 SendHUDSetFlags(player->peer_id, flags, mask);
4966 bool Server::hudSetHotbarItemcount(Player *player, s32 hotbar_itemcount) {
4969 if (hotbar_itemcount <= 0 || hotbar_itemcount > HUD_HOTBAR_ITEMCOUNT_MAX)
4972 std::ostringstream os(std::ios::binary);
4973 writeS32(os, hotbar_itemcount);
4974 SendHUDSetParam(player->peer_id, HUD_PARAM_HOTBAR_ITEMCOUNT, os.str());
4978 void Server::notifyPlayers(const std::wstring msg)
4980 BroadcastChatMessage(msg);
4983 void Server::spawnParticle(const char *playername, v3f pos,
4984 v3f velocity, v3f acceleration,
4985 float expirationtime, float size, bool
4986 collisiondetection, std::string texture)
4988 Player *player = m_env->getPlayer(playername);
4991 SendSpawnParticle(player->peer_id, pos, velocity, acceleration,
4992 expirationtime, size, collisiondetection, texture);
4995 void Server::spawnParticleAll(v3f pos, v3f velocity, v3f acceleration,
4996 float expirationtime, float size,
4997 bool collisiondetection, std::string texture)
4999 SendSpawnParticleAll(pos, velocity, acceleration,
5000 expirationtime, size, collisiondetection, texture);
5003 u32 Server::addParticleSpawner(const char *playername,
5004 u16 amount, float spawntime,
5005 v3f minpos, v3f maxpos,
5006 v3f minvel, v3f maxvel,
5007 v3f minacc, v3f maxacc,
5008 float minexptime, float maxexptime,
5009 float minsize, float maxsize,
5010 bool collisiondetection, std::string texture)
5012 Player *player = m_env->getPlayer(playername);
5017 for(;;) // look for unused particlespawner id
5020 if (std::find(m_particlespawner_ids.begin(),
5021 m_particlespawner_ids.end(), id)
5022 == m_particlespawner_ids.end())
5024 m_particlespawner_ids.push_back(id);
5029 SendAddParticleSpawner(player->peer_id, amount, spawntime,
5030 minpos, maxpos, minvel, maxvel, minacc, maxacc,
5031 minexptime, maxexptime, minsize, maxsize,
5032 collisiondetection, texture, id);
5037 u32 Server::addParticleSpawnerAll(u16 amount, float spawntime,
5038 v3f minpos, v3f maxpos,
5039 v3f minvel, v3f maxvel,
5040 v3f minacc, v3f maxacc,
5041 float minexptime, float maxexptime,
5042 float minsize, float maxsize,
5043 bool collisiondetection, std::string texture)
5046 for(;;) // look for unused particlespawner id
5049 if (std::find(m_particlespawner_ids.begin(),
5050 m_particlespawner_ids.end(), id)
5051 == m_particlespawner_ids.end())
5053 m_particlespawner_ids.push_back(id);
5058 SendAddParticleSpawnerAll(amount, spawntime,
5059 minpos, maxpos, minvel, maxvel, minacc, maxacc,
5060 minexptime, maxexptime, minsize, maxsize,
5061 collisiondetection, texture, id);
5066 void Server::deleteParticleSpawner(const char *playername, u32 id)
5068 Player *player = m_env->getPlayer(playername);
5072 m_particlespawner_ids.erase(
5073 std::remove(m_particlespawner_ids.begin(),
5074 m_particlespawner_ids.end(), id),
5075 m_particlespawner_ids.end());
5076 SendDeleteParticleSpawner(player->peer_id, id);
5079 void Server::deleteParticleSpawnerAll(u32 id)
5081 m_particlespawner_ids.erase(
5082 std::remove(m_particlespawner_ids.begin(),
5083 m_particlespawner_ids.end(), id),
5084 m_particlespawner_ids.end());
5085 SendDeleteParticleSpawnerAll(id);
5088 void Server::queueBlockEmerge(v3s16 blockpos, bool allow_generate)
5090 m_emerge->enqueueBlockEmerge(PEER_ID_INEXISTENT, blockpos, allow_generate);
5093 Inventory* Server::createDetachedInventory(const std::string &name)
5095 if(m_detached_inventories.count(name) > 0){
5096 infostream<<"Server clearing detached inventory \""<<name<<"\""<<std::endl;
5097 delete m_detached_inventories[name];
5099 infostream<<"Server creating detached inventory \""<<name<<"\""<<std::endl;
5101 Inventory *inv = new Inventory(m_itemdef);
5103 m_detached_inventories[name] = inv;
5104 sendDetachedInventoryToAll(name);
5111 BoolScopeSet(bool *dst, bool val):
5114 m_orig_state = *m_dst;
5119 *m_dst = m_orig_state;
5126 // actions: time-reversed list
5127 // Return value: success/failure
5128 bool Server::rollbackRevertActions(const std::list<RollbackAction> &actions,
5129 std::list<std::string> *log)
5131 infostream<<"Server::rollbackRevertActions(len="<<actions.size()<<")"<<std::endl;
5132 ServerMap *map = (ServerMap*)(&m_env->getMap());
5133 // Disable rollback report sink while reverting
5134 BoolScopeSet rollback_scope_disable(&m_rollback_sink_enabled, false);
5136 // Fail if no actions to handle
5137 if(actions.empty()){
5138 log->push_back("Nothing to do.");
5145 for(std::list<RollbackAction>::const_iterator
5146 i = actions.begin();
5147 i != actions.end(); i++)
5149 const RollbackAction &action = *i;
5151 bool success = action.applyRevert(map, this, this);
5154 std::ostringstream os;
5155 os<<"Revert of step ("<<num_tried<<") "<<action.toString()<<" failed";
5156 infostream<<"Map::rollbackRevertActions(): "<<os.str()<<std::endl;
5158 log->push_back(os.str());
5160 std::ostringstream os;
5161 os<<"Successfully reverted step ("<<num_tried<<") "<<action.toString();
5162 infostream<<"Map::rollbackRevertActions(): "<<os.str()<<std::endl;
5164 log->push_back(os.str());
5168 infostream<<"Map::rollbackRevertActions(): "<<num_failed<<"/"<<num_tried
5169 <<" failed"<<std::endl;
5171 // Call it done if less than half failed
5172 return num_failed <= num_tried/2;
5175 // IGameDef interface
5177 IItemDefManager* Server::getItemDefManager()
5181 INodeDefManager* Server::getNodeDefManager()
5185 ICraftDefManager* Server::getCraftDefManager()
5189 ITextureSource* Server::getTextureSource()
5193 IShaderSource* Server::getShaderSource()
5197 u16 Server::allocateUnknownNodeId(const std::string &name)
5199 return m_nodedef->allocateDummy(name);
5201 ISoundManager* Server::getSoundManager()
5203 return &dummySoundManager;
5205 MtEventManager* Server::getEventManager()
5209 IRollbackReportSink* Server::getRollbackReportSink()
5211 if(!m_enable_rollback_recording)
5213 if(!m_rollback_sink_enabled)
5218 IWritableItemDefManager* Server::getWritableItemDefManager()
5222 IWritableNodeDefManager* Server::getWritableNodeDefManager()
5226 IWritableCraftDefManager* Server::getWritableCraftDefManager()
5231 const ModSpec* Server::getModSpec(const std::string &modname)
5233 for(std::vector<ModSpec>::iterator i = m_mods.begin();
5234 i != m_mods.end(); i++){
5235 const ModSpec &mod = *i;
5236 if(mod.name == modname)
5241 void Server::getModNames(std::list<std::string> &modlist)
5243 for(std::vector<ModSpec>::iterator i = m_mods.begin(); i != m_mods.end(); i++)
5245 modlist.push_back(i->name);
5248 std::string Server::getBuiltinLuaPath()
5250 return porting::path_share + DIR_DELIM + "builtin";
5253 v3f findSpawnPos(ServerMap &map)
5255 //return v3f(50,50,50)*BS;
5260 nodepos = v2s16(0,0);
5265 s16 water_level = map.m_mgparams->water_level;
5267 // Try to find a good place a few times
5268 for(s32 i=0; i<1000; i++)
5271 // We're going to try to throw the player to this position
5272 v2s16 nodepos2d = v2s16(
5273 -range + (myrand() % (range * 2)),
5274 -range + (myrand() % (range * 2)));
5276 // Get ground height at point
5277 s16 groundheight = map.findGroundLevel(nodepos2d);
5278 if (groundheight <= water_level) // Don't go underwater
5280 if (groundheight > water_level + 6) // Don't go to high places
5283 nodepos = v3s16(nodepos2d.X, groundheight, nodepos2d.Y);
5284 bool is_good = false;
5286 for (s32 i = 0; i < 10; i++) {
5287 v3s16 blockpos = getNodeBlockPos(nodepos);
5288 map.emergeBlock(blockpos, true);
5289 content_t c = map.getNodeNoEx(nodepos).getContent();
5290 if (c == CONTENT_AIR || c == CONTENT_IGNORE) {
5292 if (air_count >= 2){
5300 // Found a good place
5301 //infostream<<"Searched through "<<i<<" places."<<std::endl;
5307 return intToFloat(nodepos, BS);
5310 PlayerSAO* Server::emergePlayer(const char *name, u16 peer_id)
5312 RemotePlayer *player = NULL;
5313 bool newplayer = false;
5316 Try to get an existing player
5318 player = static_cast<RemotePlayer*>(m_env->getPlayer(name));
5320 // If player is already connected, cancel
5321 if(player != NULL && player->peer_id != 0)
5323 infostream<<"emergePlayer(): Player already connected"<<std::endl;
5328 If player with the wanted peer_id already exists, cancel.
5330 if(m_env->getPlayer(peer_id) != NULL)
5332 infostream<<"emergePlayer(): Player with wrong name but same"
5333 " peer_id already exists"<<std::endl;
5338 Create a new player if it doesn't exist yet
5343 player = new RemotePlayer(this);
5344 player->updateName(name);
5346 /* Set player position */
5347 infostream<<"Server: Finding spawn place for player \""
5348 <<name<<"\""<<std::endl;
5349 v3f pos = findSpawnPos(m_env->getServerMap());
5350 player->setPosition(pos);
5352 /* Add player to environment */
5353 m_env->addPlayer(player);
5357 Create a new player active object
5359 PlayerSAO *playersao = new PlayerSAO(m_env, player, peer_id,
5360 getPlayerEffectivePrivs(player->getName()),
5363 /* Clean up old HUD elements from previous sessions */
5364 player->hud.clear();
5366 /* Add object to environment */
5367 m_env->addActiveObject(playersao);
5371 m_script->on_newplayer(playersao);
5373 m_script->on_joinplayer(playersao);
5378 void Server::handlePeerChange(PeerChange &c)
5380 JMutexAutoLock envlock(m_env_mutex);
5381 JMutexAutoLock conlock(m_con_mutex);
5383 if(c.type == PEER_ADDED)
5390 std::map<u16, RemoteClient*>::iterator n;
5391 n = m_clients.find(c.peer_id);
5392 // The client shouldn't already exist
5393 assert(n == m_clients.end());
5396 RemoteClient *client = new RemoteClient();
5397 client->peer_id = c.peer_id;
5398 m_clients[client->peer_id] = client;
5401 else if(c.type == PEER_REMOVED)
5407 DeleteClient(c.peer_id, c.timeout?CDR_TIMEOUT:CDR_LEAVE);
5416 void Server::handlePeerChanges()
5418 while(m_peer_change_queue.size() > 0)
5420 PeerChange c = m_peer_change_queue.pop_front();
5422 verbosestream<<"Server: Handling peer change: "
5423 <<"id="<<c.peer_id<<", timeout="<<c.timeout
5426 handlePeerChange(c);
5430 void dedicated_server_loop(Server &server, bool &kill)
5432 DSTACK(__FUNCTION_NAME);
5434 verbosestream<<"dedicated_server_loop()"<<std::endl;
5436 IntervalLimiter m_profiler_interval;
5440 float steplen = g_settings->getFloat("dedicated_server_step");
5441 // This is kind of a hack but can be done like this
5442 // because server.step() is very light
5444 ScopeProfiler sp(g_profiler, "dedicated server sleep");
5445 sleep_ms((int)(steplen*1000.0));
5447 server.step(steplen);
5449 if(server.getShutdownRequested() || kill)
5451 infostream<<"Dedicated server quitting"<<std::endl;
5453 if(g_settings->getBool("server_announce") == true)
5454 ServerList::sendAnnounce("delete");
5462 float profiler_print_interval =
5463 g_settings->getFloat("profiler_print_interval");
5464 if(profiler_print_interval != 0)
5466 if(m_profiler_interval.step(steplen, profiler_print_interval))
5468 infostream<<"Profiler:"<<std::endl;
5469 g_profiler->print(infostream);
5470 g_profiler->clear();