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.
23 #include "clientserver.h"
25 #include "jmutexautolock.h"
27 #include "constants.h"
32 #include "serverobject.h"
37 #include "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"
62 void * ServerThread::Thread()
66 log_register_thread("ServerThread");
68 DSTACK(__FUNCTION_NAME);
70 BEGIN_DEBUG_EXCEPTION_HANDLER
75 //TimeTaker timer("AsyncRunStep() + Receive()");
78 //TimeTaker timer("AsyncRunStep()");
79 m_server->AsyncRunStep();
82 //infostream<<"Running m_server->Receive()"<<std::endl;
85 catch(con::NoIncomingDataException &e)
88 catch(con::PeerNotFoundException &e)
90 infostream<<"Server: PeerNotFoundException"<<std::endl;
92 catch(con::ConnectionBindFailed &e)
94 m_server->setAsyncFatalError(e.what());
98 m_server->setAsyncFatalError(e.what());
102 END_DEBUG_EXCEPTION_HANDLER(errorstream)
107 v3f ServerSoundParams::getPos(ServerEnvironment *env, bool *pos_exists) const
109 if(pos_exists) *pos_exists = false;
114 if(pos_exists) *pos_exists = true;
119 ServerActiveObject *sao = env->getActiveObject(object);
122 if(pos_exists) *pos_exists = true;
123 return sao->getBasePosition(); }
128 void RemoteClient::GetNextBlocks(Server *server, float dtime,
129 std::vector<PrioritySortedBlockTransfer> &dest)
131 DSTACK(__FUNCTION_NAME);
134 TimeTaker timer("RemoteClient::GetNextBlocks", &timer_result);*/
137 m_nothing_to_send_pause_timer -= dtime;
138 m_nearest_unsent_reset_timer += dtime;
140 if(m_nothing_to_send_pause_timer >= 0)
143 Player *player = server->m_env->getPlayer(peer_id);
144 // This can happen sometimes; clients and players are not in perfect sync.
148 // Won't send anything if already sending
149 if(m_blocks_sending.size() >= g_settings->getU16
150 ("max_simultaneous_block_sends_per_client"))
152 //infostream<<"Not sending any blocks, Queue full."<<std::endl;
156 //TimeTaker timer("RemoteClient::GetNextBlocks");
158 v3f playerpos = player->getPosition();
159 v3f playerspeed = player->getSpeed();
160 v3f playerspeeddir(0,0,0);
161 if(playerspeed.getLength() > 1.0*BS)
162 playerspeeddir = playerspeed / playerspeed.getLength();
163 // Predict to next block
164 v3f playerpos_predicted = playerpos + playerspeeddir*MAP_BLOCKSIZE*BS;
166 v3s16 center_nodepos = floatToInt(playerpos_predicted, BS);
168 v3s16 center = getNodeBlockPos(center_nodepos);
170 // Camera position and direction
171 v3f camera_pos = player->getEyePosition();
172 v3f camera_dir = v3f(0,0,1);
173 camera_dir.rotateYZBy(player->getPitch());
174 camera_dir.rotateXZBy(player->getYaw());
176 /*infostream<<"camera_dir=("<<camera_dir.X<<","<<camera_dir.Y<<","
177 <<camera_dir.Z<<")"<<std::endl;*/
180 Get the starting value of the block finder radius.
183 if(m_last_center != center)
185 m_nearest_unsent_d = 0;
186 m_last_center = center;
189 /*infostream<<"m_nearest_unsent_reset_timer="
190 <<m_nearest_unsent_reset_timer<<std::endl;*/
192 // Reset periodically to workaround for some bugs or stuff
193 if(m_nearest_unsent_reset_timer > 20.0)
195 m_nearest_unsent_reset_timer = 0;
196 m_nearest_unsent_d = 0;
197 //infostream<<"Resetting m_nearest_unsent_d for "
198 // <<server->getPlayerName(peer_id)<<std::endl;
201 //s16 last_nearest_unsent_d = m_nearest_unsent_d;
202 s16 d_start = m_nearest_unsent_d;
204 //infostream<<"d_start="<<d_start<<std::endl;
206 u16 max_simul_sends_setting = g_settings->getU16
207 ("max_simultaneous_block_sends_per_client");
208 u16 max_simul_sends_usually = max_simul_sends_setting;
211 Check the time from last addNode/removeNode.
213 Decrease send rate if player is building stuff.
215 m_time_from_building += dtime;
216 if(m_time_from_building < g_settings->getFloat(
217 "full_block_send_enable_min_time_from_building"))
219 max_simul_sends_usually
220 = LIMITED_MAX_SIMULTANEOUS_BLOCK_SENDS;
224 Number of blocks sending + number of blocks selected for sending
226 u32 num_blocks_selected = m_blocks_sending.size();
229 next time d will be continued from the d from which the nearest
230 unsent block was found this time.
232 This is because not necessarily any of the blocks found this
233 time are actually sent.
235 s32 new_nearest_unsent_d = -1;
237 s16 d_max = g_settings->getS16("max_block_send_distance");
238 s16 d_max_gen = g_settings->getS16("max_block_generate_distance");
240 // Don't loop very much at a time
241 s16 max_d_increment_at_time = 2;
242 if(d_max > d_start + max_d_increment_at_time)
243 d_max = d_start + max_d_increment_at_time;
244 /*if(d_max_gen > d_start+2)
245 d_max_gen = d_start+2;*/
247 //infostream<<"Starting from "<<d_start<<std::endl;
249 s32 nearest_emerged_d = -1;
250 s32 nearest_emergefull_d = -1;
251 s32 nearest_sent_d = -1;
252 bool queue_is_full = false;
255 for(d = d_start; d <= d_max; d++)
257 /*errorstream<<"checking d="<<d<<" for "
258 <<server->getPlayerName(peer_id)<<std::endl;*/
259 //infostream<<"RemoteClient::SendBlocks(): d="<<d<<std::endl;
262 If m_nearest_unsent_d was changed by the EmergeThread
263 (it can change it to 0 through SetBlockNotSent),
265 Else update m_nearest_unsent_d
267 /*if(m_nearest_unsent_d != last_nearest_unsent_d)
269 d = m_nearest_unsent_d;
270 last_nearest_unsent_d = m_nearest_unsent_d;
274 Get the border/face dot coordinates of a "d-radiused"
277 std::list<v3s16> list;
278 getFacePositions(list, d);
280 std::list<v3s16>::iterator li;
281 for(li=list.begin(); li!=list.end(); ++li)
283 v3s16 p = *li + center;
287 - Don't allow too many simultaneous transfers
288 - EXCEPT when the blocks are very close
290 Also, don't send blocks that are already flying.
293 // Start with the usual maximum
294 u16 max_simul_dynamic = max_simul_sends_usually;
296 // If block is very close, allow full maximum
297 if(d <= BLOCK_SEND_DISABLE_LIMITS_MAX_D)
298 max_simul_dynamic = max_simul_sends_setting;
300 // Don't select too many blocks for sending
301 if(num_blocks_selected >= max_simul_dynamic)
303 queue_is_full = true;
304 goto queue_full_break;
307 // Don't send blocks that are currently being transferred
308 if(m_blocks_sending.find(p) != m_blocks_sending.end())
314 if(p.X < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
315 || p.X > MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
316 || p.Y < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
317 || p.Y > MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
318 || p.Z < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
319 || p.Z > MAP_GENERATION_LIMIT / MAP_BLOCKSIZE)
322 // If this is true, inexistent block will be made from scratch
323 bool generate = d <= d_max_gen;
326 /*// Limit the generating area vertically to 2/3
327 if(abs(p.Y - center.Y) > d_max_gen - d_max_gen / 3)
330 // Limit the send area vertically to 1/2
331 if(abs(p.Y - center.Y) > d_max / 2)
337 If block is far away, don't generate it unless it is
343 // Block center y in nodes
344 f32 y = (f32)(p.Y * MAP_BLOCKSIZE + MAP_BLOCKSIZE/2);
345 // Don't generate if it's very high or very low
346 if(y < -64 || y > 64)
350 v2s16 p2d_nodes_center(
354 // Get ground height in nodes
355 s16 gh = server->m_env->getServerMap().findGroundLevel(
358 // If differs a lot, don't generate
359 if(fabs(gh - y) > MAP_BLOCKSIZE*2)
361 // Actually, don't even send it
367 //infostream<<"d="<<d<<std::endl;
370 Don't generate or send if not in sight
371 FIXME This only works if the client uses a small enough
372 FOV setting. The default of 72 degrees is fine.
375 float camera_fov = (72.0*M_PI/180) * 4./3.;
376 if(isBlockInSight(p, camera_pos, camera_dir, camera_fov, 10000*BS) == false)
382 Don't send already sent blocks
385 if(m_blocks_sent.find(p) != m_blocks_sent.end())
392 Check if map has this block
394 MapBlock *block = server->m_env->getMap().getBlockNoCreateNoEx(p);
396 bool surely_not_found_on_disk = false;
397 bool block_is_invalid = false;
400 // Reset usage timer, this block will be of use in the future.
401 block->resetUsageTimer();
403 // Block is dummy if data doesn't exist.
404 // It means it has been not found from disk and not generated
407 surely_not_found_on_disk = true;
410 // Block is valid if lighting is up-to-date and data exists
411 if(block->isValid() == false)
413 block_is_invalid = true;
416 /*if(block->isFullyGenerated() == false)
418 block_is_invalid = true;
423 ServerMap *map = (ServerMap*)(&server->m_env->getMap());
424 v2s16 chunkpos = map->sector_to_chunk(p2d);
425 if(map->chunkNonVolatile(chunkpos) == false)
426 block_is_invalid = true;
428 if(block->isGenerated() == false)
429 block_is_invalid = true;
432 If block is not close, don't send it unless it is near
435 Block is near ground level if night-time mesh
436 differs from day-time mesh.
440 if(block->getDayNightDiff() == false)
447 If block has been marked to not exist on disk (dummy)
448 and generating new ones is not wanted, skip block.
450 if(generate == false && surely_not_found_on_disk == true)
457 Add inexistent block to emerge queue.
459 if(block == NULL || surely_not_found_on_disk || block_is_invalid)
461 /* //TODO: Get value from somewhere
462 // Allow only one block in emerge queue
463 //if(server->m_emerge_queue.peerItemCount(peer_id) < 1)
464 // Allow two blocks in queue per client
465 //if(server->m_emerge_queue.peerItemCount(peer_id) < 2)
467 // Make it more responsive when needing to generate stuff
468 if(surely_not_found_on_disk)
470 if(server->m_emerge_queue.peerItemCount(peer_id) < max_emerge)
472 //infostream<<"Adding block to emerge queue"<<std::endl;
474 // Add it to the emerge queue and trigger the thread
477 if(generate == false)
478 flags |= BLOCK_EMERGE_FLAG_FROMDISK;
480 server->m_emerge_queue.addBlock(peer_id, p, flags);
481 server->m_emergethread.trigger();
483 if(nearest_emerged_d == -1)
484 nearest_emerged_d = d;
486 if(nearest_emergefull_d == -1)
487 nearest_emergefull_d = d;
488 goto queue_full_break;
492 if (server->m_emerge->enqueueBlockEmerge(peer_id, p, generate)) {
493 if (nearest_emerged_d == -1)
494 nearest_emerged_d = d;
496 if (nearest_emergefull_d == -1)
497 nearest_emergefull_d = d;
498 goto queue_full_break;
505 if(nearest_sent_d == -1)
509 Add block to send queue
512 /*errorstream<<"sending from d="<<d<<" to "
513 <<server->getPlayerName(peer_id)<<std::endl;*/
515 PrioritySortedBlockTransfer q((float)d, p, peer_id);
519 num_blocks_selected += 1;
524 //infostream<<"Stopped at "<<d<<std::endl;
526 // If nothing was found for sending and nothing was queued for
527 // emerging, continue next time browsing from here
528 if(nearest_emerged_d != -1){
529 new_nearest_unsent_d = nearest_emerged_d;
530 } else if(nearest_emergefull_d != -1){
531 new_nearest_unsent_d = nearest_emergefull_d;
533 if(d > g_settings->getS16("max_block_send_distance")){
534 new_nearest_unsent_d = 0;
535 m_nothing_to_send_pause_timer = 2.0;
536 /*infostream<<"GetNextBlocks(): d wrapped around for "
537 <<server->getPlayerName(peer_id)
538 <<"; setting to 0 and pausing"<<std::endl;*/
540 if(nearest_sent_d != -1)
541 new_nearest_unsent_d = nearest_sent_d;
543 new_nearest_unsent_d = d;
547 if(new_nearest_unsent_d != -1)
548 m_nearest_unsent_d = new_nearest_unsent_d;
550 /*timer_result = timer.stop(true);
551 if(timer_result != 0)
552 infostream<<"GetNextBlocks timeout: "<<timer_result<<" (!=0)"<<std::endl;*/
555 void RemoteClient::GotBlock(v3s16 p)
557 if(m_blocks_sending.find(p) != m_blocks_sending.end())
558 m_blocks_sending.erase(p);
561 /*infostream<<"RemoteClient::GotBlock(): Didn't find in"
562 " m_blocks_sending"<<std::endl;*/
563 m_excess_gotblocks++;
565 m_blocks_sent.insert(p);
568 void RemoteClient::SentBlock(v3s16 p)
570 if(m_blocks_sending.find(p) == m_blocks_sending.end())
571 m_blocks_sending[p] = 0.0;
573 infostream<<"RemoteClient::SentBlock(): Sent block"
574 " already in m_blocks_sending"<<std::endl;
577 void RemoteClient::SetBlockNotSent(v3s16 p)
579 m_nearest_unsent_d = 0;
581 if(m_blocks_sending.find(p) != m_blocks_sending.end())
582 m_blocks_sending.erase(p);
583 if(m_blocks_sent.find(p) != m_blocks_sent.end())
584 m_blocks_sent.erase(p);
587 void RemoteClient::SetBlocksNotSent(std::map<v3s16, MapBlock*> &blocks)
589 m_nearest_unsent_d = 0;
591 for(std::map<v3s16, MapBlock*>::iterator
593 i != blocks.end(); ++i)
597 if(m_blocks_sending.find(p) != m_blocks_sending.end())
598 m_blocks_sending.erase(p);
599 if(m_blocks_sent.find(p) != m_blocks_sent.end())
600 m_blocks_sent.erase(p);
608 PlayerInfo::PlayerInfo()
614 void PlayerInfo::PrintLine(std::ostream *s)
617 (*s)<<"\""<<name<<"\" ("
618 <<(position.X/10)<<","<<(position.Y/10)
619 <<","<<(position.Z/10)<<") ";
621 (*s)<<" avg_rtt="<<avg_rtt;
630 const std::string &path_world,
631 const std::string &path_config,
632 const SubgameSpec &gamespec,
633 bool simple_singleplayer_mode
635 m_path_world(path_world),
636 m_path_config(path_config),
637 m_gamespec(gamespec),
638 m_simple_singleplayer_mode(simple_singleplayer_mode),
639 m_async_fatal_error(""),
641 m_con(PROTOCOL_ID, 512, CONNECTION_TIMEOUT, this),
642 m_banmanager(path_world+DIR_DELIM+"ipban.txt"),
644 m_rollback_sink_enabled(true),
645 m_enable_rollback_recording(false),
649 m_itemdef(createItemDefManager()),
650 m_nodedef(createNodeDefManager()),
651 m_craftdef(createCraftDefManager()),
652 m_event(new EventManager()),
654 //m_emergethread(this),
655 m_time_of_day_send_timer(0),
657 m_shutdown_requested(false),
658 m_ignore_map_edit_events(false),
659 m_ignore_map_edit_events_peer_id(0)
661 m_liquid_transform_timer = 0.0;
662 m_liquid_transform_every = 1.0;
663 m_print_info_timer = 0.0;
664 m_masterserver_timer = 0.0;
665 m_objectdata_timer = 0.0;
666 m_emergethread_trigger_timer = 0.0;
667 m_savemap_timer = 0.0;
668 m_clients_number = 0;
672 m_step_dtime_mutex.Init();
676 throw ServerError("Supplied empty world path");
678 if(!gamespec.isValid())
679 throw ServerError("Supplied invalid gamespec");
681 infostream<<"Server created for gameid \""<<m_gamespec.id<<"\"";
682 if(m_simple_singleplayer_mode)
683 infostream<<" in simple singleplayer mode"<<std::endl;
685 infostream<<std::endl;
686 infostream<<"- world: "<<m_path_world<<std::endl;
687 infostream<<"- config: "<<m_path_config<<std::endl;
688 infostream<<"- game: "<<m_gamespec.path<<std::endl;
690 // Create biome definition manager
691 m_biomedef = new BiomeDefManager(this);
693 // Create rollback manager
694 std::string rollback_path = m_path_world+DIR_DELIM+"rollback.txt";
695 m_rollback = createRollbackManager(rollback_path, this);
697 // Create world if it doesn't exist
698 if(!initializeWorld(m_path_world, m_gamespec.id))
699 throw ServerError("Failed to initialize world");
701 ModConfiguration modconf(m_path_world);
702 m_mods = modconf.getMods();
703 std::list<ModSpec> unsatisfied_mods = modconf.getUnsatisfiedMods();
704 // complain about mods with unsatisfied dependencies
705 if(!modconf.isConsistent())
707 for(std::list<ModSpec>::iterator it = unsatisfied_mods.begin();
708 it != unsatisfied_mods.end(); ++it)
711 errorstream << "mod \"" << mod.name << "\" has unsatisfied dependencies: ";
712 for(std::set<std::string>::iterator dep_it = mod.unsatisfied_depends.begin();
713 dep_it != mod.unsatisfied_depends.end(); ++dep_it)
714 errorstream << " \"" << *dep_it << "\"";
715 errorstream << std::endl;
719 Settings worldmt_settings;
720 std::string worldmt = m_path_world + DIR_DELIM + "world.mt";
721 worldmt_settings.readConfigFile(worldmt.c_str());
722 std::vector<std::string> names = worldmt_settings.getNames();
723 std::set<std::string> exclude_mod_names;
724 std::set<std::string> load_mod_names;
725 for(std::vector<std::string>::iterator it = names.begin();
726 it != names.end(); ++it)
728 std::string name = *it;
729 if (name.compare(0,9,"load_mod_")==0)
731 if(worldmt_settings.getBool(name))
732 load_mod_names.insert(name.substr(9));
734 exclude_mod_names.insert(name.substr(9));
737 // complain about mods declared to be loaded, but not found
738 for(std::vector<ModSpec>::iterator it = m_mods.begin();
739 it != m_mods.end(); ++it)
740 load_mod_names.erase((*it).name);
741 for(std::list<ModSpec>::iterator it = unsatisfied_mods.begin();
742 it != unsatisfied_mods.end(); ++it)
743 load_mod_names.erase((*it).name);
744 if(!load_mod_names.empty())
746 errorstream << "The following mods could not be found:";
747 for(std::set<std::string>::iterator it = load_mod_names.begin();
748 it != load_mod_names.end(); ++it)
749 errorstream << " \"" << (*it) << "\"";
750 errorstream << std::endl;
753 // Path to builtin.lua
754 std::string builtinpath = getBuiltinLuaPath() + DIR_DELIM + "builtin.lua";
757 JMutexAutoLock envlock(m_env_mutex);
758 JMutexAutoLock conlock(m_con_mutex);
760 // Initialize scripting
762 infostream<<"Server: Initializing Lua"<<std::endl;
763 m_lua = script_init();
766 scriptapi_export(m_lua, this);
767 // Load and run builtin.lua
768 infostream<<"Server: Loading builtin.lua [\""
769 <<builtinpath<<"\"]"<<std::endl;
770 bool success = scriptapi_loadmod(m_lua, builtinpath, "__builtin");
772 errorstream<<"Server: Failed to load and run "
773 <<builtinpath<<std::endl;
774 throw ModError("Failed to load and run "+builtinpath);
777 infostream<<"Server: Loading mods: ";
778 for(std::vector<ModSpec>::iterator i = m_mods.begin();
779 i != m_mods.end(); i++){
780 const ModSpec &mod = *i;
781 infostream<<mod.name<<" ";
783 infostream<<std::endl;
784 // Load and run "mod" scripts
785 for(std::vector<ModSpec>::iterator i = m_mods.begin();
786 i != m_mods.end(); i++){
787 const ModSpec &mod = *i;
788 std::string scriptpath = mod.path + DIR_DELIM + "init.lua";
789 infostream<<" ["<<padStringRight(mod.name, 12)<<"] [\""
790 <<scriptpath<<"\"]"<<std::endl;
791 bool success = scriptapi_loadmod(m_lua, scriptpath, mod.name);
793 errorstream<<"Server: Failed to load and run "
794 <<scriptpath<<std::endl;
795 throw ModError("Failed to load and run "+scriptpath);
799 // Read Textures and calculate sha1 sums
802 // Apply item aliases in the node definition manager
803 m_nodedef->updateAliases(m_itemdef);
805 // Add default biomes after nodedef had its aliases added
806 m_biomedef->addDefaultBiomes();
808 // Create emerge manager
809 m_emerge = new EmergeManager(this, m_biomedef);
811 // Initialize Environment
812 ServerMap *servermap = new ServerMap(path_world, this, m_emerge);
813 m_env = new ServerEnvironment(servermap, m_lua, this, this);
815 m_emerge->initMapgens(servermap->getMapgenParams());
817 // Give environment reference to scripting api
818 scriptapi_add_environment(m_lua, m_env);
820 // Register us to receive map edit events
821 servermap->addEventReceiver(this);
823 // If file exists, load environment metadata
824 if(fs::PathExists(m_path_world+DIR_DELIM+"env_meta.txt"))
826 infostream<<"Server: Loading environment metadata"<<std::endl;
827 m_env->loadMeta(m_path_world);
831 infostream<<"Server: Loading players"<<std::endl;
832 m_env->deSerializePlayers(m_path_world);
835 Add some test ActiveBlockModifiers to environment
837 add_legacy_abms(m_env, m_nodedef);
839 m_liquid_transform_every = g_settings->getFloat("liquid_update");
844 infostream<<"Server destructing"<<std::endl;
847 Send shutdown message
850 JMutexAutoLock conlock(m_con_mutex);
852 std::wstring line = L"*** Server shutting down";
855 Send the message to clients
857 for(std::map<u16, RemoteClient*>::iterator
858 i = m_clients.begin();
859 i != m_clients.end(); ++i)
861 // Get client and check that it is valid
862 RemoteClient *client = i->second;
863 assert(client->peer_id == i->first);
864 if(client->serialization_version == SER_FMT_VER_INVALID)
868 SendChatMessage(client->peer_id, line);
870 catch(con::PeerNotFoundException &e)
876 JMutexAutoLock envlock(m_env_mutex);
877 JMutexAutoLock conlock(m_con_mutex);
880 Execute script shutdown hooks
882 scriptapi_on_shutdown(m_lua);
886 JMutexAutoLock envlock(m_env_mutex);
891 infostream<<"Server: Saving players"<<std::endl;
892 m_env->serializePlayers(m_path_world);
895 Save environment metadata
897 infostream<<"Server: Saving environment metadata"<<std::endl;
898 m_env->saveMeta(m_path_world);
910 JMutexAutoLock clientslock(m_con_mutex);
912 for(std::map<u16, RemoteClient*>::iterator
913 i = m_clients.begin();
914 i != m_clients.end(); ++i)
922 // Delete things in the reverse order of creation
931 // Deinitialize scripting
932 infostream<<"Server: Deinitializing scripting"<<std::endl;
933 script_deinit(m_lua);
935 // Delete detached inventories
937 for(std::map<std::string, Inventory*>::iterator
938 i = m_detached_inventories.begin();
939 i != m_detached_inventories.end(); i++){
945 void Server::start(unsigned short port)
947 DSTACK(__FUNCTION_NAME);
948 infostream<<"Starting server on port "<<port<<"..."<<std::endl;
950 // Stop thread if already running
953 // Initialize connection
954 m_con.SetTimeoutMs(30);
958 m_thread.setRun(true);
961 // ASCII art for the win!
963 <<" .__ __ __ "<<std::endl
964 <<" _____ |__| ____ _____/ |_ ____ _______/ |_ "<<std::endl
965 <<" / \\| |/ \\_/ __ \\ __\\/ __ \\ / ___/\\ __\\"<<std::endl
966 <<"| Y Y \\ | | \\ ___/| | \\ ___/ \\___ \\ | | "<<std::endl
967 <<"|__|_| /__|___| /\\___ >__| \\___ >____ > |__| "<<std::endl
968 <<" \\/ \\/ \\/ \\/ \\/ "<<std::endl;
969 actionstream<<"World at ["<<m_path_world<<"]"<<std::endl;
970 actionstream<<"Server for gameid=\""<<m_gamespec.id
971 <<"\" listening on port "<<port<<"."<<std::endl;
976 DSTACK(__FUNCTION_NAME);
978 infostream<<"Server: Stopping and waiting threads"<<std::endl;
980 // Stop threads (set run=false first so both start stopping)
981 m_thread.setRun(false);
982 //m_emergethread.setRun(false);
984 //m_emergethread.stop();
986 infostream<<"Server: Threads stopped"<<std::endl;
989 void Server::step(float dtime)
991 DSTACK(__FUNCTION_NAME);
996 JMutexAutoLock lock(m_step_dtime_mutex);
997 m_step_dtime += dtime;
999 // Throw if fatal error occurred in thread
1000 std::string async_err = m_async_fatal_error.get();
1001 if(async_err != ""){
1002 throw ServerError(async_err);
1006 void Server::AsyncRunStep()
1008 DSTACK(__FUNCTION_NAME);
1010 g_profiler->add("Server::AsyncRunStep (num)", 1);
1014 JMutexAutoLock lock1(m_step_dtime_mutex);
1015 dtime = m_step_dtime;
1019 // Send blocks to clients
1026 g_profiler->add("Server::AsyncRunStep with dtime (num)", 1);
1028 //infostream<<"Server steps "<<dtime<<std::endl;
1029 //infostream<<"Server::AsyncRunStep(): dtime="<<dtime<<std::endl;
1032 JMutexAutoLock lock1(m_step_dtime_mutex);
1033 m_step_dtime -= dtime;
1040 m_uptime.set(m_uptime.get() + dtime);
1044 // Process connection's timeouts
1045 JMutexAutoLock lock2(m_con_mutex);
1046 ScopeProfiler sp(g_profiler, "Server: connection timeout processing");
1047 m_con.RunTimeouts(dtime);
1051 // This has to be called so that the client list gets synced
1052 // with the peer list of the connection
1053 handlePeerChanges();
1057 Update time of day and overall game time
1060 JMutexAutoLock envlock(m_env_mutex);
1062 m_env->setTimeOfDaySpeed(g_settings->getFloat("time_speed"));
1065 Send to clients at constant intervals
1068 m_time_of_day_send_timer -= dtime;
1069 if(m_time_of_day_send_timer < 0.0)
1071 m_time_of_day_send_timer = g_settings->getFloat("time_send_interval");
1073 //JMutexAutoLock envlock(m_env_mutex);
1074 JMutexAutoLock conlock(m_con_mutex);
1076 for(std::map<u16, RemoteClient*>::iterator
1077 i = m_clients.begin();
1078 i != m_clients.end(); ++i)
1080 RemoteClient *client = i->second;
1081 SharedBuffer<u8> data = makePacket_TOCLIENT_TIME_OF_DAY(
1082 m_env->getTimeOfDay(), g_settings->getFloat("time_speed"));
1084 m_con.Send(client->peer_id, 0, data, true);
1090 JMutexAutoLock lock(m_env_mutex);
1092 ScopeProfiler sp(g_profiler, "SEnv step");
1093 ScopeProfiler sp2(g_profiler, "SEnv step avg", SPT_AVG);
1097 const float map_timer_and_unload_dtime = 2.92;
1098 if(m_map_timer_and_unload_interval.step(dtime, map_timer_and_unload_dtime))
1100 JMutexAutoLock lock(m_env_mutex);
1101 // Run Map's timers and unload unused data
1102 ScopeProfiler sp(g_profiler, "Server: map timer and unload");
1103 m_env->getMap().timerUpdate(map_timer_and_unload_dtime,
1104 g_settings->getFloat("server_unload_unused_data_timeout"));
1115 JMutexAutoLock lock(m_env_mutex);
1116 JMutexAutoLock lock2(m_con_mutex);
1118 ScopeProfiler sp(g_profiler, "Server: handle players");
1120 for(std::map<u16, RemoteClient*>::iterator
1121 i = m_clients.begin();
1122 i != m_clients.end(); ++i)
1124 RemoteClient *client = i->second;
1125 PlayerSAO *playersao = getPlayerSAO(client->peer_id);
1126 if(playersao == NULL)
1130 Handle player HPs (die if hp=0)
1132 if(playersao->m_hp_not_sent && g_settings->getBool("enable_damage"))
1134 if(playersao->getHP() == 0)
1135 DiePlayer(client->peer_id);
1137 SendPlayerHP(client->peer_id);
1141 Send player inventories if necessary
1143 if(playersao->m_moved){
1144 SendMovePlayer(client->peer_id);
1145 playersao->m_moved = false;
1147 if(playersao->m_inventory_not_sent){
1148 UpdateCrafting(client->peer_id);
1149 SendInventory(client->peer_id);
1154 /* Transform liquids */
1155 m_liquid_transform_timer += dtime;
1156 if(m_liquid_transform_timer >= m_liquid_transform_every)
1158 m_liquid_transform_timer -= m_liquid_transform_every;
1160 JMutexAutoLock lock(m_env_mutex);
1162 ScopeProfiler sp(g_profiler, "Server: liquid transform");
1164 std::map<v3s16, MapBlock*> modified_blocks;
1165 m_env->getMap().transformLiquids(modified_blocks);
1170 core::map<v3s16, MapBlock*> lighting_modified_blocks;
1171 ServerMap &map = ((ServerMap&)m_env->getMap());
1172 map.updateLighting(modified_blocks, lighting_modified_blocks);
1174 // Add blocks modified by lighting to modified_blocks
1175 for(core::map<v3s16, MapBlock*>::Iterator
1176 i = lighting_modified_blocks.getIterator();
1177 i.atEnd() == false; i++)
1179 MapBlock *block = i.getNode()->getValue();
1180 modified_blocks.insert(block->getPos(), block);
1184 Set the modified blocks unsent for all the clients
1187 JMutexAutoLock lock2(m_con_mutex);
1189 for(std::map<u16, RemoteClient*>::iterator
1190 i = m_clients.begin();
1191 i != m_clients.end(); ++i)
1193 RemoteClient *client = i->second;
1195 if(modified_blocks.size() > 0)
1197 // Remove block from sent history
1198 client->SetBlocksNotSent(modified_blocks);
1203 // Periodically print some info
1205 float &counter = m_print_info_timer;
1211 JMutexAutoLock lock2(m_con_mutex);
1212 m_clients_number = 0;
1213 if(m_clients.size() != 0)
1214 infostream<<"Players:"<<std::endl;
1215 for(std::map<u16, RemoteClient*>::iterator
1216 i = m_clients.begin();
1217 i != m_clients.end(); ++i)
1219 //u16 peer_id = i.getNode()->getKey();
1220 RemoteClient *client = i->second;
1221 Player *player = m_env->getPlayer(client->peer_id);
1224 infostream<<"* "<<player->getName()<<"\t";
1225 client->PrintInfo(infostream);
1233 // send masterserver announce
1235 float &counter = m_masterserver_timer;
1236 if((!counter || counter >= 300.0) && g_settings->getBool("server_announce") == true)
1238 ServerList::sendAnnounce(!counter ? "start" : "update", m_clients_number);
1245 //if(g_settings->getBool("enable_experimental"))
1249 Check added and deleted active objects
1252 //infostream<<"Server: Checking added and deleted active objects"<<std::endl;
1253 JMutexAutoLock envlock(m_env_mutex);
1254 JMutexAutoLock conlock(m_con_mutex);
1256 ScopeProfiler sp(g_profiler, "Server: checking added and deleted objs");
1258 // Radius inside which objects are active
1259 s16 radius = g_settings->getS16("active_object_send_range_blocks");
1260 radius *= MAP_BLOCKSIZE;
1262 for(std::map<u16, RemoteClient*>::iterator
1263 i = m_clients.begin();
1264 i != m_clients.end(); ++i)
1266 RemoteClient *client = i->second;
1268 // If definitions and textures have not been sent, don't
1269 // send objects either
1270 if(!client->definitions_sent)
1273 Player *player = m_env->getPlayer(client->peer_id);
1276 // This can happen if the client timeouts somehow
1277 /*infostream<<"WARNING: "<<__FUNCTION_NAME<<": Client "
1279 <<" has no associated player"<<std::endl;*/
1282 v3s16 pos = floatToInt(player->getPosition(), BS);
1284 std::set<u16> removed_objects;
1285 std::set<u16> added_objects;
1286 m_env->getRemovedActiveObjects(pos, radius,
1287 client->m_known_objects, removed_objects);
1288 m_env->getAddedActiveObjects(pos, radius,
1289 client->m_known_objects, added_objects);
1291 // Ignore if nothing happened
1292 if(removed_objects.size() == 0 && added_objects.size() == 0)
1294 //infostream<<"active objects: none changed"<<std::endl;
1298 std::string data_buffer;
1302 // Handle removed objects
1303 writeU16((u8*)buf, removed_objects.size());
1304 data_buffer.append(buf, 2);
1305 for(std::set<u16>::iterator
1306 i = removed_objects.begin();
1307 i != removed_objects.end(); ++i)
1311 ServerActiveObject* obj = m_env->getActiveObject(id);
1313 // Add to data buffer for sending
1314 writeU16((u8*)buf, id);
1315 data_buffer.append(buf, 2);
1317 // Remove from known objects
1318 client->m_known_objects.erase(id);
1320 if(obj && obj->m_known_by_count > 0)
1321 obj->m_known_by_count--;
1324 // Handle added objects
1325 writeU16((u8*)buf, added_objects.size());
1326 data_buffer.append(buf, 2);
1327 for(std::set<u16>::iterator
1328 i = added_objects.begin();
1329 i != added_objects.end(); ++i)
1333 ServerActiveObject* obj = m_env->getActiveObject(id);
1336 u8 type = ACTIVEOBJECT_TYPE_INVALID;
1338 infostream<<"WARNING: "<<__FUNCTION_NAME
1339 <<": NULL object"<<std::endl;
1341 type = obj->getSendType();
1343 // Add to data buffer for sending
1344 writeU16((u8*)buf, id);
1345 data_buffer.append(buf, 2);
1346 writeU8((u8*)buf, type);
1347 data_buffer.append(buf, 1);
1350 data_buffer.append(serializeLongString(
1351 obj->getClientInitializationData(client->net_proto_version)));
1353 data_buffer.append(serializeLongString(""));
1355 // Add to known objects
1356 client->m_known_objects.insert(id);
1359 obj->m_known_by_count++;
1363 SharedBuffer<u8> reply(2 + data_buffer.size());
1364 writeU16(&reply[0], TOCLIENT_ACTIVE_OBJECT_REMOVE_ADD);
1365 memcpy((char*)&reply[2], data_buffer.c_str(),
1366 data_buffer.size());
1368 m_con.Send(client->peer_id, 0, reply, true);
1370 verbosestream<<"Server: Sent object remove/add: "
1371 <<removed_objects.size()<<" removed, "
1372 <<added_objects.size()<<" added, "
1373 <<"packet size is "<<reply.getSize()<<std::endl;
1378 Collect a list of all the objects known by the clients
1379 and report it back to the environment.
1382 core::map<u16, bool> all_known_objects;
1384 for(core::map<u16, RemoteClient*>::Iterator
1385 i = m_clients.getIterator();
1386 i.atEnd() == false; i++)
1388 RemoteClient *client = i.getNode()->getValue();
1389 // Go through all known objects of client
1390 for(core::map<u16, bool>::Iterator
1391 i = client->m_known_objects.getIterator();
1392 i.atEnd()==false; i++)
1394 u16 id = i.getNode()->getKey();
1395 all_known_objects[id] = true;
1399 m_env->setKnownActiveObjects(whatever);
1405 Send object messages
1408 JMutexAutoLock envlock(m_env_mutex);
1409 JMutexAutoLock conlock(m_con_mutex);
1411 ScopeProfiler sp(g_profiler, "Server: sending object messages");
1414 // Value = data sent by object
1415 std::map<u16, std::list<ActiveObjectMessage>* > buffered_messages;
1417 // Get active object messages from environment
1420 ActiveObjectMessage aom = m_env->getActiveObjectMessage();
1424 std::list<ActiveObjectMessage>* message_list = NULL;
1425 std::map<u16, std::list<ActiveObjectMessage>* >::iterator n;
1426 n = buffered_messages.find(aom.id);
1427 if(n == buffered_messages.end())
1429 message_list = new std::list<ActiveObjectMessage>;
1430 buffered_messages[aom.id] = message_list;
1434 message_list = n->second;
1436 message_list->push_back(aom);
1439 // Route data to every client
1440 for(std::map<u16, RemoteClient*>::iterator
1441 i = m_clients.begin();
1442 i != m_clients.end(); ++i)
1444 RemoteClient *client = i->second;
1445 std::string reliable_data;
1446 std::string unreliable_data;
1447 // Go through all objects in message buffer
1448 for(std::map<u16, std::list<ActiveObjectMessage>* >::iterator
1449 j = buffered_messages.begin();
1450 j != buffered_messages.end(); ++j)
1452 // If object is not known by client, skip it
1454 if(client->m_known_objects.find(id) == client->m_known_objects.end())
1456 // Get message list of object
1457 std::list<ActiveObjectMessage>* list = j->second;
1458 // Go through every message
1459 for(std::list<ActiveObjectMessage>::iterator
1460 k = list->begin(); k != list->end(); ++k)
1462 // Compose the full new data with header
1463 ActiveObjectMessage aom = *k;
1464 std::string new_data;
1467 writeU16((u8*)&buf[0], aom.id);
1468 new_data.append(buf, 2);
1470 new_data += serializeString(aom.datastring);
1471 // Add data to buffer
1473 reliable_data += new_data;
1475 unreliable_data += new_data;
1479 reliable_data and unreliable_data are now ready.
1482 if(reliable_data.size() > 0)
1484 SharedBuffer<u8> reply(2 + reliable_data.size());
1485 writeU16(&reply[0], TOCLIENT_ACTIVE_OBJECT_MESSAGES);
1486 memcpy((char*)&reply[2], reliable_data.c_str(),
1487 reliable_data.size());
1489 m_con.Send(client->peer_id, 0, reply, true);
1491 if(unreliable_data.size() > 0)
1493 SharedBuffer<u8> reply(2 + unreliable_data.size());
1494 writeU16(&reply[0], TOCLIENT_ACTIVE_OBJECT_MESSAGES);
1495 memcpy((char*)&reply[2], unreliable_data.c_str(),
1496 unreliable_data.size());
1497 // Send as unreliable
1498 m_con.Send(client->peer_id, 0, reply, false);
1501 /*if(reliable_data.size() > 0 || unreliable_data.size() > 0)
1503 infostream<<"Server: Size of object message data: "
1504 <<"reliable: "<<reliable_data.size()
1505 <<", unreliable: "<<unreliable_data.size()
1510 // Clear buffered_messages
1511 for(std::map<u16, std::list<ActiveObjectMessage>* >::iterator
1512 i = buffered_messages.begin();
1513 i != buffered_messages.end(); ++i)
1519 } // enable_experimental
1522 Send queued-for-sending map edit events.
1525 // We will be accessing the environment and the connection
1526 JMutexAutoLock lock(m_env_mutex);
1527 JMutexAutoLock conlock(m_con_mutex);
1529 // Don't send too many at a time
1532 // Single change sending is disabled if queue size is not small
1533 bool disable_single_change_sending = false;
1534 if(m_unsent_map_edit_queue.size() >= 4)
1535 disable_single_change_sending = true;
1537 int event_count = m_unsent_map_edit_queue.size();
1539 // We'll log the amount of each
1542 while(m_unsent_map_edit_queue.size() != 0)
1544 MapEditEvent* event = m_unsent_map_edit_queue.pop_front();
1546 // Players far away from the change are stored here.
1547 // Instead of sending the changes, MapBlocks are set not sent
1549 std::list<u16> far_players;
1551 if(event->type == MEET_ADDNODE)
1553 //infostream<<"Server: MEET_ADDNODE"<<std::endl;
1554 prof.add("MEET_ADDNODE", 1);
1555 if(disable_single_change_sending)
1556 sendAddNode(event->p, event->n, event->already_known_by_peer,
1559 sendAddNode(event->p, event->n, event->already_known_by_peer,
1562 else if(event->type == MEET_REMOVENODE)
1564 //infostream<<"Server: MEET_REMOVENODE"<<std::endl;
1565 prof.add("MEET_REMOVENODE", 1);
1566 if(disable_single_change_sending)
1567 sendRemoveNode(event->p, event->already_known_by_peer,
1570 sendRemoveNode(event->p, event->already_known_by_peer,
1573 else if(event->type == MEET_BLOCK_NODE_METADATA_CHANGED)
1575 infostream<<"Server: MEET_BLOCK_NODE_METADATA_CHANGED"<<std::endl;
1576 prof.add("MEET_BLOCK_NODE_METADATA_CHANGED", 1);
1577 setBlockNotSent(event->p);
1579 else if(event->type == MEET_OTHER)
1581 infostream<<"Server: MEET_OTHER"<<std::endl;
1582 prof.add("MEET_OTHER", 1);
1583 for(std::set<v3s16>::iterator
1584 i = event->modified_blocks.begin();
1585 i != event->modified_blocks.end(); ++i)
1587 setBlockNotSent(*i);
1592 prof.add("unknown", 1);
1593 infostream<<"WARNING: Server: Unknown MapEditEvent "
1594 <<((u32)event->type)<<std::endl;
1598 Set blocks not sent to far players
1600 if(far_players.size() > 0)
1602 // Convert list format to that wanted by SetBlocksNotSent
1603 std::map<v3s16, MapBlock*> modified_blocks2;
1604 for(std::set<v3s16>::iterator
1605 i = event->modified_blocks.begin();
1606 i != event->modified_blocks.end(); ++i)
1608 modified_blocks2[*i] =
1609 m_env->getMap().getBlockNoCreateNoEx(*i);
1611 // Set blocks not sent
1612 for(std::list<u16>::iterator
1613 i = far_players.begin();
1614 i != far_players.end(); ++i)
1617 RemoteClient *client = getClient(peer_id);
1620 client->SetBlocksNotSent(modified_blocks2);
1626 /*// Don't send too many at a time
1628 if(count >= 1 && m_unsent_map_edit_queue.size() < 100)
1632 if(event_count >= 5){
1633 infostream<<"Server: MapEditEvents:"<<std::endl;
1634 prof.print(infostream);
1635 } else if(event_count != 0){
1636 verbosestream<<"Server: MapEditEvents:"<<std::endl;
1637 prof.print(verbosestream);
1643 Trigger emergethread (it somehow gets to a non-triggered but
1644 bysy state sometimes)
1647 float &counter = m_emergethread_trigger_timer;
1653 for (unsigned int i = 0; i != m_emerge->emergethread.size(); i++)
1654 m_emerge->emergethread[i]->trigger();
1656 // Update m_enable_rollback_recording here too
1657 m_enable_rollback_recording =
1658 g_settings->getBool("enable_rollback_recording");
1662 // Save map, players and auth stuff
1664 float &counter = m_savemap_timer;
1666 if(counter >= g_settings->getFloat("server_map_save_interval"))
1669 JMutexAutoLock lock(m_env_mutex);
1671 ScopeProfiler sp(g_profiler, "Server: saving stuff");
1674 if(m_banmanager.isModified())
1675 m_banmanager.save();
1677 // Save changed parts of map
1678 m_env->getMap().save(MOD_STATE_WRITE_NEEDED);
1681 m_env->serializePlayers(m_path_world);
1683 // Save environment metadata
1684 m_env->saveMeta(m_path_world);
1689 void Server::Receive()
1691 DSTACK(__FUNCTION_NAME);
1692 SharedBuffer<u8> data;
1697 JMutexAutoLock conlock(m_con_mutex);
1698 datasize = m_con.Receive(peer_id, data);
1701 // This has to be called so that the client list gets synced
1702 // with the peer list of the connection
1703 handlePeerChanges();
1705 ProcessData(*data, datasize, peer_id);
1707 catch(con::InvalidIncomingDataException &e)
1709 infostream<<"Server::Receive(): "
1710 "InvalidIncomingDataException: what()="
1711 <<e.what()<<std::endl;
1713 catch(con::PeerNotFoundException &e)
1715 //NOTE: This is not needed anymore
1717 // The peer has been disconnected.
1718 // Find the associated player and remove it.
1720 /*JMutexAutoLock envlock(m_env_mutex);
1722 infostream<<"ServerThread: peer_id="<<peer_id
1723 <<" has apparently closed connection. "
1724 <<"Removing player."<<std::endl;
1726 m_env->removePlayer(peer_id);*/
1730 void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
1732 DSTACK(__FUNCTION_NAME);
1733 // Environment is locked first.
1734 JMutexAutoLock envlock(m_env_mutex);
1735 JMutexAutoLock conlock(m_con_mutex);
1737 ScopeProfiler sp(g_profiler, "Server::ProcessData");
1740 Address address = m_con.GetPeerAddress(peer_id);
1741 std::string addr_s = address.serializeString();
1743 // drop player if is ip is banned
1744 if(m_banmanager.isIpBanned(addr_s)){
1745 infostream<<"Server: A banned client tried to connect from "
1746 <<addr_s<<"; banned name was "
1747 <<m_banmanager.getBanName(addr_s)<<std::endl;
1748 // This actually doesn't seem to transfer to the client
1749 SendAccessDenied(m_con, peer_id,
1750 L"Your ip is banned. Banned name was "
1751 +narrow_to_wide(m_banmanager.getBanName(addr_s)));
1752 m_con.DeletePeer(peer_id);
1756 catch(con::PeerNotFoundException &e)
1758 infostream<<"Server::ProcessData(): Cancelling: peer "
1759 <<peer_id<<" not found"<<std::endl;
1763 std::string addr_s = m_con.GetPeerAddress(peer_id).serializeString();
1765 u8 peer_ser_ver = getClient(peer_id)->serialization_version;
1773 ToServerCommand command = (ToServerCommand)readU16(&data[0]);
1775 if(command == TOSERVER_INIT)
1777 // [0] u16 TOSERVER_INIT
1778 // [2] u8 SER_FMT_VER_HIGHEST
1779 // [3] u8[20] player_name
1780 // [23] u8[28] password <--- can be sent without this, from old versions
1782 if(datasize < 2+1+PLAYERNAME_SIZE)
1785 verbosestream<<"Server: Got TOSERVER_INIT from "
1786 <<peer_id<<std::endl;
1788 // First byte after command is maximum supported
1789 // serialization version
1790 u8 client_max = data[2];
1791 u8 our_max = SER_FMT_VER_HIGHEST;
1792 // Use the highest version supported by both
1793 u8 deployed = std::min(client_max, our_max);
1794 // If it's lower than the lowest supported, give up.
1795 if(deployed < SER_FMT_VER_LOWEST)
1796 deployed = SER_FMT_VER_INVALID;
1798 //peer->serialization_version = deployed;
1799 getClient(peer_id)->pending_serialization_version = deployed;
1801 if(deployed == SER_FMT_VER_INVALID)
1803 actionstream<<"Server: A mismatched client tried to connect from "
1804 <<addr_s<<std::endl;
1805 infostream<<"Server: Cannot negotiate "
1806 "serialization version with peer "
1807 <<peer_id<<std::endl;
1808 SendAccessDenied(m_con, peer_id, std::wstring(
1809 L"Your client's version is not supported.\n"
1810 L"Server version is ")
1811 + narrow_to_wide(VERSION_STRING) + L"."
1817 Read and check network protocol version
1820 u16 min_net_proto_version = 0;
1821 if(datasize >= 2+1+PLAYERNAME_SIZE+PASSWORD_SIZE+2)
1822 min_net_proto_version = readU16(&data[2+1+PLAYERNAME_SIZE+PASSWORD_SIZE]);
1824 // Use same version as minimum and maximum if maximum version field
1825 // doesn't exist (backwards compatibility)
1826 u16 max_net_proto_version = min_net_proto_version;
1827 if(datasize >= 2+1+PLAYERNAME_SIZE+PASSWORD_SIZE+2+2)
1828 max_net_proto_version = readU16(&data[2+1+PLAYERNAME_SIZE+PASSWORD_SIZE+2]);
1830 // Start with client's maximum version
1831 u16 net_proto_version = max_net_proto_version;
1833 // Figure out a working version if it is possible at all
1834 if(max_net_proto_version >= SERVER_PROTOCOL_VERSION_MIN ||
1835 min_net_proto_version <= SERVER_PROTOCOL_VERSION_MAX)
1837 // If maximum is larger than our maximum, go with our maximum
1838 if(max_net_proto_version > SERVER_PROTOCOL_VERSION_MAX)
1839 net_proto_version = SERVER_PROTOCOL_VERSION_MAX;
1840 // Else go with client's maximum
1842 net_proto_version = max_net_proto_version;
1845 verbosestream<<"Server: "<<peer_id<<" Protocol version: min: "
1846 <<min_net_proto_version<<", max: "<<max_net_proto_version
1847 <<", chosen: "<<net_proto_version<<std::endl;
1849 getClient(peer_id)->net_proto_version = net_proto_version;
1851 if(net_proto_version < SERVER_PROTOCOL_VERSION_MIN ||
1852 net_proto_version > SERVER_PROTOCOL_VERSION_MAX)
1854 actionstream<<"Server: A mismatched client tried to connect from "<<addr_s
1856 SendAccessDenied(m_con, peer_id, std::wstring(
1857 L"Your client's version is not supported.\n"
1858 L"Server version is ")
1859 + narrow_to_wide(VERSION_STRING) + L",\n"
1860 + L"server's PROTOCOL_VERSION is "
1861 + narrow_to_wide(itos(SERVER_PROTOCOL_VERSION_MIN))
1863 + narrow_to_wide(itos(SERVER_PROTOCOL_VERSION_MAX))
1864 + L", client's PROTOCOL_VERSION is "
1865 + narrow_to_wide(itos(min_net_proto_version))
1867 + narrow_to_wide(itos(max_net_proto_version))
1872 if(g_settings->getBool("strict_protocol_version_checking"))
1874 if(net_proto_version != LATEST_PROTOCOL_VERSION)
1876 actionstream<<"Server: A mismatched (strict) client tried to "
1877 <<"connect from "<<addr_s<<std::endl;
1878 SendAccessDenied(m_con, peer_id, std::wstring(
1879 L"Your client's version is not supported.\n"
1880 L"Server version is ")
1881 + narrow_to_wide(VERSION_STRING) + L",\n"
1882 + L"server's PROTOCOL_VERSION (strict) is "
1883 + narrow_to_wide(itos(LATEST_PROTOCOL_VERSION))
1884 + L", client's PROTOCOL_VERSION is "
1885 + narrow_to_wide(itos(min_net_proto_version))
1887 + narrow_to_wide(itos(max_net_proto_version))
1898 char playername[PLAYERNAME_SIZE];
1899 for(u32 i=0; i<PLAYERNAME_SIZE-1; i++)
1901 playername[i] = data[3+i];
1903 playername[PLAYERNAME_SIZE-1] = 0;
1905 if(playername[0]=='\0')
1907 actionstream<<"Server: Player with an empty name "
1908 <<"tried to connect from "<<addr_s<<std::endl;
1909 SendAccessDenied(m_con, peer_id,
1914 if(string_allowed(playername, PLAYERNAME_ALLOWED_CHARS)==false)
1916 actionstream<<"Server: Player with an invalid name "
1917 <<"tried to connect from "<<addr_s<<std::endl;
1918 SendAccessDenied(m_con, peer_id,
1919 L"Name contains unallowed characters");
1923 infostream<<"Server: New connection: \""<<playername<<"\" from "
1924 <<m_con.GetPeerAddress(peer_id).serializeString()<<std::endl;
1927 char given_password[PASSWORD_SIZE];
1928 if(datasize < 2+1+PLAYERNAME_SIZE+PASSWORD_SIZE)
1930 // old version - assume blank password
1931 given_password[0] = 0;
1935 for(u32 i=0; i<PASSWORD_SIZE-1; i++)
1937 given_password[i] = data[23+i];
1939 given_password[PASSWORD_SIZE-1] = 0;
1942 if(!base64_is_valid(given_password)){
1943 infostream<<"Server: "<<playername
1944 <<" supplied invalid password hash"<<std::endl;
1945 SendAccessDenied(m_con, peer_id, L"Invalid password hash");
1949 std::string checkpwd; // Password hash to check against
1950 bool has_auth = scriptapi_get_auth(m_lua, playername, &checkpwd, NULL);
1952 // If no authentication info exists for user, create it
1954 if(!isSingleplayer() &&
1955 g_settings->getBool("disallow_empty_password") &&
1956 std::string(given_password) == ""){
1957 SendAccessDenied(m_con, peer_id, L"Empty passwords are "
1958 L"disallowed. Set a password and try again.");
1961 std::wstring raw_default_password =
1962 narrow_to_wide(g_settings->get("default_password"));
1963 std::string initial_password =
1964 translatePassword(playername, raw_default_password);
1966 // If default_password is empty, allow any initial password
1967 if (raw_default_password.length() == 0)
1968 initial_password = given_password;
1970 scriptapi_create_auth(m_lua, playername, initial_password);
1973 has_auth = scriptapi_get_auth(m_lua, playername, &checkpwd, NULL);
1976 SendAccessDenied(m_con, peer_id, L"Not allowed to login");
1980 if(given_password != checkpwd){
1981 infostream<<"Server: peer_id="<<peer_id
1982 <<": supplied invalid password for "
1983 <<playername<<std::endl;
1984 SendAccessDenied(m_con, peer_id, L"Invalid password");
1988 // Do not allow multiple players in simple singleplayer mode.
1989 // This isn't a perfect way to do it, but will suffice for now.
1990 if(m_simple_singleplayer_mode && m_clients.size() > 1){
1991 infostream<<"Server: Not allowing another client to connect in"
1992 <<" simple singleplayer mode"<<std::endl;
1993 SendAccessDenied(m_con, peer_id,
1994 L"Running in simple singleplayer mode.");
1998 // Enforce user limit.
1999 // Don't enforce for users that have some admin right
2000 if(m_clients.size() >= g_settings->getU16("max_users") &&
2001 !checkPriv(playername, "server") &&
2002 !checkPriv(playername, "ban") &&
2003 !checkPriv(playername, "privs") &&
2004 !checkPriv(playername, "password") &&
2005 playername != g_settings->get("name"))
2007 actionstream<<"Server: "<<playername<<" tried to join, but there"
2008 <<" are already max_users="
2009 <<g_settings->getU16("max_users")<<" players."<<std::endl;
2010 SendAccessDenied(m_con, peer_id, L"Too many users.");
2015 PlayerSAO *playersao = emergePlayer(playername, peer_id);
2017 // If failed, cancel
2018 if(playersao == NULL)
2020 errorstream<<"Server: peer_id="<<peer_id
2021 <<": failed to emerge player"<<std::endl;
2026 Answer with a TOCLIENT_INIT
2029 SharedBuffer<u8> reply(2+1+6+8+4);
2030 writeU16(&reply[0], TOCLIENT_INIT);
2031 writeU8(&reply[2], deployed);
2032 writeV3S16(&reply[2+1], floatToInt(playersao->getPlayer()->getPosition()+v3f(0,BS/2,0), BS));
2033 writeU64(&reply[2+1+6], m_env->getServerMap().getSeed());
2034 writeF1000(&reply[2+1+6+8], g_settings->getFloat("dedicated_server_step"));
2037 m_con.Send(peer_id, 0, reply, true);
2041 Send complete position information
2043 SendMovePlayer(peer_id);
2048 if(command == TOSERVER_INIT2)
2050 verbosestream<<"Server: Got TOSERVER_INIT2 from "
2051 <<peer_id<<std::endl;
2053 Player *player = m_env->getPlayer(peer_id);
2055 verbosestream<<"Server: TOSERVER_INIT2: "
2056 <<"Player not found; ignoring."<<std::endl;
2060 RemoteClient *client = getClient(peer_id);
2061 client->serialization_version =
2062 getClient(peer_id)->pending_serialization_version;
2065 Send some initialization data
2068 infostream<<"Server: Sending content to "
2069 <<getPlayerName(peer_id)<<std::endl;
2071 // Send player movement settings
2072 SendMovement(m_con, peer_id);
2074 // Send item definitions
2075 SendItemDef(m_con, peer_id, m_itemdef);
2077 // Send node definitions
2078 SendNodeDef(m_con, peer_id, m_nodedef, client->net_proto_version);
2080 // Send media announcement
2081 sendMediaAnnouncement(peer_id);
2084 SendPlayerPrivileges(peer_id);
2086 // Send inventory formspec
2087 SendPlayerInventoryFormspec(peer_id);
2090 UpdateCrafting(peer_id);
2091 SendInventory(peer_id);
2094 if(g_settings->getBool("enable_damage"))
2095 SendPlayerHP(peer_id);
2097 // Send detached inventories
2098 sendDetachedInventories(peer_id);
2100 // Show death screen if necessary
2102 SendDeathscreen(m_con, peer_id, false, v3f(0,0,0));
2106 SharedBuffer<u8> data = makePacket_TOCLIENT_TIME_OF_DAY(
2107 m_env->getTimeOfDay(), g_settings->getFloat("time_speed"));
2108 m_con.Send(peer_id, 0, data, true);
2111 // Note things in chat if not in simple singleplayer mode
2112 if(!m_simple_singleplayer_mode)
2114 // Send information about server to player in chat
2115 SendChatMessage(peer_id, getStatusString());
2117 // Send information about joining in chat
2119 std::wstring name = L"unknown";
2120 Player *player = m_env->getPlayer(peer_id);
2122 name = narrow_to_wide(player->getName());
2124 std::wstring message;
2127 message += L" joined the game.";
2128 BroadcastChatMessage(message);
2132 // Warnings about protocol version can be issued here
2133 if(getClient(peer_id)->net_proto_version < LATEST_PROTOCOL_VERSION)
2135 SendChatMessage(peer_id, L"# Server: WARNING: YOUR CLIENT'S "
2136 L"VERSION MAY NOT BE FULLY COMPATIBLE WITH THIS SERVER!");
2143 std::ostringstream os(std::ios_base::binary);
2144 for(std::map<u16, RemoteClient*>::iterator
2145 i = m_clients.begin();
2146 i != m_clients.end(); ++i)
2148 RemoteClient *client = i->second;
2149 assert(client->peer_id == i->first);
2150 if(client->serialization_version == SER_FMT_VER_INVALID)
2153 Player *player = m_env->getPlayer(client->peer_id);
2156 // Get name of player
2157 os<<player->getName()<<" ";
2160 actionstream<<player->getName()<<" joins game. List of players: "
2161 <<os.str()<<std::endl;
2167 if(peer_ser_ver == SER_FMT_VER_INVALID)
2169 infostream<<"Server::ProcessData(): Cancelling: Peer"
2170 " serialization format invalid or not initialized."
2171 " Skipping incoming command="<<command<<std::endl;
2175 Player *player = m_env->getPlayer(peer_id);
2177 infostream<<"Server::ProcessData(): Cancelling: "
2178 "No player for peer_id="<<peer_id
2183 PlayerSAO *playersao = player->getPlayerSAO();
2184 if(playersao == NULL){
2185 infostream<<"Server::ProcessData(): Cancelling: "
2186 "No player object for peer_id="<<peer_id
2191 if(command == TOSERVER_PLAYERPOS)
2193 if(datasize < 2+12+12+4+4)
2197 v3s32 ps = readV3S32(&data[start+2]);
2198 v3s32 ss = readV3S32(&data[start+2+12]);
2199 f32 pitch = (f32)readS32(&data[2+12+12]) / 100.0;
2200 f32 yaw = (f32)readS32(&data[2+12+12+4]) / 100.0;
2202 if(datasize >= 2+12+12+4+4+4)
2203 keyPressed = (u32)readU32(&data[2+12+12+4+4]);
2204 v3f position((f32)ps.X/100., (f32)ps.Y/100., (f32)ps.Z/100.);
2205 v3f speed((f32)ss.X/100., (f32)ss.Y/100., (f32)ss.Z/100.);
2206 pitch = wrapDegrees(pitch);
2207 yaw = wrapDegrees(yaw);
2209 player->setPosition(position);
2210 player->setSpeed(speed);
2211 player->setPitch(pitch);
2212 player->setYaw(yaw);
2213 player->keyPressed=keyPressed;
2214 player->control.up = (bool)(keyPressed&1);
2215 player->control.down = (bool)(keyPressed&2);
2216 player->control.left = (bool)(keyPressed&4);
2217 player->control.right = (bool)(keyPressed&8);
2218 player->control.jump = (bool)(keyPressed&16);
2219 player->control.aux1 = (bool)(keyPressed&32);
2220 player->control.sneak = (bool)(keyPressed&64);
2221 player->control.LMB = (bool)(keyPressed&128);
2222 player->control.RMB = (bool)(keyPressed&256);
2224 /*infostream<<"Server::ProcessData(): Moved player "<<peer_id<<" to "
2225 <<"("<<position.X<<","<<position.Y<<","<<position.Z<<")"
2226 <<" pitch="<<pitch<<" yaw="<<yaw<<std::endl;*/
2228 else if(command == TOSERVER_GOTBLOCKS)
2241 u16 count = data[2];
2242 for(u16 i=0; i<count; i++)
2244 if((s16)datasize < 2+1+(i+1)*6)
2245 throw con::InvalidIncomingDataException
2246 ("GOTBLOCKS length is too short");
2247 v3s16 p = readV3S16(&data[2+1+i*6]);
2248 /*infostream<<"Server: GOTBLOCKS ("
2249 <<p.X<<","<<p.Y<<","<<p.Z<<")"<<std::endl;*/
2250 RemoteClient *client = getClient(peer_id);
2251 client->GotBlock(p);
2254 else if(command == TOSERVER_DELETEDBLOCKS)
2267 u16 count = data[2];
2268 for(u16 i=0; i<count; i++)
2270 if((s16)datasize < 2+1+(i+1)*6)
2271 throw con::InvalidIncomingDataException
2272 ("DELETEDBLOCKS length is too short");
2273 v3s16 p = readV3S16(&data[2+1+i*6]);
2274 /*infostream<<"Server: DELETEDBLOCKS ("
2275 <<p.X<<","<<p.Y<<","<<p.Z<<")"<<std::endl;*/
2276 RemoteClient *client = getClient(peer_id);
2277 client->SetBlockNotSent(p);
2280 else if(command == TOSERVER_CLICK_OBJECT)
2282 infostream<<"Server: CLICK_OBJECT not supported anymore"<<std::endl;
2285 else if(command == TOSERVER_CLICK_ACTIVEOBJECT)
2287 infostream<<"Server: CLICK_ACTIVEOBJECT not supported anymore"<<std::endl;
2290 else if(command == TOSERVER_GROUND_ACTION)
2292 infostream<<"Server: GROUND_ACTION not supported anymore"<<std::endl;
2296 else if(command == TOSERVER_RELEASE)
2298 infostream<<"Server: RELEASE not supported anymore"<<std::endl;
2301 else if(command == TOSERVER_SIGNTEXT)
2303 infostream<<"Server: SIGNTEXT not supported anymore"
2307 else if(command == TOSERVER_SIGNNODETEXT)
2309 infostream<<"Server: SIGNNODETEXT not supported anymore"
2313 else if(command == TOSERVER_INVENTORY_ACTION)
2315 // Strip command and create a stream
2316 std::string datastring((char*)&data[2], datasize-2);
2317 verbosestream<<"TOSERVER_INVENTORY_ACTION: data="<<datastring<<std::endl;
2318 std::istringstream is(datastring, std::ios_base::binary);
2320 InventoryAction *a = InventoryAction::deSerialize(is);
2323 infostream<<"TOSERVER_INVENTORY_ACTION: "
2324 <<"InventoryAction::deSerialize() returned NULL"
2329 // If something goes wrong, this player is to blame
2330 RollbackScopeActor rollback_scope(m_rollback,
2331 std::string("player:")+player->getName());
2334 Note: Always set inventory not sent, to repair cases
2335 where the client made a bad prediction.
2339 Handle restrictions and special cases of the move action
2341 if(a->getType() == IACTION_MOVE)
2343 IMoveAction *ma = (IMoveAction*)a;
2345 ma->from_inv.applyCurrentPlayer(player->getName());
2346 ma->to_inv.applyCurrentPlayer(player->getName());
2348 setInventoryModified(ma->from_inv);
2349 setInventoryModified(ma->to_inv);
2351 bool from_inv_is_current_player =
2352 (ma->from_inv.type == InventoryLocation::PLAYER) &&
2353 (ma->from_inv.name == player->getName());
2355 bool to_inv_is_current_player =
2356 (ma->to_inv.type == InventoryLocation::PLAYER) &&
2357 (ma->to_inv.name == player->getName());
2360 Disable moving items out of craftpreview
2362 if(ma->from_list == "craftpreview")
2364 infostream<<"Ignoring IMoveAction from "
2365 <<(ma->from_inv.dump())<<":"<<ma->from_list
2366 <<" to "<<(ma->to_inv.dump())<<":"<<ma->to_list
2367 <<" because src is "<<ma->from_list<<std::endl;
2373 Disable moving items into craftresult and craftpreview
2375 if(ma->to_list == "craftpreview" || ma->to_list == "craftresult")
2377 infostream<<"Ignoring IMoveAction from "
2378 <<(ma->from_inv.dump())<<":"<<ma->from_list
2379 <<" to "<<(ma->to_inv.dump())<<":"<<ma->to_list
2380 <<" because dst is "<<ma->to_list<<std::endl;
2385 // Disallow moving items in elsewhere than player's inventory
2386 // if not allowed to interact
2387 if(!checkPriv(player->getName(), "interact") &&
2388 (!from_inv_is_current_player ||
2389 !to_inv_is_current_player))
2391 infostream<<"Cannot move outside of player's inventory: "
2392 <<"No interact privilege"<<std::endl;
2398 Handle restrictions and special cases of the drop action
2400 else if(a->getType() == IACTION_DROP)
2402 IDropAction *da = (IDropAction*)a;
2404 da->from_inv.applyCurrentPlayer(player->getName());
2406 setInventoryModified(da->from_inv);
2408 // Disallow dropping items if not allowed to interact
2409 if(!checkPriv(player->getName(), "interact"))
2416 Handle restrictions and special cases of the craft action
2418 else if(a->getType() == IACTION_CRAFT)
2420 ICraftAction *ca = (ICraftAction*)a;
2422 ca->craft_inv.applyCurrentPlayer(player->getName());
2424 setInventoryModified(ca->craft_inv);
2426 //bool craft_inv_is_current_player =
2427 // (ca->craft_inv.type == InventoryLocation::PLAYER) &&
2428 // (ca->craft_inv.name == player->getName());
2430 // Disallow crafting if not allowed to interact
2431 if(!checkPriv(player->getName(), "interact"))
2433 infostream<<"Cannot craft: "
2434 <<"No interact privilege"<<std::endl;
2441 a->apply(this, playersao, this);
2445 else if(command == TOSERVER_CHAT_MESSAGE)
2453 std::string datastring((char*)&data[2], datasize-2);
2454 std::istringstream is(datastring, std::ios_base::binary);
2457 is.read((char*)buf, 2);
2458 u16 len = readU16(buf);
2460 std::wstring message;
2461 for(u16 i=0; i<len; i++)
2463 is.read((char*)buf, 2);
2464 message += (wchar_t)readU16(buf);
2467 // If something goes wrong, this player is to blame
2468 RollbackScopeActor rollback_scope(m_rollback,
2469 std::string("player:")+player->getName());
2471 // Get player name of this client
2472 std::wstring name = narrow_to_wide(player->getName());
2475 bool ate = scriptapi_on_chat_message(m_lua, player->getName(),
2476 wide_to_narrow(message));
2477 // If script ate the message, don't proceed
2481 // Line to send to players
2483 // Whether to send to the player that sent the line
2484 bool send_to_sender = false;
2485 // Whether to send to other players
2486 bool send_to_others = false;
2488 // Commands are implemented in Lua, so only catch invalid
2489 // commands that were not "eaten" and send an error back
2490 if(message[0] == L'/')
2492 message = message.substr(1);
2493 send_to_sender = true;
2494 if(message.length() == 0)
2495 line += L"-!- Empty command";
2497 line += L"-!- Invalid command: " + str_split(message, L' ')[0];
2501 if(checkPriv(player->getName(), "shout")){
2506 send_to_others = true;
2508 line += L"-!- You don't have permission to shout.";
2509 send_to_sender = true;
2516 actionstream<<"CHAT: "<<wide_to_narrow(line)<<std::endl;
2519 Send the message to clients
2521 for(std::map<u16, RemoteClient*>::iterator
2522 i = m_clients.begin();
2523 i != m_clients.end(); ++i)
2525 // Get client and check that it is valid
2526 RemoteClient *client = i->second;
2527 assert(client->peer_id == i->first);
2528 if(client->serialization_version == SER_FMT_VER_INVALID)
2532 bool sender_selected = (peer_id == client->peer_id);
2533 if(sender_selected == true && send_to_sender == false)
2535 if(sender_selected == false && send_to_others == false)
2538 SendChatMessage(client->peer_id, line);
2542 else if(command == TOSERVER_DAMAGE)
2544 std::string datastring((char*)&data[2], datasize-2);
2545 std::istringstream is(datastring, std::ios_base::binary);
2546 u8 damage = readU8(is);
2548 if(g_settings->getBool("enable_damage"))
2550 actionstream<<player->getName()<<" damaged by "
2551 <<(int)damage<<" hp at "<<PP(player->getPosition()/BS)
2554 playersao->setHP(playersao->getHP() - damage);
2556 if(playersao->getHP() == 0 && playersao->m_hp_not_sent)
2559 if(playersao->m_hp_not_sent)
2560 SendPlayerHP(peer_id);
2563 else if(command == TOSERVER_PASSWORD)
2566 [0] u16 TOSERVER_PASSWORD
2567 [2] u8[28] old password
2568 [30] u8[28] new password
2571 if(datasize != 2+PASSWORD_SIZE*2)
2573 /*char password[PASSWORD_SIZE];
2574 for(u32 i=0; i<PASSWORD_SIZE-1; i++)
2575 password[i] = data[2+i];
2576 password[PASSWORD_SIZE-1] = 0;*/
2578 for(u32 i=0; i<PASSWORD_SIZE-1; i++)
2586 for(u32 i=0; i<PASSWORD_SIZE-1; i++)
2588 char c = data[2+PASSWORD_SIZE+i];
2594 if(!base64_is_valid(newpwd)){
2595 infostream<<"Server: "<<player->getName()<<" supplied invalid password hash"<<std::endl;
2596 // Wrong old password supplied!!
2597 SendChatMessage(peer_id, L"Invalid new password hash supplied. Password NOT changed.");
2601 infostream<<"Server: Client requests a password change from "
2602 <<"'"<<oldpwd<<"' to '"<<newpwd<<"'"<<std::endl;
2604 std::string playername = player->getName();
2606 std::string checkpwd;
2607 scriptapi_get_auth(m_lua, playername, &checkpwd, NULL);
2609 if(oldpwd != checkpwd)
2611 infostream<<"Server: invalid old password"<<std::endl;
2612 // Wrong old password supplied!!
2613 SendChatMessage(peer_id, L"Invalid old password supplied. Password NOT changed.");
2617 bool success = scriptapi_set_password(m_lua, playername, newpwd);
2619 actionstream<<player->getName()<<" changes password"<<std::endl;
2620 SendChatMessage(peer_id, L"Password change successful.");
2622 actionstream<<player->getName()<<" tries to change password but "
2623 <<"it fails"<<std::endl;
2624 SendChatMessage(peer_id, L"Password change failed or inavailable.");
2627 else if(command == TOSERVER_PLAYERITEM)
2632 u16 item = readU16(&data[2]);
2633 playersao->setWieldIndex(item);
2635 else if(command == TOSERVER_RESPAWN)
2637 if(player->hp != 0 || !g_settings->getBool("enable_damage"))
2640 RespawnPlayer(peer_id);
2642 actionstream<<player->getName()<<" respawns at "
2643 <<PP(player->getPosition()/BS)<<std::endl;
2645 // ActiveObject is added to environment in AsyncRunStep after
2646 // the previous addition has been succesfully removed
2648 else if(command == TOSERVER_REQUEST_MEDIA) {
2649 std::string datastring((char*)&data[2], datasize-2);
2650 std::istringstream is(datastring, std::ios_base::binary);
2652 std::list<MediaRequest> tosend;
2653 u16 numfiles = readU16(is);
2655 infostream<<"Sending "<<numfiles<<" files to "
2656 <<getPlayerName(peer_id)<<std::endl;
2657 verbosestream<<"TOSERVER_REQUEST_MEDIA: "<<std::endl;
2659 for(int i = 0; i < numfiles; i++) {
2660 std::string name = deSerializeString(is);
2661 tosend.push_back(MediaRequest(name));
2662 verbosestream<<"TOSERVER_REQUEST_MEDIA: requested file "
2666 sendRequestedMedia(peer_id, tosend);
2668 // Now the client should know about everything
2669 // (definitions and files)
2670 getClient(peer_id)->definitions_sent = true;
2672 else if(command == TOSERVER_RECEIVED_MEDIA) {
2673 getClient(peer_id)->definitions_sent = true;
2675 else if(command == TOSERVER_INTERACT)
2677 std::string datastring((char*)&data[2], datasize-2);
2678 std::istringstream is(datastring, std::ios_base::binary);
2684 [5] u32 length of the next item
2685 [9] serialized PointedThing
2687 0: start digging (from undersurface) or use
2688 1: stop digging (all parameters ignored)
2689 2: digging completed
2690 3: place block or item (to abovesurface)
2693 u8 action = readU8(is);
2694 u16 item_i = readU16(is);
2695 std::istringstream tmp_is(deSerializeLongString(is), std::ios::binary);
2696 PointedThing pointed;
2697 pointed.deSerialize(tmp_is);
2699 verbosestream<<"TOSERVER_INTERACT: action="<<(int)action<<", item="
2700 <<item_i<<", pointed="<<pointed.dump()<<std::endl;
2704 verbosestream<<"TOSERVER_INTERACT: "<<player->getName()
2705 <<" tried to interact, but is dead!"<<std::endl;
2709 v3f player_pos = playersao->getLastGoodPosition();
2711 // Update wielded item
2712 playersao->setWieldIndex(item_i);
2714 // Get pointed to node (undefined if not POINTEDTYPE_NODE)
2715 v3s16 p_under = pointed.node_undersurface;
2716 v3s16 p_above = pointed.node_abovesurface;
2718 // Get pointed to object (NULL if not POINTEDTYPE_OBJECT)
2719 ServerActiveObject *pointed_object = NULL;
2720 if(pointed.type == POINTEDTHING_OBJECT)
2722 pointed_object = m_env->getActiveObject(pointed.object_id);
2723 if(pointed_object == NULL)
2725 verbosestream<<"TOSERVER_INTERACT: "
2726 "pointed object is NULL"<<std::endl;
2732 v3f pointed_pos_under = player_pos;
2733 v3f pointed_pos_above = player_pos;
2734 if(pointed.type == POINTEDTHING_NODE)
2736 pointed_pos_under = intToFloat(p_under, BS);
2737 pointed_pos_above = intToFloat(p_above, BS);
2739 else if(pointed.type == POINTEDTHING_OBJECT)
2741 pointed_pos_under = pointed_object->getBasePosition();
2742 pointed_pos_above = pointed_pos_under;
2746 Check that target is reasonably close
2747 (only when digging or placing things)
2749 if(action == 0 || action == 2 || action == 3)
2751 float d = player_pos.getDistanceFrom(pointed_pos_under);
2752 float max_d = BS * 14; // Just some large enough value
2754 actionstream<<"Player "<<player->getName()
2755 <<" tried to access "<<pointed.dump()
2757 <<"d="<<d<<", max_d="<<max_d
2758 <<". ignoring."<<std::endl;
2759 // Re-send block to revert change on client-side
2760 RemoteClient *client = getClient(peer_id);
2761 v3s16 blockpos = getNodeBlockPos(floatToInt(pointed_pos_under, BS));
2762 client->SetBlockNotSent(blockpos);
2769 Make sure the player is allowed to do it
2771 if(!checkPriv(player->getName(), "interact"))
2773 actionstream<<player->getName()<<" attempted to interact with "
2774 <<pointed.dump()<<" without 'interact' privilege"
2776 // Re-send block to revert change on client-side
2777 RemoteClient *client = getClient(peer_id);
2778 // Digging completed -> under
2780 v3s16 blockpos = getNodeBlockPos(floatToInt(pointed_pos_under, BS));
2781 client->SetBlockNotSent(blockpos);
2783 // Placement -> above
2785 v3s16 blockpos = getNodeBlockPos(floatToInt(pointed_pos_above, BS));
2786 client->SetBlockNotSent(blockpos);
2792 If something goes wrong, this player is to blame
2794 RollbackScopeActor rollback_scope(m_rollback,
2795 std::string("player:")+player->getName());
2798 0: start digging or punch object
2802 if(pointed.type == POINTEDTHING_NODE)
2805 NOTE: This can be used in the future to check if
2806 somebody is cheating, by checking the timing.
2808 MapNode n(CONTENT_IGNORE);
2811 n = m_env->getMap().getNode(p_under);
2813 catch(InvalidPositionException &e)
2815 infostream<<"Server: Not punching: Node not found."
2816 <<" Adding block to emerge queue."
2818 m_emerge->enqueueBlockEmerge(peer_id, getNodeBlockPos(p_above), false);
2820 if(n.getContent() != CONTENT_IGNORE)
2821 scriptapi_node_on_punch(m_lua, p_under, n, playersao);
2823 playersao->noCheatDigStart(p_under);
2825 else if(pointed.type == POINTEDTHING_OBJECT)
2827 // Skip if object has been removed
2828 if(pointed_object->m_removed)
2831 actionstream<<player->getName()<<" punches object "
2832 <<pointed.object_id<<": "
2833 <<pointed_object->getDescription()<<std::endl;
2835 ItemStack punchitem = playersao->getWieldedItem();
2836 ToolCapabilities toolcap =
2837 punchitem.getToolCapabilities(m_itemdef);
2838 v3f dir = (pointed_object->getBasePosition() -
2839 (player->getPosition() + player->getEyeOffset())
2841 float time_from_last_punch =
2842 playersao->resetTimeFromLastPunch();
2843 pointed_object->punch(dir, &toolcap, playersao,
2844 time_from_last_punch);
2852 else if(action == 1)
2857 2: Digging completed
2859 else if(action == 2)
2861 // Only digging of nodes
2862 if(pointed.type == POINTEDTHING_NODE)
2864 MapNode n(CONTENT_IGNORE);
2867 n = m_env->getMap().getNode(p_under);
2869 catch(InvalidPositionException &e)
2871 infostream<<"Server: Not finishing digging: Node not found."
2872 <<" Adding block to emerge queue."
2874 m_emerge->enqueueBlockEmerge(peer_id, getNodeBlockPos(p_above), false);
2877 /* Cheat prevention */
2878 bool is_valid_dig = true;
2879 if(!isSingleplayer() && !g_settings->getBool("disable_anticheat"))
2881 v3s16 nocheat_p = playersao->getNoCheatDigPos();
2882 float nocheat_t = playersao->getNoCheatDigTime();
2883 playersao->noCheatDigEnd();
2884 // If player didn't start digging this, ignore dig
2885 if(nocheat_p != p_under){
2886 infostream<<"Server: NoCheat: "<<player->getName()
2887 <<" started digging "
2888 <<PP(nocheat_p)<<" and completed digging "
2889 <<PP(p_under)<<"; not digging."<<std::endl;
2890 is_valid_dig = false;
2892 // Get player's wielded item
2893 ItemStack playeritem;
2894 InventoryList *mlist = playersao->getInventory()->getList("main");
2896 playeritem = mlist->getItem(playersao->getWieldIndex());
2897 ToolCapabilities playeritem_toolcap =
2898 playeritem.getToolCapabilities(m_itemdef);
2899 // Get diggability and expected digging time
2900 DigParams params = getDigParams(m_nodedef->get(n).groups,
2901 &playeritem_toolcap);
2902 // If can't dig, try hand
2903 if(!params.diggable){
2904 const ItemDefinition &hand = m_itemdef->get("");
2905 const ToolCapabilities *tp = hand.tool_capabilities;
2907 params = getDigParams(m_nodedef->get(n).groups, tp);
2909 // If can't dig, ignore dig
2910 if(!params.diggable){
2911 infostream<<"Server: NoCheat: "<<player->getName()
2912 <<" completed digging "<<PP(p_under)
2913 <<", which is not diggable with tool. not digging."
2915 is_valid_dig = false;
2917 // If time is considerably too short, ignore dig
2918 // Check time only for medium and slow timed digs
2919 if(params.diggable && params.time > 0.3 && nocheat_t < 0.5 * params.time){
2920 infostream<<"Server: NoCheat: "<<player->getName()
2921 <<" completed digging "
2922 <<PP(p_under)<<" in "<<nocheat_t<<"s; expected "
2923 <<params.time<<"s; not digging."<<std::endl;
2924 is_valid_dig = false;
2928 /* Actually dig node */
2930 if(is_valid_dig && n.getContent() != CONTENT_IGNORE)
2931 scriptapi_node_on_dig(m_lua, p_under, n, playersao);
2933 // Send unusual result (that is, node not being removed)
2934 if(m_env->getMap().getNodeNoEx(p_under).getContent() != CONTENT_AIR)
2936 // Re-send block to revert change on client-side
2937 RemoteClient *client = getClient(peer_id);
2938 v3s16 blockpos = getNodeBlockPos(floatToInt(pointed_pos_under, BS));
2939 client->SetBlockNotSent(blockpos);
2945 3: place block or right-click object
2947 else if(action == 3)
2949 ItemStack item = playersao->getWieldedItem();
2951 // Reset build time counter
2952 if(pointed.type == POINTEDTHING_NODE &&
2953 item.getDefinition(m_itemdef).type == ITEM_NODE)
2954 getClient(peer_id)->m_time_from_building = 0.0;
2956 if(pointed.type == POINTEDTHING_OBJECT)
2958 // Right click object
2960 // Skip if object has been removed
2961 if(pointed_object->m_removed)
2964 actionstream<<player->getName()<<" right-clicks object "
2965 <<pointed.object_id<<": "
2966 <<pointed_object->getDescription()<<std::endl;
2969 pointed_object->rightClick(playersao);
2971 else if(scriptapi_item_on_place(m_lua,
2972 item, playersao, pointed))
2974 // Placement was handled in lua
2976 // Apply returned ItemStack
2977 playersao->setWieldedItem(item);
2980 // If item has node placement prediction, always send the above
2981 // node to make sure the client knows what exactly happened
2982 if(item.getDefinition(m_itemdef).node_placement_prediction != ""){
2983 RemoteClient *client = getClient(peer_id);
2984 v3s16 blockpos = getNodeBlockPos(floatToInt(pointed_pos_above, BS));
2985 client->SetBlockNotSent(blockpos);
2992 else if(action == 4)
2994 ItemStack item = playersao->getWieldedItem();
2996 actionstream<<player->getName()<<" uses "<<item.name
2997 <<", pointing at "<<pointed.dump()<<std::endl;
2999 if(scriptapi_item_on_use(m_lua,
3000 item, playersao, pointed))
3002 // Apply returned ItemStack
3003 playersao->setWieldedItem(item);
3010 Catch invalid actions
3014 infostream<<"WARNING: Server: Invalid action "
3015 <<action<<std::endl;
3018 else if(command == TOSERVER_REMOVED_SOUNDS)
3020 std::string datastring((char*)&data[2], datasize-2);
3021 std::istringstream is(datastring, std::ios_base::binary);
3023 int num = readU16(is);
3024 for(int k=0; k<num; k++){
3025 s32 id = readS32(is);
3026 std::map<s32, ServerPlayingSound>::iterator i =
3027 m_playing_sounds.find(id);
3028 if(i == m_playing_sounds.end())
3030 ServerPlayingSound &psound = i->second;
3031 psound.clients.erase(peer_id);
3032 if(psound.clients.size() == 0)
3033 m_playing_sounds.erase(i++);
3036 else if(command == TOSERVER_NODEMETA_FIELDS)
3038 std::string datastring((char*)&data[2], datasize-2);
3039 std::istringstream is(datastring, std::ios_base::binary);
3041 v3s16 p = readV3S16(is);
3042 std::string formname = deSerializeString(is);
3043 int num = readU16(is);
3044 std::map<std::string, std::string> fields;
3045 for(int k=0; k<num; k++){
3046 std::string fieldname = deSerializeString(is);
3047 std::string fieldvalue = deSerializeLongString(is);
3048 fields[fieldname] = fieldvalue;
3051 // If something goes wrong, this player is to blame
3052 RollbackScopeActor rollback_scope(m_rollback,
3053 std::string("player:")+player->getName());
3055 // Check the target node for rollback data; leave others unnoticed
3056 RollbackNode rn_old(&m_env->getMap(), p, this);
3058 scriptapi_node_on_receive_fields(m_lua, p, formname, fields,
3061 // Report rollback data
3062 RollbackNode rn_new(&m_env->getMap(), p, this);
3063 if(rollback() && rn_new != rn_old){
3064 RollbackAction action;
3065 action.setSetNode(p, rn_old, rn_new);
3066 rollback()->reportAction(action);
3069 else if(command == TOSERVER_INVENTORY_FIELDS)
3071 std::string datastring((char*)&data[2], datasize-2);
3072 std::istringstream is(datastring, std::ios_base::binary);
3074 std::string formname = deSerializeString(is);
3075 int num = readU16(is);
3076 std::map<std::string, std::string> fields;
3077 for(int k=0; k<num; k++){
3078 std::string fieldname = deSerializeString(is);
3079 std::string fieldvalue = deSerializeLongString(is);
3080 fields[fieldname] = fieldvalue;
3083 scriptapi_on_player_receive_fields(m_lua, playersao, formname, fields);
3087 infostream<<"Server::ProcessData(): Ignoring "
3088 "unknown command "<<command<<std::endl;
3092 catch(SendFailedException &e)
3094 errorstream<<"Server::ProcessData(): SendFailedException: "
3100 void Server::onMapEditEvent(MapEditEvent *event)
3102 //infostream<<"Server::onMapEditEvent()"<<std::endl;
3103 if(m_ignore_map_edit_events)
3105 if(m_ignore_map_edit_events_area.contains(event->getArea()))
3107 MapEditEvent *e = event->clone();
3108 m_unsent_map_edit_queue.push_back(e);
3111 Inventory* Server::getInventory(const InventoryLocation &loc)
3114 case InventoryLocation::UNDEFINED:
3117 case InventoryLocation::CURRENT_PLAYER:
3120 case InventoryLocation::PLAYER:
3122 Player *player = m_env->getPlayer(loc.name.c_str());
3125 PlayerSAO *playersao = player->getPlayerSAO();
3128 return playersao->getInventory();
3131 case InventoryLocation::NODEMETA:
3133 NodeMetadata *meta = m_env->getMap().getNodeMetadata(loc.p);
3136 return meta->getInventory();
3139 case InventoryLocation::DETACHED:
3141 if(m_detached_inventories.count(loc.name) == 0)
3143 return m_detached_inventories[loc.name];
3151 void Server::setInventoryModified(const InventoryLocation &loc)
3154 case InventoryLocation::UNDEFINED:
3157 case InventoryLocation::PLAYER:
3159 Player *player = m_env->getPlayer(loc.name.c_str());
3162 PlayerSAO *playersao = player->getPlayerSAO();
3165 playersao->m_inventory_not_sent = true;
3166 playersao->m_wielded_item_not_sent = true;
3169 case InventoryLocation::NODEMETA:
3171 v3s16 blockpos = getNodeBlockPos(loc.p);
3173 MapBlock *block = m_env->getMap().getBlockNoCreateNoEx(blockpos);
3175 block->raiseModified(MOD_STATE_WRITE_NEEDED);
3177 setBlockNotSent(blockpos);
3180 case InventoryLocation::DETACHED:
3182 sendDetachedInventoryToAll(loc.name);
3190 std::list<PlayerInfo> Server::getPlayerInfo()
3192 DSTACK(__FUNCTION_NAME);
3193 JMutexAutoLock envlock(m_env_mutex);
3194 JMutexAutoLock conlock(m_con_mutex);
3196 std::list<PlayerInfo> list;
3198 std::list<Player*> players = m_env->getPlayers();
3200 std::list<Player*>::iterator i;
3201 for(i = players.begin();
3202 i != players.end(); ++i)
3206 Player *player = *i;
3209 // Copy info from connection to info struct
3210 info.id = player->peer_id;
3211 info.address = m_con.GetPeerAddress(player->peer_id);
3212 info.avg_rtt = m_con.GetPeerAvgRTT(player->peer_id);
3214 catch(con::PeerNotFoundException &e)
3216 // Set dummy peer info
3218 info.address = Address(0,0,0,0,0);
3222 snprintf(info.name, PLAYERNAME_SIZE, "%s", player->getName());
3223 info.position = player->getPosition();
3225 list.push_back(info);
3232 void Server::peerAdded(con::Peer *peer)
3234 DSTACK(__FUNCTION_NAME);
3235 verbosestream<<"Server::peerAdded(): peer->id="
3236 <<peer->id<<std::endl;
3239 c.type = PEER_ADDED;
3240 c.peer_id = peer->id;
3242 m_peer_change_queue.push_back(c);
3245 void Server::deletingPeer(con::Peer *peer, bool timeout)
3247 DSTACK(__FUNCTION_NAME);
3248 verbosestream<<"Server::deletingPeer(): peer->id="
3249 <<peer->id<<", timeout="<<timeout<<std::endl;
3252 c.type = PEER_REMOVED;
3253 c.peer_id = peer->id;
3254 c.timeout = timeout;
3255 m_peer_change_queue.push_back(c);
3262 void Server::SendMovement(con::Connection &con, u16 peer_id)
3264 DSTACK(__FUNCTION_NAME);
3265 std::ostringstream os(std::ios_base::binary);
3267 writeU16(os, TOCLIENT_MOVEMENT);
3268 writeF1000(os, g_settings->getFloat("movement_acceleration_default"));
3269 writeF1000(os, g_settings->getFloat("movement_acceleration_air"));
3270 writeF1000(os, g_settings->getFloat("movement_acceleration_fast"));
3271 writeF1000(os, g_settings->getFloat("movement_speed_walk"));
3272 writeF1000(os, g_settings->getFloat("movement_speed_crouch"));
3273 writeF1000(os, g_settings->getFloat("movement_speed_fast"));
3274 writeF1000(os, g_settings->getFloat("movement_speed_climb"));
3275 writeF1000(os, g_settings->getFloat("movement_speed_jump"));
3276 writeF1000(os, g_settings->getFloat("movement_liquid_fluidity"));
3277 writeF1000(os, g_settings->getFloat("movement_liquid_fluidity_smooth"));
3278 writeF1000(os, g_settings->getFloat("movement_liquid_sink"));
3279 writeF1000(os, g_settings->getFloat("movement_gravity"));
3282 std::string s = os.str();
3283 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3285 con.Send(peer_id, 0, data, true);
3288 void Server::SendHP(con::Connection &con, u16 peer_id, u8 hp)
3290 DSTACK(__FUNCTION_NAME);
3291 std::ostringstream os(std::ios_base::binary);
3293 writeU16(os, TOCLIENT_HP);
3297 std::string s = os.str();
3298 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3300 con.Send(peer_id, 0, data, true);
3303 void Server::SendAccessDenied(con::Connection &con, u16 peer_id,
3304 const std::wstring &reason)
3306 DSTACK(__FUNCTION_NAME);
3307 std::ostringstream os(std::ios_base::binary);
3309 writeU16(os, TOCLIENT_ACCESS_DENIED);
3310 os<<serializeWideString(reason);
3313 std::string s = os.str();
3314 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3316 con.Send(peer_id, 0, data, true);
3319 void Server::SendDeathscreen(con::Connection &con, u16 peer_id,
3320 bool set_camera_point_target, v3f camera_point_target)
3322 DSTACK(__FUNCTION_NAME);
3323 std::ostringstream os(std::ios_base::binary);
3325 writeU16(os, TOCLIENT_DEATHSCREEN);
3326 writeU8(os, set_camera_point_target);
3327 writeV3F1000(os, camera_point_target);
3330 std::string s = os.str();
3331 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3333 con.Send(peer_id, 0, data, true);
3336 void Server::SendItemDef(con::Connection &con, u16 peer_id,
3337 IItemDefManager *itemdef)
3339 DSTACK(__FUNCTION_NAME);
3340 std::ostringstream os(std::ios_base::binary);
3344 u32 length of the next item
3345 zlib-compressed serialized ItemDefManager
3347 writeU16(os, TOCLIENT_ITEMDEF);
3348 std::ostringstream tmp_os(std::ios::binary);
3349 itemdef->serialize(tmp_os);
3350 std::ostringstream tmp_os2(std::ios::binary);
3351 compressZlib(tmp_os.str(), tmp_os2);
3352 os<<serializeLongString(tmp_os2.str());
3355 std::string s = os.str();
3356 verbosestream<<"Server: Sending item definitions to id("<<peer_id
3357 <<"): size="<<s.size()<<std::endl;
3358 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3360 con.Send(peer_id, 0, data, true);
3363 void Server::SendNodeDef(con::Connection &con, u16 peer_id,
3364 INodeDefManager *nodedef, u16 protocol_version)
3366 DSTACK(__FUNCTION_NAME);
3367 std::ostringstream os(std::ios_base::binary);
3371 u32 length of the next item
3372 zlib-compressed serialized NodeDefManager
3374 writeU16(os, TOCLIENT_NODEDEF);
3375 std::ostringstream tmp_os(std::ios::binary);
3376 nodedef->serialize(tmp_os, protocol_version);
3377 std::ostringstream tmp_os2(std::ios::binary);
3378 compressZlib(tmp_os.str(), tmp_os2);
3379 os<<serializeLongString(tmp_os2.str());
3382 std::string s = os.str();
3383 verbosestream<<"Server: Sending node definitions to id("<<peer_id
3384 <<"): size="<<s.size()<<std::endl;
3385 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3387 con.Send(peer_id, 0, data, true);
3391 Non-static send methods
3394 void Server::SendInventory(u16 peer_id)
3396 DSTACK(__FUNCTION_NAME);
3398 PlayerSAO *playersao = getPlayerSAO(peer_id);
3401 playersao->m_inventory_not_sent = false;
3407 std::ostringstream os;
3408 playersao->getInventory()->serialize(os);
3410 std::string s = os.str();
3412 SharedBuffer<u8> data(s.size()+2);
3413 writeU16(&data[0], TOCLIENT_INVENTORY);
3414 memcpy(&data[2], s.c_str(), s.size());
3417 m_con.Send(peer_id, 0, data, true);
3420 void Server::SendChatMessage(u16 peer_id, const std::wstring &message)
3422 DSTACK(__FUNCTION_NAME);
3424 std::ostringstream os(std::ios_base::binary);
3428 writeU16(buf, TOCLIENT_CHAT_MESSAGE);
3429 os.write((char*)buf, 2);
3432 writeU16(buf, message.size());
3433 os.write((char*)buf, 2);
3436 for(u32 i=0; i<message.size(); i++)
3440 os.write((char*)buf, 2);
3444 std::string s = os.str();
3445 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3447 m_con.Send(peer_id, 0, data, true);
3449 void Server::SendShowFormspecMessage(u16 peer_id, const std::string formspec, const std::string formname)
3451 DSTACK(__FUNCTION_NAME);
3453 std::ostringstream os(std::ios_base::binary);
3457 writeU16(buf, TOCLIENT_SHOW_FORMSPEC);
3458 os.write((char*)buf, 2);
3459 os<<serializeLongString(formspec);
3460 os<<serializeString(formname);
3463 std::string s = os.str();
3464 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3466 m_con.Send(peer_id, 0, data, true);
3469 void Server::BroadcastChatMessage(const std::wstring &message)
3471 for(std::map<u16, RemoteClient*>::iterator
3472 i = m_clients.begin();
3473 i != m_clients.end(); ++i)
3475 // Get client and check that it is valid
3476 RemoteClient *client = i->second;
3477 assert(client->peer_id == i->first);
3478 if(client->serialization_version == SER_FMT_VER_INVALID)
3481 SendChatMessage(client->peer_id, message);
3485 void Server::SendPlayerHP(u16 peer_id)
3487 DSTACK(__FUNCTION_NAME);
3488 PlayerSAO *playersao = getPlayerSAO(peer_id);
3490 playersao->m_hp_not_sent = false;
3491 SendHP(m_con, peer_id, playersao->getHP());
3494 void Server::SendMovePlayer(u16 peer_id)
3496 DSTACK(__FUNCTION_NAME);
3497 Player *player = m_env->getPlayer(peer_id);
3500 std::ostringstream os(std::ios_base::binary);
3501 writeU16(os, TOCLIENT_MOVE_PLAYER);
3502 writeV3F1000(os, player->getPosition());
3503 writeF1000(os, player->getPitch());
3504 writeF1000(os, player->getYaw());
3507 v3f pos = player->getPosition();
3508 f32 pitch = player->getPitch();
3509 f32 yaw = player->getYaw();
3510 verbosestream<<"Server: Sending TOCLIENT_MOVE_PLAYER"
3511 <<" pos=("<<pos.X<<","<<pos.Y<<","<<pos.Z<<")"
3518 std::string s = os.str();
3519 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3521 m_con.Send(peer_id, 0, data, true);
3524 void Server::SendPlayerPrivileges(u16 peer_id)
3526 Player *player = m_env->getPlayer(peer_id);
3528 if(player->peer_id == PEER_ID_INEXISTENT)
3531 std::set<std::string> privs;
3532 scriptapi_get_auth(m_lua, player->getName(), NULL, &privs);
3534 std::ostringstream os(std::ios_base::binary);
3535 writeU16(os, TOCLIENT_PRIVILEGES);
3536 writeU16(os, privs.size());
3537 for(std::set<std::string>::const_iterator i = privs.begin();
3538 i != privs.end(); i++){
3539 os<<serializeString(*i);
3543 std::string s = os.str();
3544 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3546 m_con.Send(peer_id, 0, data, true);
3549 void Server::SendPlayerInventoryFormspec(u16 peer_id)
3551 Player *player = m_env->getPlayer(peer_id);
3553 if(player->peer_id == PEER_ID_INEXISTENT)
3556 std::ostringstream os(std::ios_base::binary);
3557 writeU16(os, TOCLIENT_INVENTORY_FORMSPEC);
3558 os<<serializeLongString(player->inventory_formspec);
3561 std::string s = os.str();
3562 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3564 m_con.Send(peer_id, 0, data, true);
3567 s32 Server::playSound(const SimpleSoundSpec &spec,
3568 const ServerSoundParams ¶ms)
3570 // Find out initial position of sound
3571 bool pos_exists = false;
3572 v3f pos = params.getPos(m_env, &pos_exists);
3573 // If position is not found while it should be, cancel sound
3574 if(pos_exists != (params.type != ServerSoundParams::SSP_LOCAL))
3576 // Filter destination clients
3577 std::set<RemoteClient*> dst_clients;
3578 if(params.to_player != "")
3580 Player *player = m_env->getPlayer(params.to_player.c_str());
3582 infostream<<"Server::playSound: Player \""<<params.to_player
3583 <<"\" not found"<<std::endl;
3586 if(player->peer_id == PEER_ID_INEXISTENT){
3587 infostream<<"Server::playSound: Player \""<<params.to_player
3588 <<"\" not connected"<<std::endl;
3591 RemoteClient *client = getClient(player->peer_id);
3592 dst_clients.insert(client);
3596 for(std::map<u16, RemoteClient*>::iterator
3597 i = m_clients.begin(); i != m_clients.end(); ++i)
3599 RemoteClient *client = i->second;
3600 Player *player = m_env->getPlayer(client->peer_id);
3604 if(player->getPosition().getDistanceFrom(pos) >
3605 params.max_hear_distance)
3608 dst_clients.insert(client);
3611 if(dst_clients.size() == 0)
3614 s32 id = m_next_sound_id++;
3615 // The sound will exist as a reference in m_playing_sounds
3616 m_playing_sounds[id] = ServerPlayingSound();
3617 ServerPlayingSound &psound = m_playing_sounds[id];
3618 psound.params = params;
3619 for(std::set<RemoteClient*>::iterator i = dst_clients.begin();
3620 i != dst_clients.end(); i++)
3621 psound.clients.insert((*i)->peer_id);
3623 std::ostringstream os(std::ios_base::binary);
3624 writeU16(os, TOCLIENT_PLAY_SOUND);
3626 os<<serializeString(spec.name);
3627 writeF1000(os, spec.gain * params.gain);
3628 writeU8(os, params.type);
3629 writeV3F1000(os, pos);
3630 writeU16(os, params.object);
3631 writeU8(os, params.loop);
3633 std::string s = os.str();
3634 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3636 for(std::set<RemoteClient*>::iterator i = dst_clients.begin();
3637 i != dst_clients.end(); i++){
3639 m_con.Send((*i)->peer_id, 0, data, true);
3643 void Server::stopSound(s32 handle)
3645 // Get sound reference
3646 std::map<s32, ServerPlayingSound>::iterator i =
3647 m_playing_sounds.find(handle);
3648 if(i == m_playing_sounds.end())
3650 ServerPlayingSound &psound = i->second;
3652 std::ostringstream os(std::ios_base::binary);
3653 writeU16(os, TOCLIENT_STOP_SOUND);
3654 writeS32(os, handle);
3656 std::string s = os.str();
3657 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3659 for(std::set<u16>::iterator i = psound.clients.begin();
3660 i != psound.clients.end(); i++){
3662 m_con.Send(*i, 0, data, true);
3664 // Remove sound reference
3665 m_playing_sounds.erase(i);
3668 void Server::sendRemoveNode(v3s16 p, u16 ignore_id,
3669 std::list<u16> *far_players, float far_d_nodes)
3671 float maxd = far_d_nodes*BS;
3672 v3f p_f = intToFloat(p, BS);
3676 SharedBuffer<u8> reply(replysize);
3677 writeU16(&reply[0], TOCLIENT_REMOVENODE);
3678 writeS16(&reply[2], p.X);
3679 writeS16(&reply[4], p.Y);
3680 writeS16(&reply[6], p.Z);
3682 for(std::map<u16, RemoteClient*>::iterator
3683 i = m_clients.begin();
3684 i != m_clients.end(); ++i)
3686 // Get client and check that it is valid
3687 RemoteClient *client = i->second;
3688 assert(client->peer_id == i->first);
3689 if(client->serialization_version == SER_FMT_VER_INVALID)
3692 // Don't send if it's the same one
3693 if(client->peer_id == ignore_id)
3699 Player *player = m_env->getPlayer(client->peer_id);
3702 // If player is far away, only set modified blocks not sent
3703 v3f player_pos = player->getPosition();
3704 if(player_pos.getDistanceFrom(p_f) > maxd)
3706 far_players->push_back(client->peer_id);
3713 m_con.Send(client->peer_id, 0, reply, true);
3717 void Server::sendAddNode(v3s16 p, MapNode n, u16 ignore_id,
3718 std::list<u16> *far_players, float far_d_nodes)
3720 float maxd = far_d_nodes*BS;
3721 v3f p_f = intToFloat(p, BS);
3723 for(std::map<u16, RemoteClient*>::iterator
3724 i = m_clients.begin();
3725 i != m_clients.end(); ++i)
3727 // Get client and check that it is valid
3728 RemoteClient *client = i->second;
3729 assert(client->peer_id == i->first);
3730 if(client->serialization_version == SER_FMT_VER_INVALID)
3733 // Don't send if it's the same one
3734 if(client->peer_id == ignore_id)
3740 Player *player = m_env->getPlayer(client->peer_id);
3743 // If player is far away, only set modified blocks not sent
3744 v3f player_pos = player->getPosition();
3745 if(player_pos.getDistanceFrom(p_f) > maxd)
3747 far_players->push_back(client->peer_id);
3754 u32 replysize = 8 + MapNode::serializedLength(client->serialization_version);
3755 SharedBuffer<u8> reply(replysize);
3756 writeU16(&reply[0], TOCLIENT_ADDNODE);
3757 writeS16(&reply[2], p.X);
3758 writeS16(&reply[4], p.Y);
3759 writeS16(&reply[6], p.Z);
3760 n.serialize(&reply[8], client->serialization_version);
3763 m_con.Send(client->peer_id, 0, reply, true);
3767 void Server::setBlockNotSent(v3s16 p)
3769 for(std::map<u16, RemoteClient*>::iterator
3770 i = m_clients.begin();
3771 i != m_clients.end(); ++i)
3773 RemoteClient *client = i->second;
3774 client->SetBlockNotSent(p);
3778 void Server::SendBlockNoLock(u16 peer_id, MapBlock *block, u8 ver)
3780 DSTACK(__FUNCTION_NAME);
3782 v3s16 p = block->getPos();
3786 bool completely_air = true;
3787 for(s16 z0=0; z0<MAP_BLOCKSIZE; z0++)
3788 for(s16 x0=0; x0<MAP_BLOCKSIZE; x0++)
3789 for(s16 y0=0; y0<MAP_BLOCKSIZE; y0++)
3791 if(block->getNodeNoEx(v3s16(x0,y0,z0)).d != CONTENT_AIR)
3793 completely_air = false;
3794 x0 = y0 = z0 = MAP_BLOCKSIZE; // Break out
3799 infostream<<"Server: Sending block ("<<p.X<<","<<p.Y<<","<<p.Z<<"): ";
3801 infostream<<"[completely air] ";
3802 infostream<<std::endl;
3806 Create a packet with the block in the right format
3809 std::ostringstream os(std::ios_base::binary);
3810 block->serialize(os, ver, false);
3811 std::string s = os.str();
3812 SharedBuffer<u8> blockdata((u8*)s.c_str(), s.size());
3814 u32 replysize = 8 + blockdata.getSize();
3815 SharedBuffer<u8> reply(replysize);
3816 writeU16(&reply[0], TOCLIENT_BLOCKDATA);
3817 writeS16(&reply[2], p.X);
3818 writeS16(&reply[4], p.Y);
3819 writeS16(&reply[6], p.Z);
3820 memcpy(&reply[8], *blockdata, blockdata.getSize());
3822 /*infostream<<"Server: Sending block ("<<p.X<<","<<p.Y<<","<<p.Z<<")"
3823 <<": \tpacket size: "<<replysize<<std::endl;*/
3828 m_con.Send(peer_id, 1, reply, true);
3831 void Server::SendBlocks(float dtime)
3833 DSTACK(__FUNCTION_NAME);
3835 JMutexAutoLock envlock(m_env_mutex);
3836 JMutexAutoLock conlock(m_con_mutex);
3838 ScopeProfiler sp(g_profiler, "Server: sel and send blocks to clients");
3840 std::vector<PrioritySortedBlockTransfer> queue;
3842 s32 total_sending = 0;
3845 ScopeProfiler sp(g_profiler, "Server: selecting blocks for sending");
3847 for(std::map<u16, RemoteClient*>::iterator
3848 i = m_clients.begin();
3849 i != m_clients.end(); ++i)
3851 RemoteClient *client = i->second;
3852 assert(client->peer_id == i->first);
3854 // If definitions and textures have not been sent, don't
3855 // send MapBlocks either
3856 if(!client->definitions_sent)
3859 total_sending += client->SendingCount();
3861 if(client->serialization_version == SER_FMT_VER_INVALID)
3864 client->GetNextBlocks(this, dtime, queue);
3869 // Lowest priority number comes first.
3870 // Lowest is most important.
3871 std::sort(queue.begin(), queue.end());
3873 for(u32 i=0; i<queue.size(); i++)
3875 //TODO: Calculate limit dynamically
3876 if(total_sending >= g_settings->getS32
3877 ("max_simultaneous_block_sends_server_total"))
3880 PrioritySortedBlockTransfer q = queue[i];
3882 MapBlock *block = NULL;
3885 block = m_env->getMap().getBlockNoCreate(q.pos);
3887 catch(InvalidPositionException &e)
3892 RemoteClient *client = getClient(q.peer_id);
3894 SendBlockNoLock(q.peer_id, block, client->serialization_version);
3896 client->SentBlock(q.pos);
3902 void Server::fillMediaCache()
3904 DSTACK(__FUNCTION_NAME);
3906 infostream<<"Server: Calculating media file checksums"<<std::endl;
3908 // Collect all media file paths
3909 std::list<std::string> paths;
3910 for(std::vector<ModSpec>::iterator i = m_mods.begin();
3911 i != m_mods.end(); i++){
3912 const ModSpec &mod = *i;
3913 paths.push_back(mod.path + DIR_DELIM + "textures");
3914 paths.push_back(mod.path + DIR_DELIM + "sounds");
3915 paths.push_back(mod.path + DIR_DELIM + "media");
3916 paths.push_back(mod.path + DIR_DELIM + "models");
3918 std::string path_all = "textures";
3919 paths.push_back(path_all + DIR_DELIM + "all");
3921 // Collect media file information from paths into cache
3922 for(std::list<std::string>::iterator i = paths.begin();
3923 i != paths.end(); i++)
3925 std::string mediapath = *i;
3926 std::vector<fs::DirListNode> dirlist = fs::GetDirListing(mediapath);
3927 for(u32 j=0; j<dirlist.size(); j++){
3928 if(dirlist[j].dir) // Ignode dirs
3930 std::string filename = dirlist[j].name;
3931 // If name contains illegal characters, ignore the file
3932 if(!string_allowed(filename, TEXTURENAME_ALLOWED_CHARS)){
3933 infostream<<"Server: ignoring illegal file name: \""
3934 <<filename<<"\""<<std::endl;
3937 // If name is not in a supported format, ignore it
3938 const char *supported_ext[] = {
3939 ".png", ".jpg", ".bmp", ".tga",
3940 ".pcx", ".ppm", ".psd", ".wal", ".rgb",
3942 ".x", ".b3d", ".md2", ".obj",
3945 if(removeStringEnd(filename, supported_ext) == ""){
3946 infostream<<"Server: ignoring unsupported file extension: \""
3947 <<filename<<"\""<<std::endl;
3950 // Ok, attempt to load the file and add to cache
3951 std::string filepath = mediapath + DIR_DELIM + filename;
3953 std::ifstream fis(filepath.c_str(), std::ios_base::binary);
3954 if(fis.good() == false){
3955 errorstream<<"Server::fillMediaCache(): Could not open \""
3956 <<filename<<"\" for reading"<<std::endl;
3959 std::ostringstream tmp_os(std::ios_base::binary);
3963 fis.read(buf, 1024);
3964 std::streamsize len = fis.gcount();
3965 tmp_os.write(buf, len);
3974 errorstream<<"Server::fillMediaCache(): Failed to read \""
3975 <<filename<<"\""<<std::endl;
3978 if(tmp_os.str().length() == 0){
3979 errorstream<<"Server::fillMediaCache(): Empty file \""
3980 <<filepath<<"\""<<std::endl;
3985 sha1.addBytes(tmp_os.str().c_str(), tmp_os.str().length());
3987 unsigned char *digest = sha1.getDigest();
3988 std::string sha1_base64 = base64_encode(digest, 20);
3989 std::string sha1_hex = hex_encode((char*)digest, 20);
3993 this->m_media[filename] = MediaInfo(filepath, sha1_base64);
3994 verbosestream<<"Server: "<<sha1_hex<<" is "<<filename<<std::endl;
3999 struct SendableMediaAnnouncement
4002 std::string sha1_digest;
4004 SendableMediaAnnouncement(const std::string name_="",
4005 const std::string sha1_digest_=""):
4007 sha1_digest(sha1_digest_)
4011 void Server::sendMediaAnnouncement(u16 peer_id)
4013 DSTACK(__FUNCTION_NAME);
4015 verbosestream<<"Server: Announcing files to id("<<peer_id<<")"
4018 std::list<SendableMediaAnnouncement> file_announcements;
4020 for(std::map<std::string, MediaInfo>::iterator i = m_media.begin();
4021 i != m_media.end(); i++){
4023 file_announcements.push_back(
4024 SendableMediaAnnouncement(i->first, i->second.sha1_digest));
4028 std::ostringstream os(std::ios_base::binary);
4036 u16 length of sha1_digest
4041 writeU16(os, TOCLIENT_ANNOUNCE_MEDIA);
4042 writeU16(os, file_announcements.size());
4044 for(std::list<SendableMediaAnnouncement>::iterator
4045 j = file_announcements.begin();
4046 j != file_announcements.end(); ++j){
4047 os<<serializeString(j->name);
4048 os<<serializeString(j->sha1_digest);
4050 os<<serializeString(g_settings->get("remote_media"));
4053 std::string s = os.str();
4054 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
4057 m_con.Send(peer_id, 0, data, true);
4060 struct SendableMedia
4066 SendableMedia(const std::string &name_="", const std::string path_="",
4067 const std::string &data_=""):
4074 void Server::sendRequestedMedia(u16 peer_id,
4075 const std::list<MediaRequest> &tosend)
4077 DSTACK(__FUNCTION_NAME);
4079 verbosestream<<"Server::sendRequestedMedia(): "
4080 <<"Sending files to client"<<std::endl;
4084 // Put 5kB in one bunch (this is not accurate)
4085 u32 bytes_per_bunch = 5000;
4087 std::vector< std::list<SendableMedia> > file_bunches;
4088 file_bunches.push_back(std::list<SendableMedia>());
4090 u32 file_size_bunch_total = 0;
4092 for(std::list<MediaRequest>::const_iterator i = tosend.begin();
4093 i != tosend.end(); ++i)
4095 if(m_media.find(i->name) == m_media.end()){
4096 errorstream<<"Server::sendRequestedMedia(): Client asked for "
4097 <<"unknown file \""<<(i->name)<<"\""<<std::endl;
4101 //TODO get path + name
4102 std::string tpath = m_media[(*i).name].path;
4105 std::ifstream fis(tpath.c_str(), std::ios_base::binary);
4106 if(fis.good() == false){
4107 errorstream<<"Server::sendRequestedMedia(): Could not open \""
4108 <<tpath<<"\" for reading"<<std::endl;
4111 std::ostringstream tmp_os(std::ios_base::binary);
4115 fis.read(buf, 1024);
4116 std::streamsize len = fis.gcount();
4117 tmp_os.write(buf, len);
4118 file_size_bunch_total += len;
4127 errorstream<<"Server::sendRequestedMedia(): Failed to read \""
4128 <<(*i).name<<"\""<<std::endl;
4131 /*infostream<<"Server::sendRequestedMedia(): Loaded \""
4132 <<tname<<"\""<<std::endl;*/
4134 file_bunches[file_bunches.size()-1].push_back(
4135 SendableMedia((*i).name, tpath, tmp_os.str()));
4137 // Start next bunch if got enough data
4138 if(file_size_bunch_total >= bytes_per_bunch){
4139 file_bunches.push_back(std::list<SendableMedia>());
4140 file_size_bunch_total = 0;
4145 /* Create and send packets */
4147 u32 num_bunches = file_bunches.size();
4148 for(u32 i=0; i<num_bunches; i++)
4150 std::ostringstream os(std::ios_base::binary);
4154 u16 total number of texture bunches
4155 u16 index of this bunch
4156 u32 number of files in this bunch
4165 writeU16(os, TOCLIENT_MEDIA);
4166 writeU16(os, num_bunches);
4168 writeU32(os, file_bunches[i].size());
4170 for(std::list<SendableMedia>::iterator
4171 j = file_bunches[i].begin();
4172 j != file_bunches[i].end(); ++j){
4173 os<<serializeString(j->name);
4174 os<<serializeLongString(j->data);
4178 std::string s = os.str();
4179 verbosestream<<"Server::sendRequestedMedia(): bunch "
4180 <<i<<"/"<<num_bunches
4181 <<" files="<<file_bunches[i].size()
4182 <<" size=" <<s.size()<<std::endl;
4183 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
4185 m_con.Send(peer_id, 0, data, true);
4189 void Server::sendDetachedInventory(const std::string &name, u16 peer_id)
4191 if(m_detached_inventories.count(name) == 0){
4192 errorstream<<__FUNCTION_NAME<<": \""<<name<<"\" not found"<<std::endl;
4195 Inventory *inv = m_detached_inventories[name];
4197 std::ostringstream os(std::ios_base::binary);
4198 writeU16(os, TOCLIENT_DETACHED_INVENTORY);
4199 os<<serializeString(name);
4203 std::string s = os.str();
4204 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
4206 m_con.Send(peer_id, 0, data, true);
4209 void Server::sendDetachedInventoryToAll(const std::string &name)
4211 DSTACK(__FUNCTION_NAME);
4213 for(std::map<u16, RemoteClient*>::iterator
4214 i = m_clients.begin();
4215 i != m_clients.end(); ++i){
4216 RemoteClient *client = i->second;
4217 sendDetachedInventory(name, client->peer_id);
4221 void Server::sendDetachedInventories(u16 peer_id)
4223 DSTACK(__FUNCTION_NAME);
4225 for(std::map<std::string, Inventory*>::iterator
4226 i = m_detached_inventories.begin();
4227 i != m_detached_inventories.end(); i++){
4228 const std::string &name = i->first;
4229 //Inventory *inv = i->second;
4230 sendDetachedInventory(name, peer_id);
4238 void Server::DiePlayer(u16 peer_id)
4240 DSTACK(__FUNCTION_NAME);
4242 PlayerSAO *playersao = getPlayerSAO(peer_id);
4245 infostream<<"Server::DiePlayer(): Player "
4246 <<playersao->getPlayer()->getName()
4247 <<" dies"<<std::endl;
4249 playersao->setHP(0);
4251 // Trigger scripted stuff
4252 scriptapi_on_dieplayer(m_lua, playersao);
4254 SendPlayerHP(peer_id);
4255 SendDeathscreen(m_con, peer_id, false, v3f(0,0,0));
4258 void Server::RespawnPlayer(u16 peer_id)
4260 DSTACK(__FUNCTION_NAME);
4262 PlayerSAO *playersao = getPlayerSAO(peer_id);
4265 infostream<<"Server::RespawnPlayer(): Player "
4266 <<playersao->getPlayer()->getName()
4267 <<" respawns"<<std::endl;
4269 playersao->setHP(PLAYER_MAX_HP);
4271 bool repositioned = scriptapi_on_respawnplayer(m_lua, playersao);
4273 v3f pos = findSpawnPos(m_env->getServerMap());
4274 playersao->setPos(pos);
4278 void Server::UpdateCrafting(u16 peer_id)
4280 DSTACK(__FUNCTION_NAME);
4282 Player* player = m_env->getPlayer(peer_id);
4285 // Get a preview for crafting
4287 getCraftingResult(&player->inventory, preview, false, this);
4289 // Put the new preview in
4290 InventoryList *plist = player->inventory.getList("craftpreview");
4292 assert(plist->getSize() >= 1);
4293 plist->changeItem(0, preview);
4296 RemoteClient* Server::getClient(u16 peer_id)
4298 DSTACK(__FUNCTION_NAME);
4299 //JMutexAutoLock lock(m_con_mutex);
4300 std::map<u16, RemoteClient*>::iterator n;
4301 n = m_clients.find(peer_id);
4302 // A client should exist for all peers
4303 assert(n != m_clients.end());
4307 std::wstring Server::getStatusString()
4309 std::wostringstream os(std::ios_base::binary);
4312 os<<L"version="<<narrow_to_wide(VERSION_STRING);
4314 os<<L", uptime="<<m_uptime.get();
4315 // Information about clients
4316 std::map<u16, RemoteClient*>::iterator i;
4319 for(i = m_clients.begin(), first = true;
4320 i != m_clients.end(); ++i)
4322 // Get client and check that it is valid
4323 RemoteClient *client = i->second;
4324 assert(client->peer_id == i->first);
4325 if(client->serialization_version == SER_FMT_VER_INVALID)
4328 Player *player = m_env->getPlayer(client->peer_id);
4329 // Get name of player
4330 std::wstring name = L"unknown";
4332 name = narrow_to_wide(player->getName());
4333 // Add name to information string
4341 if(((ServerMap*)(&m_env->getMap()))->isSavingEnabled() == false)
4342 os<<std::endl<<L"# Server: "<<" WARNING: Map saving is disabled.";
4343 if(g_settings->get("motd") != "")
4344 os<<std::endl<<L"# Server: "<<narrow_to_wide(g_settings->get("motd"));
4348 std::set<std::string> Server::getPlayerEffectivePrivs(const std::string &name)
4350 std::set<std::string> privs;
4351 scriptapi_get_auth(m_lua, name, NULL, &privs);
4355 bool Server::checkPriv(const std::string &name, const std::string &priv)
4357 std::set<std::string> privs = getPlayerEffectivePrivs(name);
4358 return (privs.count(priv) != 0);
4361 void Server::reportPrivsModified(const std::string &name)
4364 for(std::map<u16, RemoteClient*>::iterator
4365 i = m_clients.begin();
4366 i != m_clients.end(); ++i){
4367 RemoteClient *client = i->second;
4368 Player *player = m_env->getPlayer(client->peer_id);
4369 reportPrivsModified(player->getName());
4372 Player *player = m_env->getPlayer(name.c_str());
4375 SendPlayerPrivileges(player->peer_id);
4376 PlayerSAO *sao = player->getPlayerSAO();
4379 sao->updatePrivileges(
4380 getPlayerEffectivePrivs(name),
4385 void Server::reportInventoryFormspecModified(const std::string &name)
4387 Player *player = m_env->getPlayer(name.c_str());
4390 SendPlayerInventoryFormspec(player->peer_id);
4393 // Saves g_settings to configpath given at initialization
4394 void Server::saveConfig()
4396 if(m_path_config != "")
4397 g_settings->updateConfigFile(m_path_config.c_str());
4400 void Server::notifyPlayer(const char *name, const std::wstring msg)
4402 Player *player = m_env->getPlayer(name);
4405 SendChatMessage(player->peer_id, std::wstring(L"Server: -!- ")+msg);
4408 bool Server::showFormspec(const char *playername, const std::string &formspec, const std::string &formname)
4410 Player *player = m_env->getPlayer(playername);
4414 infostream<<"showFormspec: couldn't find player:"<<playername<<std::endl;
4418 SendShowFormspecMessage(player->peer_id, formspec, formname);
4422 void Server::notifyPlayers(const std::wstring msg)
4424 BroadcastChatMessage(msg);
4427 void Server::queueBlockEmerge(v3s16 blockpos, bool allow_generate)
4429 m_emerge->enqueueBlockEmerge(PEER_ID_INEXISTENT, blockpos, allow_generate);
4432 Inventory* Server::createDetachedInventory(const std::string &name)
4434 if(m_detached_inventories.count(name) > 0){
4435 infostream<<"Server clearing detached inventory \""<<name<<"\""<<std::endl;
4436 delete m_detached_inventories[name];
4438 infostream<<"Server creating detached inventory \""<<name<<"\""<<std::endl;
4440 Inventory *inv = new Inventory(m_itemdef);
4442 m_detached_inventories[name] = inv;
4443 sendDetachedInventoryToAll(name);
4450 BoolScopeSet(bool *dst, bool val):
4453 m_orig_state = *m_dst;
4458 *m_dst = m_orig_state;
4465 // actions: time-reversed list
4466 // Return value: success/failure
4467 bool Server::rollbackRevertActions(const std::list<RollbackAction> &actions,
4468 std::list<std::string> *log)
4470 infostream<<"Server::rollbackRevertActions(len="<<actions.size()<<")"<<std::endl;
4471 ServerMap *map = (ServerMap*)(&m_env->getMap());
4472 // Disable rollback report sink while reverting
4473 BoolScopeSet rollback_scope_disable(&m_rollback_sink_enabled, false);
4475 // Fail if no actions to handle
4476 if(actions.empty()){
4477 log->push_back("Nothing to do.");
4484 for(std::list<RollbackAction>::const_iterator
4485 i = actions.begin();
4486 i != actions.end(); i++)
4488 const RollbackAction &action = *i;
4490 bool success = action.applyRevert(map, this, this);
4493 std::ostringstream os;
4494 os<<"Revert of step ("<<num_tried<<") "<<action.toString()<<" failed";
4495 infostream<<"Map::rollbackRevertActions(): "<<os.str()<<std::endl;
4497 log->push_back(os.str());
4499 std::ostringstream os;
4500 os<<"Successfully reverted step ("<<num_tried<<") "<<action.toString();
4501 infostream<<"Map::rollbackRevertActions(): "<<os.str()<<std::endl;
4503 log->push_back(os.str());
4507 infostream<<"Map::rollbackRevertActions(): "<<num_failed<<"/"<<num_tried
4508 <<" failed"<<std::endl;
4510 // Call it done if less than half failed
4511 return num_failed <= num_tried/2;
4514 // IGameDef interface
4516 IItemDefManager* Server::getItemDefManager()
4520 INodeDefManager* Server::getNodeDefManager()
4524 ICraftDefManager* Server::getCraftDefManager()
4528 ITextureSource* Server::getTextureSource()
4532 IShaderSource* Server::getShaderSource()
4536 u16 Server::allocateUnknownNodeId(const std::string &name)
4538 return m_nodedef->allocateDummy(name);
4540 ISoundManager* Server::getSoundManager()
4542 return &dummySoundManager;
4544 MtEventManager* Server::getEventManager()
4548 IRollbackReportSink* Server::getRollbackReportSink()
4550 if(!m_enable_rollback_recording)
4552 if(!m_rollback_sink_enabled)
4557 IWritableItemDefManager* Server::getWritableItemDefManager()
4561 IWritableNodeDefManager* Server::getWritableNodeDefManager()
4565 IWritableCraftDefManager* Server::getWritableCraftDefManager()
4570 const ModSpec* Server::getModSpec(const std::string &modname)
4572 for(std::vector<ModSpec>::iterator i = m_mods.begin();
4573 i != m_mods.end(); i++){
4574 const ModSpec &mod = *i;
4575 if(mod.name == modname)
4580 void Server::getModNames(std::list<std::string> &modlist)
4582 for(std::vector<ModSpec>::iterator i = m_mods.begin(); i != m_mods.end(); i++)
4584 modlist.push_back(i->name);
4587 std::string Server::getBuiltinLuaPath()
4589 return porting::path_share + DIR_DELIM + "builtin";
4592 v3f findSpawnPos(ServerMap &map)
4594 //return v3f(50,50,50)*BS;
4599 nodepos = v2s16(0,0);
4604 s16 water_level = map.m_mgparams->water_level;
4606 // Try to find a good place a few times
4607 for(s32 i=0; i<1000; i++)
4610 // We're going to try to throw the player to this position
4611 v2s16 nodepos2d = v2s16(-range + (myrand()%(range*2)),
4612 -range + (myrand()%(range*2)));
4613 //v2s16 sectorpos = getNodeSectorPos(nodepos2d);
4614 // Get ground height at point (fallbacks to heightmap function)
4615 s16 groundheight = map.findGroundLevel(nodepos2d);
4616 // Don't go underwater
4617 if(groundheight <= water_level)
4619 //infostream<<"-> Underwater"<<std::endl;
4622 // Don't go to high places
4623 if(groundheight > water_level + 6)
4625 //infostream<<"-> Underwater"<<std::endl;
4629 nodepos = v3s16(nodepos2d.X, groundheight-2, nodepos2d.Y);
4630 bool is_good = false;
4632 for(s32 i=0; i<10; i++){
4633 v3s16 blockpos = getNodeBlockPos(nodepos);
4634 map.emergeBlock(blockpos, true);
4635 MapNode n = map.getNodeNoEx(nodepos);
4636 if(n.getContent() == CONTENT_AIR){
4647 // Found a good place
4648 //infostream<<"Searched through "<<i<<" places."<<std::endl;
4654 return intToFloat(nodepos, BS);
4657 PlayerSAO* Server::emergePlayer(const char *name, u16 peer_id)
4659 RemotePlayer *player = NULL;
4660 bool newplayer = false;
4663 Try to get an existing player
4665 player = static_cast<RemotePlayer*>(m_env->getPlayer(name));
4667 // If player is already connected, cancel
4668 if(player != NULL && player->peer_id != 0)
4670 infostream<<"emergePlayer(): Player already connected"<<std::endl;
4675 If player with the wanted peer_id already exists, cancel.
4677 if(m_env->getPlayer(peer_id) != NULL)
4679 infostream<<"emergePlayer(): Player with wrong name but same"
4680 " peer_id already exists"<<std::endl;
4685 Create a new player if it doesn't exist yet
4690 player = new RemotePlayer(this);
4691 player->updateName(name);
4693 /* Set player position */
4694 infostream<<"Server: Finding spawn place for player \""
4695 <<name<<"\""<<std::endl;
4696 v3f pos = findSpawnPos(m_env->getServerMap());
4697 player->setPosition(pos);
4699 /* Add player to environment */
4700 m_env->addPlayer(player);
4704 Create a new player active object
4706 PlayerSAO *playersao = new PlayerSAO(m_env, player, peer_id,
4707 getPlayerEffectivePrivs(player->getName()),
4710 /* Add object to environment */
4711 m_env->addActiveObject(playersao);
4715 scriptapi_on_newplayer(m_lua, playersao);
4717 scriptapi_on_joinplayer(m_lua, playersao);
4722 void Server::handlePeerChange(PeerChange &c)
4724 JMutexAutoLock envlock(m_env_mutex);
4725 JMutexAutoLock conlock(m_con_mutex);
4727 if(c.type == PEER_ADDED)
4734 std::map<u16, RemoteClient*>::iterator n;
4735 n = m_clients.find(c.peer_id);
4736 // The client shouldn't already exist
4737 assert(n == m_clients.end());
4740 RemoteClient *client = new RemoteClient();
4741 client->peer_id = c.peer_id;
4742 m_clients[client->peer_id] = client;
4745 else if(c.type == PEER_REMOVED)
4752 std::map<u16, RemoteClient*>::iterator n;
4753 n = m_clients.find(c.peer_id);
4754 // The client should exist
4755 assert(n != m_clients.end());
4758 Mark objects to be not known by the client
4760 RemoteClient *client = n->second;
4762 for(std::set<u16>::iterator
4763 i = client->m_known_objects.begin();
4764 i != client->m_known_objects.end(); ++i)
4768 ServerActiveObject* obj = m_env->getActiveObject(id);
4770 if(obj && obj->m_known_by_count > 0)
4771 obj->m_known_by_count--;
4775 Clear references to playing sounds
4777 for(std::map<s32, ServerPlayingSound>::iterator
4778 i = m_playing_sounds.begin();
4779 i != m_playing_sounds.end();)
4781 ServerPlayingSound &psound = i->second;
4782 psound.clients.erase(c.peer_id);
4783 if(psound.clients.size() == 0)
4784 m_playing_sounds.erase(i++);
4789 Player *player = m_env->getPlayer(c.peer_id);
4791 // Collect information about leaving in chat
4792 std::wstring message;
4796 std::wstring name = narrow_to_wide(player->getName());
4799 message += L" left the game.";
4801 message += L" (timed out)";
4805 /* Run scripts and remove from environment */
4809 PlayerSAO *playersao = player->getPlayerSAO();
4812 scriptapi_on_leaveplayer(m_lua, playersao);
4814 playersao->disconnected();
4824 std::ostringstream os(std::ios_base::binary);
4825 for(std::map<u16, RemoteClient*>::iterator
4826 i = m_clients.begin();
4827 i != m_clients.end(); ++i)
4829 RemoteClient *client = i->second;
4830 assert(client->peer_id == i->first);
4831 if(client->serialization_version == SER_FMT_VER_INVALID)
4834 Player *player = m_env->getPlayer(client->peer_id);
4837 // Get name of player
4838 os<<player->getName()<<" ";
4841 actionstream<<player->getName()<<" "
4842 <<(c.timeout?"times out.":"leaves game.")
4843 <<" List of players: "
4844 <<os.str()<<std::endl;
4849 delete m_clients[c.peer_id];
4850 m_clients.erase(c.peer_id);
4852 // Send player info to all remaining clients
4853 //SendPlayerInfos();
4855 // Send leave chat message to all remaining clients
4856 if(message.length() != 0)
4857 BroadcastChatMessage(message);
4866 void Server::handlePeerChanges()
4868 while(m_peer_change_queue.size() > 0)
4870 PeerChange c = m_peer_change_queue.pop_front();
4872 verbosestream<<"Server: Handling peer change: "
4873 <<"id="<<c.peer_id<<", timeout="<<c.timeout
4876 handlePeerChange(c);
4880 void dedicated_server_loop(Server &server, bool &kill)
4882 DSTACK(__FUNCTION_NAME);
4884 verbosestream<<"dedicated_server_loop()"<<std::endl;
4886 IntervalLimiter m_profiler_interval;
4890 float steplen = g_settings->getFloat("dedicated_server_step");
4891 // This is kind of a hack but can be done like this
4892 // because server.step() is very light
4894 ScopeProfiler sp(g_profiler, "dedicated server sleep");
4895 sleep_ms((int)(steplen*1000.0));
4897 server.step(steplen);
4899 if(server.getShutdownRequested() || kill)
4901 infostream<<"Dedicated server quitting"<<std::endl;
4903 if(g_settings->getBool("server_announce") == true)
4904 ServerList::sendAnnounce("delete");
4912 float profiler_print_interval =
4913 g_settings->getFloat("profiler_print_interval");
4914 if(profiler_print_interval != 0)
4916 if(m_profiler_interval.step(steplen, profiler_print_interval))
4918 infostream<<"Profiler:"<<std::endl;
4919 g_profiler->print(infostream);
4920 g_profiler->clear();