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 core::array<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 core::list<v3s16> list;
278 getFacePositions(list, d);
280 core::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) != NULL)
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) != NULL)
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) != NULL)
558 m_blocks_sending.remove(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, true);
568 void RemoteClient::SentBlock(v3s16 p)
570 if(m_blocks_sending.find(p) == NULL)
571 m_blocks_sending.insert(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) != NULL)
582 m_blocks_sending.remove(p);
583 if(m_blocks_sent.find(p) != NULL)
584 m_blocks_sent.remove(p);
587 void RemoteClient::SetBlocksNotSent(core::map<v3s16, MapBlock*> &blocks)
589 m_nearest_unsent_d = 0;
591 for(core::map<v3s16, MapBlock*>::Iterator
592 i = blocks.getIterator();
593 i.atEnd()==false; i++)
595 v3s16 p = i.getNode()->getKey();
597 if(m_blocks_sending.find(p) != NULL)
598 m_blocks_sending.remove(p);
599 if(m_blocks_sent.find(p) != NULL)
600 m_blocks_sent.remove(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_print_info_timer = 0.0;
663 m_masterserver_timer = 0.0;
664 m_objectdata_timer = 0.0;
665 m_emergethread_trigger_timer = 0.0;
666 m_savemap_timer = 0.0;
667 m_clients_number = 0;
671 m_step_dtime_mutex.Init();
675 throw ServerError("Supplied empty world path");
677 if(!gamespec.isValid())
678 throw ServerError("Supplied invalid gamespec");
680 infostream<<"Server created for gameid \""<<m_gamespec.id<<"\"";
681 if(m_simple_singleplayer_mode)
682 infostream<<" in simple singleplayer mode"<<std::endl;
684 infostream<<std::endl;
685 infostream<<"- world: "<<m_path_world<<std::endl;
686 infostream<<"- config: "<<m_path_config<<std::endl;
687 infostream<<"- game: "<<m_gamespec.path<<std::endl;
689 // Create biome definition manager
690 m_biomedef = new BiomeDefManager(this);
692 // Create rollback manager
693 std::string rollback_path = m_path_world+DIR_DELIM+"rollback.txt";
694 m_rollback = createRollbackManager(rollback_path, this);
696 // Create world if it doesn't exist
697 if(!initializeWorld(m_path_world, m_gamespec.id))
698 throw ServerError("Failed to initialize world");
700 ModConfiguration modconf(m_path_world);
701 m_mods = modconf.getMods();
702 std::list<ModSpec> unsatisfied_mods = modconf.getUnsatisfiedMods();
703 // complain about mods with unsatisfied dependencies
704 if(!modconf.isConsistent())
706 for(std::list<ModSpec>::iterator it = unsatisfied_mods.begin();
707 it != unsatisfied_mods.end(); ++it)
710 errorstream << "mod \"" << mod.name << "\" has unsatisfied dependencies: ";
711 for(std::set<std::string>::iterator dep_it = mod.unsatisfied_depends.begin();
712 dep_it != mod.unsatisfied_depends.end(); ++dep_it)
713 errorstream << " \"" << *dep_it << "\"";
714 errorstream << std::endl;
718 Settings worldmt_settings;
719 std::string worldmt = m_path_world + DIR_DELIM + "world.mt";
720 worldmt_settings.readConfigFile(worldmt.c_str());
721 std::vector<std::string> names = worldmt_settings.getNames();
722 std::set<std::string> exclude_mod_names;
723 std::set<std::string> load_mod_names;
724 for(std::vector<std::string>::iterator it = names.begin();
725 it != names.end(); ++it)
727 std::string name = *it;
728 if (name.compare(0,9,"load_mod_")==0)
730 if(worldmt_settings.getBool(name))
731 load_mod_names.insert(name.substr(9));
733 exclude_mod_names.insert(name.substr(9));
736 // complain about mods declared to be loaded, but not found
737 for(std::vector<ModSpec>::iterator it = m_mods.begin();
738 it != m_mods.end(); ++it)
739 load_mod_names.erase((*it).name);
740 for(std::list<ModSpec>::iterator it = unsatisfied_mods.begin();
741 it != unsatisfied_mods.end(); ++it)
742 load_mod_names.erase((*it).name);
743 if(!load_mod_names.empty())
745 errorstream << "The following mods could not be found:";
746 for(std::set<std::string>::iterator it = load_mod_names.begin();
747 it != load_mod_names.end(); ++it)
748 errorstream << " \"" << (*it) << "\"";
749 errorstream << std::endl;
752 // Path to builtin.lua
753 std::string builtinpath = getBuiltinLuaPath() + DIR_DELIM + "builtin.lua";
756 JMutexAutoLock envlock(m_env_mutex);
757 JMutexAutoLock conlock(m_con_mutex);
759 // Initialize scripting
761 infostream<<"Server: Initializing Lua"<<std::endl;
762 m_lua = script_init();
765 scriptapi_export(m_lua, this);
766 // Load and run builtin.lua
767 infostream<<"Server: Loading builtin.lua [\""
768 <<builtinpath<<"\"]"<<std::endl;
769 bool success = scriptapi_loadmod(m_lua, builtinpath, "__builtin");
771 errorstream<<"Server: Failed to load and run "
772 <<builtinpath<<std::endl;
773 throw ModError("Failed to load and run "+builtinpath);
776 infostream<<"Server: Loading mods: ";
777 for(std::vector<ModSpec>::iterator i = m_mods.begin();
778 i != m_mods.end(); i++){
779 const ModSpec &mod = *i;
780 infostream<<mod.name<<" ";
782 infostream<<std::endl;
783 // Load and run "mod" scripts
784 for(std::vector<ModSpec>::iterator i = m_mods.begin();
785 i != m_mods.end(); i++){
786 const ModSpec &mod = *i;
787 std::string scriptpath = mod.path + DIR_DELIM + "init.lua";
788 infostream<<" ["<<padStringRight(mod.name, 12)<<"] [\""
789 <<scriptpath<<"\"]"<<std::endl;
790 bool success = scriptapi_loadmod(m_lua, scriptpath, mod.name);
792 errorstream<<"Server: Failed to load and run "
793 <<scriptpath<<std::endl;
794 throw ModError("Failed to load and run "+scriptpath);
798 // Read Textures and calculate sha1 sums
801 // Apply item aliases in the node definition manager
802 m_nodedef->updateAliases(m_itemdef);
804 // Add default biomes after nodedef had its aliases added
805 m_biomedef->addDefaultBiomes();
807 // Create emerge manager
808 m_emerge = new EmergeManager(this, m_biomedef);
810 // Initialize Environment
811 ServerMap *servermap = new ServerMap(path_world, this, m_emerge);
812 m_env = new ServerEnvironment(servermap, m_lua, this, this);
814 m_emerge->initMapgens(servermap->getMapgenParams());
816 // Give environment reference to scripting api
817 scriptapi_add_environment(m_lua, m_env);
819 // Register us to receive map edit events
820 servermap->addEventReceiver(this);
822 // If file exists, load environment metadata
823 if(fs::PathExists(m_path_world+DIR_DELIM+"env_meta.txt"))
825 infostream<<"Server: Loading environment metadata"<<std::endl;
826 m_env->loadMeta(m_path_world);
830 infostream<<"Server: Loading players"<<std::endl;
831 m_env->deSerializePlayers(m_path_world);
834 Add some test ActiveBlockModifiers to environment
836 add_legacy_abms(m_env, m_nodedef);
841 infostream<<"Server destructing"<<std::endl;
844 Send shutdown message
847 JMutexAutoLock conlock(m_con_mutex);
849 std::wstring line = L"*** Server shutting down";
852 Send the message to clients
854 for(core::map<u16, RemoteClient*>::Iterator
855 i = m_clients.getIterator();
856 i.atEnd() == false; i++)
858 // Get client and check that it is valid
859 RemoteClient *client = i.getNode()->getValue();
860 assert(client->peer_id == i.getNode()->getKey());
861 if(client->serialization_version == SER_FMT_VER_INVALID)
865 SendChatMessage(client->peer_id, line);
867 catch(con::PeerNotFoundException &e)
873 JMutexAutoLock envlock(m_env_mutex);
874 JMutexAutoLock conlock(m_con_mutex);
877 Execute script shutdown hooks
879 scriptapi_on_shutdown(m_lua);
883 JMutexAutoLock envlock(m_env_mutex);
888 infostream<<"Server: Saving players"<<std::endl;
889 m_env->serializePlayers(m_path_world);
892 Save environment metadata
894 infostream<<"Server: Saving environment metadata"<<std::endl;
895 m_env->saveMeta(m_path_world);
907 JMutexAutoLock clientslock(m_con_mutex);
909 for(core::map<u16, RemoteClient*>::Iterator
910 i = m_clients.getIterator();
911 i.atEnd() == false; i++)
915 delete i.getNode()->getValue();
919 // Delete things in the reverse order of creation
928 // Deinitialize scripting
929 infostream<<"Server: Deinitializing scripting"<<std::endl;
930 script_deinit(m_lua);
932 // Delete detached inventories
934 for(std::map<std::string, Inventory*>::iterator
935 i = m_detached_inventories.begin();
936 i != m_detached_inventories.end(); i++){
942 void Server::start(unsigned short port)
944 DSTACK(__FUNCTION_NAME);
945 infostream<<"Starting server on port "<<port<<"..."<<std::endl;
947 // Stop thread if already running
950 // Initialize connection
951 m_con.SetTimeoutMs(30);
955 m_thread.setRun(true);
958 // ASCII art for the win!
960 <<" .__ __ __ "<<std::endl
961 <<" _____ |__| ____ _____/ |_ ____ _______/ |_ "<<std::endl
962 <<" / \\| |/ \\_/ __ \\ __\\/ __ \\ / ___/\\ __\\"<<std::endl
963 <<"| Y Y \\ | | \\ ___/| | \\ ___/ \\___ \\ | | "<<std::endl
964 <<"|__|_| /__|___| /\\___ >__| \\___ >____ > |__| "<<std::endl
965 <<" \\/ \\/ \\/ \\/ \\/ "<<std::endl;
966 actionstream<<"World at ["<<m_path_world<<"]"<<std::endl;
967 actionstream<<"Server for gameid=\""<<m_gamespec.id
968 <<"\" listening on port "<<port<<"."<<std::endl;
973 DSTACK(__FUNCTION_NAME);
975 infostream<<"Server: Stopping and waiting threads"<<std::endl;
977 // Stop threads (set run=false first so both start stopping)
978 m_thread.setRun(false);
979 //m_emergethread.setRun(false);
981 //m_emergethread.stop();
983 infostream<<"Server: Threads stopped"<<std::endl;
986 void Server::step(float dtime)
988 DSTACK(__FUNCTION_NAME);
993 JMutexAutoLock lock(m_step_dtime_mutex);
994 m_step_dtime += dtime;
996 // Throw if fatal error occurred in thread
997 std::string async_err = m_async_fatal_error.get();
999 throw ServerError(async_err);
1003 void Server::AsyncRunStep()
1005 DSTACK(__FUNCTION_NAME);
1007 g_profiler->add("Server::AsyncRunStep (num)", 1);
1011 JMutexAutoLock lock1(m_step_dtime_mutex);
1012 dtime = m_step_dtime;
1016 // Send blocks to clients
1023 g_profiler->add("Server::AsyncRunStep with dtime (num)", 1);
1025 //infostream<<"Server steps "<<dtime<<std::endl;
1026 //infostream<<"Server::AsyncRunStep(): dtime="<<dtime<<std::endl;
1029 JMutexAutoLock lock1(m_step_dtime_mutex);
1030 m_step_dtime -= dtime;
1037 m_uptime.set(m_uptime.get() + dtime);
1041 // Process connection's timeouts
1042 JMutexAutoLock lock2(m_con_mutex);
1043 ScopeProfiler sp(g_profiler, "Server: connection timeout processing");
1044 m_con.RunTimeouts(dtime);
1048 // This has to be called so that the client list gets synced
1049 // with the peer list of the connection
1050 handlePeerChanges();
1054 Update time of day and overall game time
1057 JMutexAutoLock envlock(m_env_mutex);
1059 m_env->setTimeOfDaySpeed(g_settings->getFloat("time_speed"));
1062 Send to clients at constant intervals
1065 m_time_of_day_send_timer -= dtime;
1066 if(m_time_of_day_send_timer < 0.0)
1068 m_time_of_day_send_timer = g_settings->getFloat("time_send_interval");
1070 //JMutexAutoLock envlock(m_env_mutex);
1071 JMutexAutoLock conlock(m_con_mutex);
1073 for(core::map<u16, RemoteClient*>::Iterator
1074 i = m_clients.getIterator();
1075 i.atEnd() == false; i++)
1077 RemoteClient *client = i.getNode()->getValue();
1078 SharedBuffer<u8> data = makePacket_TOCLIENT_TIME_OF_DAY(
1079 m_env->getTimeOfDay(), g_settings->getFloat("time_speed"));
1081 m_con.Send(client->peer_id, 0, data, true);
1087 JMutexAutoLock lock(m_env_mutex);
1089 ScopeProfiler sp(g_profiler, "SEnv step");
1090 ScopeProfiler sp2(g_profiler, "SEnv step avg", SPT_AVG);
1094 const float map_timer_and_unload_dtime = 2.92;
1095 if(m_map_timer_and_unload_interval.step(dtime, map_timer_and_unload_dtime))
1097 JMutexAutoLock lock(m_env_mutex);
1098 // Run Map's timers and unload unused data
1099 ScopeProfiler sp(g_profiler, "Server: map timer and unload");
1100 m_env->getMap().timerUpdate(map_timer_and_unload_dtime,
1101 g_settings->getFloat("server_unload_unused_data_timeout"));
1112 JMutexAutoLock lock(m_env_mutex);
1113 JMutexAutoLock lock2(m_con_mutex);
1115 ScopeProfiler sp(g_profiler, "Server: handle players");
1117 for(core::map<u16, RemoteClient*>::Iterator
1118 i = m_clients.getIterator();
1119 i.atEnd() == false; i++)
1121 RemoteClient *client = i.getNode()->getValue();
1122 PlayerSAO *playersao = getPlayerSAO(client->peer_id);
1123 if(playersao == NULL)
1127 Handle player HPs (die if hp=0)
1129 if(playersao->m_hp_not_sent && g_settings->getBool("enable_damage"))
1131 if(playersao->getHP() == 0)
1132 DiePlayer(client->peer_id);
1134 SendPlayerHP(client->peer_id);
1138 Send player inventories if necessary
1140 if(playersao->m_moved){
1141 SendMovePlayer(client->peer_id);
1142 playersao->m_moved = false;
1144 if(playersao->m_inventory_not_sent){
1145 UpdateCrafting(client->peer_id);
1146 SendInventory(client->peer_id);
1151 /* Transform liquids */
1152 m_liquid_transform_timer += dtime;
1153 if(m_liquid_transform_timer >= 1.00)
1155 m_liquid_transform_timer -= 1.00;
1157 JMutexAutoLock lock(m_env_mutex);
1159 ScopeProfiler sp(g_profiler, "Server: liquid transform");
1161 core::map<v3s16, MapBlock*> modified_blocks;
1162 m_env->getMap().transformLiquids(modified_blocks);
1167 core::map<v3s16, MapBlock*> lighting_modified_blocks;
1168 ServerMap &map = ((ServerMap&)m_env->getMap());
1169 map.updateLighting(modified_blocks, lighting_modified_blocks);
1171 // Add blocks modified by lighting to modified_blocks
1172 for(core::map<v3s16, MapBlock*>::Iterator
1173 i = lighting_modified_blocks.getIterator();
1174 i.atEnd() == false; i++)
1176 MapBlock *block = i.getNode()->getValue();
1177 modified_blocks.insert(block->getPos(), block);
1181 Set the modified blocks unsent for all the clients
1184 JMutexAutoLock lock2(m_con_mutex);
1186 for(core::map<u16, RemoteClient*>::Iterator
1187 i = m_clients.getIterator();
1188 i.atEnd() == false; i++)
1190 RemoteClient *client = i.getNode()->getValue();
1192 if(modified_blocks.size() > 0)
1194 // Remove block from sent history
1195 client->SetBlocksNotSent(modified_blocks);
1200 // Periodically print some info
1202 float &counter = m_print_info_timer;
1208 JMutexAutoLock lock2(m_con_mutex);
1209 m_clients_number = 0;
1210 if(m_clients.size() != 0)
1211 infostream<<"Players:"<<std::endl;
1212 for(core::map<u16, RemoteClient*>::Iterator
1213 i = m_clients.getIterator();
1214 i.atEnd() == false; i++)
1216 //u16 peer_id = i.getNode()->getKey();
1217 RemoteClient *client = i.getNode()->getValue();
1218 Player *player = m_env->getPlayer(client->peer_id);
1221 infostream<<"* "<<player->getName()<<"\t";
1222 client->PrintInfo(infostream);
1230 // send masterserver announce
1232 float &counter = m_masterserver_timer;
1233 if((!counter || counter >= 300.0) && g_settings->getBool("server_announce") == true)
1235 ServerList::sendAnnounce(!counter ? "start" : "update", m_clients_number);
1242 //if(g_settings->getBool("enable_experimental"))
1246 Check added and deleted active objects
1249 //infostream<<"Server: Checking added and deleted active objects"<<std::endl;
1250 JMutexAutoLock envlock(m_env_mutex);
1251 JMutexAutoLock conlock(m_con_mutex);
1253 ScopeProfiler sp(g_profiler, "Server: checking added and deleted objs");
1255 // Radius inside which objects are active
1256 s16 radius = g_settings->getS16("active_object_send_range_blocks");
1257 radius *= MAP_BLOCKSIZE;
1259 for(core::map<u16, RemoteClient*>::Iterator
1260 i = m_clients.getIterator();
1261 i.atEnd() == false; i++)
1263 RemoteClient *client = i.getNode()->getValue();
1265 // If definitions and textures have not been sent, don't
1266 // send objects either
1267 if(!client->definitions_sent)
1270 Player *player = m_env->getPlayer(client->peer_id);
1273 // This can happen if the client timeouts somehow
1274 /*infostream<<"WARNING: "<<__FUNCTION_NAME<<": Client "
1276 <<" has no associated player"<<std::endl;*/
1279 v3s16 pos = floatToInt(player->getPosition(), BS);
1281 core::map<u16, bool> removed_objects;
1282 core::map<u16, bool> added_objects;
1283 m_env->getRemovedActiveObjects(pos, radius,
1284 client->m_known_objects, removed_objects);
1285 m_env->getAddedActiveObjects(pos, radius,
1286 client->m_known_objects, added_objects);
1288 // Ignore if nothing happened
1289 if(removed_objects.size() == 0 && added_objects.size() == 0)
1291 //infostream<<"active objects: none changed"<<std::endl;
1295 std::string data_buffer;
1299 // Handle removed objects
1300 writeU16((u8*)buf, removed_objects.size());
1301 data_buffer.append(buf, 2);
1302 for(core::map<u16, bool>::Iterator
1303 i = removed_objects.getIterator();
1304 i.atEnd()==false; i++)
1307 u16 id = i.getNode()->getKey();
1308 ServerActiveObject* obj = m_env->getActiveObject(id);
1310 // Add to data buffer for sending
1311 writeU16((u8*)buf, i.getNode()->getKey());
1312 data_buffer.append(buf, 2);
1314 // Remove from known objects
1315 client->m_known_objects.remove(i.getNode()->getKey());
1317 if(obj && obj->m_known_by_count > 0)
1318 obj->m_known_by_count--;
1321 // Handle added objects
1322 writeU16((u8*)buf, added_objects.size());
1323 data_buffer.append(buf, 2);
1324 for(core::map<u16, bool>::Iterator
1325 i = added_objects.getIterator();
1326 i.atEnd()==false; i++)
1329 u16 id = i.getNode()->getKey();
1330 ServerActiveObject* obj = m_env->getActiveObject(id);
1333 u8 type = ACTIVEOBJECT_TYPE_INVALID;
1335 infostream<<"WARNING: "<<__FUNCTION_NAME
1336 <<": NULL object"<<std::endl;
1338 type = obj->getSendType();
1340 // Add to data buffer for sending
1341 writeU16((u8*)buf, id);
1342 data_buffer.append(buf, 2);
1343 writeU8((u8*)buf, type);
1344 data_buffer.append(buf, 1);
1347 data_buffer.append(serializeLongString(
1348 obj->getClientInitializationData(client->net_proto_version)));
1350 data_buffer.append(serializeLongString(""));
1352 // Add to known objects
1353 client->m_known_objects.insert(i.getNode()->getKey(), false);
1356 obj->m_known_by_count++;
1360 SharedBuffer<u8> reply(2 + data_buffer.size());
1361 writeU16(&reply[0], TOCLIENT_ACTIVE_OBJECT_REMOVE_ADD);
1362 memcpy((char*)&reply[2], data_buffer.c_str(),
1363 data_buffer.size());
1365 m_con.Send(client->peer_id, 0, reply, true);
1367 verbosestream<<"Server: Sent object remove/add: "
1368 <<removed_objects.size()<<" removed, "
1369 <<added_objects.size()<<" added, "
1370 <<"packet size is "<<reply.getSize()<<std::endl;
1375 Collect a list of all the objects known by the clients
1376 and report it back to the environment.
1379 core::map<u16, bool> all_known_objects;
1381 for(core::map<u16, RemoteClient*>::Iterator
1382 i = m_clients.getIterator();
1383 i.atEnd() == false; i++)
1385 RemoteClient *client = i.getNode()->getValue();
1386 // Go through all known objects of client
1387 for(core::map<u16, bool>::Iterator
1388 i = client->m_known_objects.getIterator();
1389 i.atEnd()==false; i++)
1391 u16 id = i.getNode()->getKey();
1392 all_known_objects[id] = true;
1396 m_env->setKnownActiveObjects(whatever);
1402 Send object messages
1405 JMutexAutoLock envlock(m_env_mutex);
1406 JMutexAutoLock conlock(m_con_mutex);
1408 ScopeProfiler sp(g_profiler, "Server: sending object messages");
1411 // Value = data sent by object
1412 core::map<u16, core::list<ActiveObjectMessage>* > buffered_messages;
1414 // Get active object messages from environment
1417 ActiveObjectMessage aom = m_env->getActiveObjectMessage();
1421 core::list<ActiveObjectMessage>* message_list = NULL;
1422 core::map<u16, core::list<ActiveObjectMessage>* >::Node *n;
1423 n = buffered_messages.find(aom.id);
1426 message_list = new core::list<ActiveObjectMessage>;
1427 buffered_messages.insert(aom.id, message_list);
1431 message_list = n->getValue();
1433 message_list->push_back(aom);
1436 // Route data to every client
1437 for(core::map<u16, RemoteClient*>::Iterator
1438 i = m_clients.getIterator();
1439 i.atEnd()==false; i++)
1441 RemoteClient *client = i.getNode()->getValue();
1442 std::string reliable_data;
1443 std::string unreliable_data;
1444 // Go through all objects in message buffer
1445 for(core::map<u16, core::list<ActiveObjectMessage>* >::Iterator
1446 j = buffered_messages.getIterator();
1447 j.atEnd()==false; j++)
1449 // If object is not known by client, skip it
1450 u16 id = j.getNode()->getKey();
1451 if(client->m_known_objects.find(id) == NULL)
1453 // Get message list of object
1454 core::list<ActiveObjectMessage>* list = j.getNode()->getValue();
1455 // Go through every message
1456 for(core::list<ActiveObjectMessage>::Iterator
1457 k = list->begin(); k != list->end(); k++)
1459 // Compose the full new data with header
1460 ActiveObjectMessage aom = *k;
1461 std::string new_data;
1464 writeU16((u8*)&buf[0], aom.id);
1465 new_data.append(buf, 2);
1467 new_data += serializeString(aom.datastring);
1468 // Add data to buffer
1470 reliable_data += new_data;
1472 unreliable_data += new_data;
1476 reliable_data and unreliable_data are now ready.
1479 if(reliable_data.size() > 0)
1481 SharedBuffer<u8> reply(2 + reliable_data.size());
1482 writeU16(&reply[0], TOCLIENT_ACTIVE_OBJECT_MESSAGES);
1483 memcpy((char*)&reply[2], reliable_data.c_str(),
1484 reliable_data.size());
1486 m_con.Send(client->peer_id, 0, reply, true);
1488 if(unreliable_data.size() > 0)
1490 SharedBuffer<u8> reply(2 + unreliable_data.size());
1491 writeU16(&reply[0], TOCLIENT_ACTIVE_OBJECT_MESSAGES);
1492 memcpy((char*)&reply[2], unreliable_data.c_str(),
1493 unreliable_data.size());
1494 // Send as unreliable
1495 m_con.Send(client->peer_id, 0, reply, false);
1498 /*if(reliable_data.size() > 0 || unreliable_data.size() > 0)
1500 infostream<<"Server: Size of object message data: "
1501 <<"reliable: "<<reliable_data.size()
1502 <<", unreliable: "<<unreliable_data.size()
1507 // Clear buffered_messages
1508 for(core::map<u16, core::list<ActiveObjectMessage>* >::Iterator
1509 i = buffered_messages.getIterator();
1510 i.atEnd()==false; i++)
1512 delete i.getNode()->getValue();
1516 } // enable_experimental
1519 Send queued-for-sending map edit events.
1522 // We will be accessing the environment and the connection
1523 JMutexAutoLock lock(m_env_mutex);
1524 JMutexAutoLock conlock(m_con_mutex);
1526 // Don't send too many at a time
1529 // Single change sending is disabled if queue size is not small
1530 bool disable_single_change_sending = false;
1531 if(m_unsent_map_edit_queue.size() >= 4)
1532 disable_single_change_sending = true;
1534 int event_count = m_unsent_map_edit_queue.size();
1536 // We'll log the amount of each
1539 while(m_unsent_map_edit_queue.size() != 0)
1541 MapEditEvent* event = m_unsent_map_edit_queue.pop_front();
1543 // Players far away from the change are stored here.
1544 // Instead of sending the changes, MapBlocks are set not sent
1546 core::list<u16> far_players;
1548 if(event->type == MEET_ADDNODE)
1550 //infostream<<"Server: MEET_ADDNODE"<<std::endl;
1551 prof.add("MEET_ADDNODE", 1);
1552 if(disable_single_change_sending)
1553 sendAddNode(event->p, event->n, event->already_known_by_peer,
1556 sendAddNode(event->p, event->n, event->already_known_by_peer,
1559 else if(event->type == MEET_REMOVENODE)
1561 //infostream<<"Server: MEET_REMOVENODE"<<std::endl;
1562 prof.add("MEET_REMOVENODE", 1);
1563 if(disable_single_change_sending)
1564 sendRemoveNode(event->p, event->already_known_by_peer,
1567 sendRemoveNode(event->p, event->already_known_by_peer,
1570 else if(event->type == MEET_BLOCK_NODE_METADATA_CHANGED)
1572 infostream<<"Server: MEET_BLOCK_NODE_METADATA_CHANGED"<<std::endl;
1573 prof.add("MEET_BLOCK_NODE_METADATA_CHANGED", 1);
1574 setBlockNotSent(event->p);
1576 else if(event->type == MEET_OTHER)
1578 infostream<<"Server: MEET_OTHER"<<std::endl;
1579 prof.add("MEET_OTHER", 1);
1580 for(core::map<v3s16, bool>::Iterator
1581 i = event->modified_blocks.getIterator();
1582 i.atEnd()==false; i++)
1584 v3s16 p = i.getNode()->getKey();
1590 prof.add("unknown", 1);
1591 infostream<<"WARNING: Server: Unknown MapEditEvent "
1592 <<((u32)event->type)<<std::endl;
1596 Set blocks not sent to far players
1598 if(far_players.size() > 0)
1600 // Convert list format to that wanted by SetBlocksNotSent
1601 core::map<v3s16, MapBlock*> modified_blocks2;
1602 for(core::map<v3s16, bool>::Iterator
1603 i = event->modified_blocks.getIterator();
1604 i.atEnd()==false; i++)
1606 v3s16 p = i.getNode()->getKey();
1607 modified_blocks2.insert(p,
1608 m_env->getMap().getBlockNoCreateNoEx(p));
1610 // Set blocks not sent
1611 for(core::list<u16>::Iterator
1612 i = far_players.begin();
1613 i != far_players.end(); i++)
1616 RemoteClient *client = getClient(peer_id);
1619 client->SetBlocksNotSent(modified_blocks2);
1625 /*// Don't send too many at a time
1627 if(count >= 1 && m_unsent_map_edit_queue.size() < 100)
1631 if(event_count >= 5){
1632 infostream<<"Server: MapEditEvents:"<<std::endl;
1633 prof.print(infostream);
1634 } else if(event_count != 0){
1635 verbosestream<<"Server: MapEditEvents:"<<std::endl;
1636 prof.print(verbosestream);
1642 Trigger emergethread (it somehow gets to a non-triggered but
1643 bysy state sometimes)
1646 float &counter = m_emergethread_trigger_timer;
1652 for (int i = 0; i != m_emerge->emergethread.size(); i++)
1653 m_emerge->emergethread[i]->trigger();
1655 // Update m_enable_rollback_recording here too
1656 m_enable_rollback_recording =
1657 g_settings->getBool("enable_rollback_recording");
1661 // Save map, players and auth stuff
1663 float &counter = m_savemap_timer;
1665 if(counter >= g_settings->getFloat("server_map_save_interval"))
1668 JMutexAutoLock lock(m_env_mutex);
1670 ScopeProfiler sp(g_profiler, "Server: saving stuff");
1673 if(m_banmanager.isModified())
1674 m_banmanager.save();
1676 // Save changed parts of map
1677 m_env->getMap().save(MOD_STATE_WRITE_NEEDED);
1680 m_env->serializePlayers(m_path_world);
1682 // Save environment metadata
1683 m_env->saveMeta(m_path_world);
1688 void Server::Receive()
1690 DSTACK(__FUNCTION_NAME);
1691 SharedBuffer<u8> data;
1696 JMutexAutoLock conlock(m_con_mutex);
1697 datasize = m_con.Receive(peer_id, data);
1700 // This has to be called so that the client list gets synced
1701 // with the peer list of the connection
1702 handlePeerChanges();
1704 ProcessData(*data, datasize, peer_id);
1706 catch(con::InvalidIncomingDataException &e)
1708 infostream<<"Server::Receive(): "
1709 "InvalidIncomingDataException: what()="
1710 <<e.what()<<std::endl;
1712 catch(con::PeerNotFoundException &e)
1714 //NOTE: This is not needed anymore
1716 // The peer has been disconnected.
1717 // Find the associated player and remove it.
1719 /*JMutexAutoLock envlock(m_env_mutex);
1721 infostream<<"ServerThread: peer_id="<<peer_id
1722 <<" has apparently closed connection. "
1723 <<"Removing player."<<std::endl;
1725 m_env->removePlayer(peer_id);*/
1729 void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
1731 DSTACK(__FUNCTION_NAME);
1732 // Environment is locked first.
1733 JMutexAutoLock envlock(m_env_mutex);
1734 JMutexAutoLock conlock(m_con_mutex);
1736 ScopeProfiler sp(g_profiler, "Server::ProcessData");
1739 Address address = m_con.GetPeerAddress(peer_id);
1740 std::string addr_s = address.serializeString();
1742 // drop player if is ip is banned
1743 if(m_banmanager.isIpBanned(addr_s)){
1744 infostream<<"Server: A banned client tried to connect from "
1745 <<addr_s<<"; banned name was "
1746 <<m_banmanager.getBanName(addr_s)<<std::endl;
1747 // This actually doesn't seem to transfer to the client
1748 SendAccessDenied(m_con, peer_id,
1749 L"Your ip is banned. Banned name was "
1750 +narrow_to_wide(m_banmanager.getBanName(addr_s)));
1751 m_con.DeletePeer(peer_id);
1755 catch(con::PeerNotFoundException &e)
1757 infostream<<"Server::ProcessData(): Cancelling: peer "
1758 <<peer_id<<" not found"<<std::endl;
1762 std::string addr_s = m_con.GetPeerAddress(peer_id).serializeString();
1764 u8 peer_ser_ver = getClient(peer_id)->serialization_version;
1772 ToServerCommand command = (ToServerCommand)readU16(&data[0]);
1774 if(command == TOSERVER_INIT)
1776 // [0] u16 TOSERVER_INIT
1777 // [2] u8 SER_FMT_VER_HIGHEST
1778 // [3] u8[20] player_name
1779 // [23] u8[28] password <--- can be sent without this, from old versions
1781 if(datasize < 2+1+PLAYERNAME_SIZE)
1784 verbosestream<<"Server: Got TOSERVER_INIT from "
1785 <<peer_id<<std::endl;
1787 // First byte after command is maximum supported
1788 // serialization version
1789 u8 client_max = data[2];
1790 u8 our_max = SER_FMT_VER_HIGHEST;
1791 // Use the highest version supported by both
1792 u8 deployed = core::min_(client_max, our_max);
1793 // If it's lower than the lowest supported, give up.
1794 if(deployed < SER_FMT_VER_LOWEST)
1795 deployed = SER_FMT_VER_INVALID;
1797 //peer->serialization_version = deployed;
1798 getClient(peer_id)->pending_serialization_version = deployed;
1800 if(deployed == SER_FMT_VER_INVALID)
1802 actionstream<<"Server: A mismatched client tried to connect from "
1803 <<addr_s<<std::endl;
1804 infostream<<"Server: Cannot negotiate "
1805 "serialization version with peer "
1806 <<peer_id<<std::endl;
1807 SendAccessDenied(m_con, peer_id, std::wstring(
1808 L"Your client's version is not supported.\n"
1809 L"Server version is ")
1810 + narrow_to_wide(VERSION_STRING) + L"."
1816 Read and check network protocol version
1819 u16 min_net_proto_version = 0;
1820 if(datasize >= 2+1+PLAYERNAME_SIZE+PASSWORD_SIZE+2)
1821 min_net_proto_version = readU16(&data[2+1+PLAYERNAME_SIZE+PASSWORD_SIZE]);
1823 // Use same version as minimum and maximum if maximum version field
1824 // doesn't exist (backwards compatibility)
1825 u16 max_net_proto_version = min_net_proto_version;
1826 if(datasize >= 2+1+PLAYERNAME_SIZE+PASSWORD_SIZE+2+2)
1827 max_net_proto_version = readU16(&data[2+1+PLAYERNAME_SIZE+PASSWORD_SIZE+2]);
1829 // Start with client's maximum version
1830 u16 net_proto_version = max_net_proto_version;
1832 // Figure out a working version if it is possible at all
1833 if(max_net_proto_version >= SERVER_PROTOCOL_VERSION_MIN ||
1834 min_net_proto_version <= SERVER_PROTOCOL_VERSION_MAX)
1836 // If maximum is larger than our maximum, go with our maximum
1837 if(max_net_proto_version > SERVER_PROTOCOL_VERSION_MAX)
1838 net_proto_version = SERVER_PROTOCOL_VERSION_MAX;
1839 // Else go with client's maximum
1841 net_proto_version = max_net_proto_version;
1844 verbosestream<<"Server: "<<peer_id<<" Protocol version: min: "
1845 <<min_net_proto_version<<", max: "<<max_net_proto_version
1846 <<", chosen: "<<net_proto_version<<std::endl;
1848 getClient(peer_id)->net_proto_version = net_proto_version;
1850 if(net_proto_version < SERVER_PROTOCOL_VERSION_MIN ||
1851 net_proto_version > SERVER_PROTOCOL_VERSION_MAX)
1853 actionstream<<"Server: A mismatched client tried to connect from "<<addr_s
1855 SendAccessDenied(m_con, peer_id, std::wstring(
1856 L"Your client's version is not supported.\n"
1857 L"Server version is ")
1858 + narrow_to_wide(VERSION_STRING) + L",\n"
1859 + L"server's PROTOCOL_VERSION is "
1860 + narrow_to_wide(itos(SERVER_PROTOCOL_VERSION_MIN))
1862 + narrow_to_wide(itos(SERVER_PROTOCOL_VERSION_MAX))
1863 + L", client's PROTOCOL_VERSION is "
1864 + narrow_to_wide(itos(min_net_proto_version))
1866 + narrow_to_wide(itos(max_net_proto_version))
1871 if(g_settings->getBool("strict_protocol_version_checking"))
1873 if(net_proto_version != LATEST_PROTOCOL_VERSION)
1875 actionstream<<"Server: A mismatched (strict) client tried to "
1876 <<"connect from "<<addr_s<<std::endl;
1877 SendAccessDenied(m_con, peer_id, std::wstring(
1878 L"Your client's version is not supported.\n"
1879 L"Server version is ")
1880 + narrow_to_wide(VERSION_STRING) + L",\n"
1881 + L"server's PROTOCOL_VERSION (strict) is "
1882 + narrow_to_wide(itos(LATEST_PROTOCOL_VERSION))
1883 + L", client's PROTOCOL_VERSION is "
1884 + narrow_to_wide(itos(min_net_proto_version))
1886 + narrow_to_wide(itos(max_net_proto_version))
1897 char playername[PLAYERNAME_SIZE];
1898 for(u32 i=0; i<PLAYERNAME_SIZE-1; i++)
1900 playername[i] = data[3+i];
1902 playername[PLAYERNAME_SIZE-1] = 0;
1904 if(playername[0]=='\0')
1906 actionstream<<"Server: Player with an empty name "
1907 <<"tried to connect from "<<addr_s<<std::endl;
1908 SendAccessDenied(m_con, peer_id,
1913 if(string_allowed(playername, PLAYERNAME_ALLOWED_CHARS)==false)
1915 actionstream<<"Server: Player with an invalid name "
1916 <<"tried to connect from "<<addr_s<<std::endl;
1917 SendAccessDenied(m_con, peer_id,
1918 L"Name contains unallowed characters");
1922 infostream<<"Server: New connection: \""<<playername<<"\" from "
1923 <<m_con.GetPeerAddress(peer_id).serializeString()<<std::endl;
1926 char given_password[PASSWORD_SIZE];
1927 if(datasize < 2+1+PLAYERNAME_SIZE+PASSWORD_SIZE)
1929 // old version - assume blank password
1930 given_password[0] = 0;
1934 for(u32 i=0; i<PASSWORD_SIZE-1; i++)
1936 given_password[i] = data[23+i];
1938 given_password[PASSWORD_SIZE-1] = 0;
1941 if(!base64_is_valid(given_password)){
1942 infostream<<"Server: "<<playername
1943 <<" supplied invalid password hash"<<std::endl;
1944 SendAccessDenied(m_con, peer_id, L"Invalid password hash");
1948 std::string checkpwd; // Password hash to check against
1949 bool has_auth = scriptapi_get_auth(m_lua, playername, &checkpwd, NULL);
1951 // If no authentication info exists for user, create it
1953 if(!isSingleplayer() &&
1954 g_settings->getBool("disallow_empty_password") &&
1955 std::string(given_password) == ""){
1956 SendAccessDenied(m_con, peer_id, L"Empty passwords are "
1957 L"disallowed. Set a password and try again.");
1960 std::wstring raw_default_password =
1961 narrow_to_wide(g_settings->get("default_password"));
1962 std::string initial_password =
1963 translatePassword(playername, raw_default_password);
1965 // If default_password is empty, allow any initial password
1966 if (raw_default_password.length() == 0)
1967 initial_password = given_password;
1969 scriptapi_create_auth(m_lua, playername, initial_password);
1972 has_auth = scriptapi_get_auth(m_lua, playername, &checkpwd, NULL);
1975 SendAccessDenied(m_con, peer_id, L"Not allowed to login");
1979 if(given_password != checkpwd){
1980 infostream<<"Server: peer_id="<<peer_id
1981 <<": supplied invalid password for "
1982 <<playername<<std::endl;
1983 SendAccessDenied(m_con, peer_id, L"Invalid password");
1987 // Do not allow multiple players in simple singleplayer mode.
1988 // This isn't a perfect way to do it, but will suffice for now.
1989 if(m_simple_singleplayer_mode && m_clients.size() > 1){
1990 infostream<<"Server: Not allowing another client to connect in"
1991 <<" simple singleplayer mode"<<std::endl;
1992 SendAccessDenied(m_con, peer_id,
1993 L"Running in simple singleplayer mode.");
1997 // Enforce user limit.
1998 // Don't enforce for users that have some admin right
1999 if(m_clients.size() >= g_settings->getU16("max_users") &&
2000 !checkPriv(playername, "server") &&
2001 !checkPriv(playername, "ban") &&
2002 !checkPriv(playername, "privs") &&
2003 !checkPriv(playername, "password") &&
2004 playername != g_settings->get("name"))
2006 actionstream<<"Server: "<<playername<<" tried to join, but there"
2007 <<" are already max_users="
2008 <<g_settings->getU16("max_users")<<" players."<<std::endl;
2009 SendAccessDenied(m_con, peer_id, L"Too many users.");
2014 PlayerSAO *playersao = emergePlayer(playername, peer_id);
2016 // If failed, cancel
2017 if(playersao == NULL)
2019 errorstream<<"Server: peer_id="<<peer_id
2020 <<": failed to emerge player"<<std::endl;
2025 Answer with a TOCLIENT_INIT
2028 SharedBuffer<u8> reply(2+1+6+8+4);
2029 writeU16(&reply[0], TOCLIENT_INIT);
2030 writeU8(&reply[2], deployed);
2031 writeV3S16(&reply[2+1], floatToInt(playersao->getPlayer()->getPosition()+v3f(0,BS/2,0), BS));
2032 writeU64(&reply[2+1+6], m_env->getServerMap().getSeed());
2033 writeF1000(&reply[2+1+6+8], g_settings->getFloat("dedicated_server_step"));
2036 m_con.Send(peer_id, 0, reply, true);
2040 Send complete position information
2042 SendMovePlayer(peer_id);
2047 if(command == TOSERVER_INIT2)
2049 verbosestream<<"Server: Got TOSERVER_INIT2 from "
2050 <<peer_id<<std::endl;
2052 Player *player = m_env->getPlayer(peer_id);
2054 verbosestream<<"Server: TOSERVER_INIT2: "
2055 <<"Player not found; ignoring."<<std::endl;
2059 RemoteClient *client = getClient(peer_id);
2060 client->serialization_version =
2061 getClient(peer_id)->pending_serialization_version;
2064 Send some initialization data
2067 infostream<<"Server: Sending content to "
2068 <<getPlayerName(peer_id)<<std::endl;
2070 // Send player movement settings
2071 SendMovement(m_con, peer_id);
2073 // Send item definitions
2074 SendItemDef(m_con, peer_id, m_itemdef);
2076 // Send node definitions
2077 SendNodeDef(m_con, peer_id, m_nodedef, client->net_proto_version);
2079 // Send media announcement
2080 sendMediaAnnouncement(peer_id);
2083 SendPlayerPrivileges(peer_id);
2085 // Send inventory formspec
2086 SendPlayerInventoryFormspec(peer_id);
2089 UpdateCrafting(peer_id);
2090 SendInventory(peer_id);
2093 if(g_settings->getBool("enable_damage"))
2094 SendPlayerHP(peer_id);
2096 // Send detached inventories
2097 sendDetachedInventories(peer_id);
2099 // Show death screen if necessary
2101 SendDeathscreen(m_con, peer_id, false, v3f(0,0,0));
2105 SharedBuffer<u8> data = makePacket_TOCLIENT_TIME_OF_DAY(
2106 m_env->getTimeOfDay(), g_settings->getFloat("time_speed"));
2107 m_con.Send(peer_id, 0, data, true);
2110 // Note things in chat if not in simple singleplayer mode
2111 if(!m_simple_singleplayer_mode)
2113 // Send information about server to player in chat
2114 SendChatMessage(peer_id, getStatusString());
2116 // Send information about joining in chat
2118 std::wstring name = L"unknown";
2119 Player *player = m_env->getPlayer(peer_id);
2121 name = narrow_to_wide(player->getName());
2123 std::wstring message;
2126 message += L" joined the game.";
2127 BroadcastChatMessage(message);
2131 // Warnings about protocol version can be issued here
2132 if(getClient(peer_id)->net_proto_version < LATEST_PROTOCOL_VERSION)
2134 SendChatMessage(peer_id, L"# Server: WARNING: YOUR CLIENT'S "
2135 L"VERSION MAY NOT BE FULLY COMPATIBLE WITH THIS SERVER!");
2142 std::ostringstream os(std::ios_base::binary);
2143 for(core::map<u16, RemoteClient*>::Iterator
2144 i = m_clients.getIterator();
2145 i.atEnd() == false; i++)
2147 RemoteClient *client = i.getNode()->getValue();
2148 assert(client->peer_id == i.getNode()->getKey());
2149 if(client->serialization_version == SER_FMT_VER_INVALID)
2152 Player *player = m_env->getPlayer(client->peer_id);
2155 // Get name of player
2156 os<<player->getName()<<" ";
2159 actionstream<<player->getName()<<" joins game. List of players: "
2160 <<os.str()<<std::endl;
2166 if(peer_ser_ver == SER_FMT_VER_INVALID)
2168 infostream<<"Server::ProcessData(): Cancelling: Peer"
2169 " serialization format invalid or not initialized."
2170 " Skipping incoming command="<<command<<std::endl;
2174 Player *player = m_env->getPlayer(peer_id);
2176 infostream<<"Server::ProcessData(): Cancelling: "
2177 "No player for peer_id="<<peer_id
2182 PlayerSAO *playersao = player->getPlayerSAO();
2183 if(playersao == NULL){
2184 infostream<<"Server::ProcessData(): Cancelling: "
2185 "No player object for peer_id="<<peer_id
2190 if(command == TOSERVER_PLAYERPOS)
2192 if(datasize < 2+12+12+4+4)
2196 v3s32 ps = readV3S32(&data[start+2]);
2197 v3s32 ss = readV3S32(&data[start+2+12]);
2198 f32 pitch = (f32)readS32(&data[2+12+12]) / 100.0;
2199 f32 yaw = (f32)readS32(&data[2+12+12+4]) / 100.0;
2201 if(datasize >= 2+12+12+4+4+4)
2202 keyPressed = (u32)readU32(&data[2+12+12+4+4]);
2203 v3f position((f32)ps.X/100., (f32)ps.Y/100., (f32)ps.Z/100.);
2204 v3f speed((f32)ss.X/100., (f32)ss.Y/100., (f32)ss.Z/100.);
2205 pitch = wrapDegrees(pitch);
2206 yaw = wrapDegrees(yaw);
2208 player->setPosition(position);
2209 player->setSpeed(speed);
2210 player->setPitch(pitch);
2211 player->setYaw(yaw);
2212 player->keyPressed=keyPressed;
2213 player->control.up = (bool)(keyPressed&1);
2214 player->control.down = (bool)(keyPressed&2);
2215 player->control.left = (bool)(keyPressed&4);
2216 player->control.right = (bool)(keyPressed&8);
2217 player->control.jump = (bool)(keyPressed&16);
2218 player->control.aux1 = (bool)(keyPressed&32);
2219 player->control.sneak = (bool)(keyPressed&64);
2220 player->control.LMB = (bool)(keyPressed&128);
2221 player->control.RMB = (bool)(keyPressed&256);
2223 /*infostream<<"Server::ProcessData(): Moved player "<<peer_id<<" to "
2224 <<"("<<position.X<<","<<position.Y<<","<<position.Z<<")"
2225 <<" pitch="<<pitch<<" yaw="<<yaw<<std::endl;*/
2227 else if(command == TOSERVER_GOTBLOCKS)
2240 u16 count = data[2];
2241 for(u16 i=0; i<count; i++)
2243 if((s16)datasize < 2+1+(i+1)*6)
2244 throw con::InvalidIncomingDataException
2245 ("GOTBLOCKS length is too short");
2246 v3s16 p = readV3S16(&data[2+1+i*6]);
2247 /*infostream<<"Server: GOTBLOCKS ("
2248 <<p.X<<","<<p.Y<<","<<p.Z<<")"<<std::endl;*/
2249 RemoteClient *client = getClient(peer_id);
2250 client->GotBlock(p);
2253 else if(command == TOSERVER_DELETEDBLOCKS)
2266 u16 count = data[2];
2267 for(u16 i=0; i<count; i++)
2269 if((s16)datasize < 2+1+(i+1)*6)
2270 throw con::InvalidIncomingDataException
2271 ("DELETEDBLOCKS length is too short");
2272 v3s16 p = readV3S16(&data[2+1+i*6]);
2273 /*infostream<<"Server: DELETEDBLOCKS ("
2274 <<p.X<<","<<p.Y<<","<<p.Z<<")"<<std::endl;*/
2275 RemoteClient *client = getClient(peer_id);
2276 client->SetBlockNotSent(p);
2279 else if(command == TOSERVER_CLICK_OBJECT)
2281 infostream<<"Server: CLICK_OBJECT not supported anymore"<<std::endl;
2284 else if(command == TOSERVER_CLICK_ACTIVEOBJECT)
2286 infostream<<"Server: CLICK_ACTIVEOBJECT not supported anymore"<<std::endl;
2289 else if(command == TOSERVER_GROUND_ACTION)
2291 infostream<<"Server: GROUND_ACTION not supported anymore"<<std::endl;
2295 else if(command == TOSERVER_RELEASE)
2297 infostream<<"Server: RELEASE not supported anymore"<<std::endl;
2300 else if(command == TOSERVER_SIGNTEXT)
2302 infostream<<"Server: SIGNTEXT not supported anymore"
2306 else if(command == TOSERVER_SIGNNODETEXT)
2308 infostream<<"Server: SIGNNODETEXT not supported anymore"
2312 else if(command == TOSERVER_INVENTORY_ACTION)
2314 // Strip command and create a stream
2315 std::string datastring((char*)&data[2], datasize-2);
2316 verbosestream<<"TOSERVER_INVENTORY_ACTION: data="<<datastring<<std::endl;
2317 std::istringstream is(datastring, std::ios_base::binary);
2319 InventoryAction *a = InventoryAction::deSerialize(is);
2322 infostream<<"TOSERVER_INVENTORY_ACTION: "
2323 <<"InventoryAction::deSerialize() returned NULL"
2328 // If something goes wrong, this player is to blame
2329 RollbackScopeActor rollback_scope(m_rollback,
2330 std::string("player:")+player->getName());
2333 Note: Always set inventory not sent, to repair cases
2334 where the client made a bad prediction.
2338 Handle restrictions and special cases of the move action
2340 if(a->getType() == IACTION_MOVE)
2342 IMoveAction *ma = (IMoveAction*)a;
2344 ma->from_inv.applyCurrentPlayer(player->getName());
2345 ma->to_inv.applyCurrentPlayer(player->getName());
2347 setInventoryModified(ma->from_inv);
2348 setInventoryModified(ma->to_inv);
2350 bool from_inv_is_current_player =
2351 (ma->from_inv.type == InventoryLocation::PLAYER) &&
2352 (ma->from_inv.name == player->getName());
2354 bool to_inv_is_current_player =
2355 (ma->to_inv.type == InventoryLocation::PLAYER) &&
2356 (ma->to_inv.name == player->getName());
2359 Disable moving items out of craftpreview
2361 if(ma->from_list == "craftpreview")
2363 infostream<<"Ignoring IMoveAction from "
2364 <<(ma->from_inv.dump())<<":"<<ma->from_list
2365 <<" to "<<(ma->to_inv.dump())<<":"<<ma->to_list
2366 <<" because src is "<<ma->from_list<<std::endl;
2372 Disable moving items into craftresult and craftpreview
2374 if(ma->to_list == "craftpreview" || ma->to_list == "craftresult")
2376 infostream<<"Ignoring IMoveAction from "
2377 <<(ma->from_inv.dump())<<":"<<ma->from_list
2378 <<" to "<<(ma->to_inv.dump())<<":"<<ma->to_list
2379 <<" because dst is "<<ma->to_list<<std::endl;
2384 // Disallow moving items in elsewhere than player's inventory
2385 // if not allowed to interact
2386 if(!checkPriv(player->getName(), "interact") &&
2387 (!from_inv_is_current_player ||
2388 !to_inv_is_current_player))
2390 infostream<<"Cannot move outside of player's inventory: "
2391 <<"No interact privilege"<<std::endl;
2397 Handle restrictions and special cases of the drop action
2399 else if(a->getType() == IACTION_DROP)
2401 IDropAction *da = (IDropAction*)a;
2403 da->from_inv.applyCurrentPlayer(player->getName());
2405 setInventoryModified(da->from_inv);
2407 // Disallow dropping items if not allowed to interact
2408 if(!checkPriv(player->getName(), "interact"))
2415 Handle restrictions and special cases of the craft action
2417 else if(a->getType() == IACTION_CRAFT)
2419 ICraftAction *ca = (ICraftAction*)a;
2421 ca->craft_inv.applyCurrentPlayer(player->getName());
2423 setInventoryModified(ca->craft_inv);
2425 //bool craft_inv_is_current_player =
2426 // (ca->craft_inv.type == InventoryLocation::PLAYER) &&
2427 // (ca->craft_inv.name == player->getName());
2429 // Disallow crafting if not allowed to interact
2430 if(!checkPriv(player->getName(), "interact"))
2432 infostream<<"Cannot craft: "
2433 <<"No interact privilege"<<std::endl;
2440 a->apply(this, playersao, this);
2444 else if(command == TOSERVER_CHAT_MESSAGE)
2452 std::string datastring((char*)&data[2], datasize-2);
2453 std::istringstream is(datastring, std::ios_base::binary);
2456 is.read((char*)buf, 2);
2457 u16 len = readU16(buf);
2459 std::wstring message;
2460 for(u16 i=0; i<len; i++)
2462 is.read((char*)buf, 2);
2463 message += (wchar_t)readU16(buf);
2466 // If something goes wrong, this player is to blame
2467 RollbackScopeActor rollback_scope(m_rollback,
2468 std::string("player:")+player->getName());
2470 // Get player name of this client
2471 std::wstring name = narrow_to_wide(player->getName());
2474 bool ate = scriptapi_on_chat_message(m_lua, player->getName(),
2475 wide_to_narrow(message));
2476 // If script ate the message, don't proceed
2480 // Line to send to players
2482 // Whether to send to the player that sent the line
2483 bool send_to_sender = false;
2484 // Whether to send to other players
2485 bool send_to_others = false;
2487 // Commands are implemented in Lua, so only catch invalid
2488 // commands that were not "eaten" and send an error back
2489 if(message[0] == L'/')
2491 message = message.substr(1);
2492 send_to_sender = true;
2493 if(message.length() == 0)
2494 line += L"-!- Empty command";
2496 line += L"-!- Invalid command: " + str_split(message, L' ')[0];
2500 if(checkPriv(player->getName(), "shout")){
2505 send_to_others = true;
2507 line += L"-!- You don't have permission to shout.";
2508 send_to_sender = true;
2515 actionstream<<"CHAT: "<<wide_to_narrow(line)<<std::endl;
2518 Send the message to clients
2520 for(core::map<u16, RemoteClient*>::Iterator
2521 i = m_clients.getIterator();
2522 i.atEnd() == false; i++)
2524 // Get client and check that it is valid
2525 RemoteClient *client = i.getNode()->getValue();
2526 assert(client->peer_id == i.getNode()->getKey());
2527 if(client->serialization_version == SER_FMT_VER_INVALID)
2531 bool sender_selected = (peer_id == client->peer_id);
2532 if(sender_selected == true && send_to_sender == false)
2534 if(sender_selected == false && send_to_others == false)
2537 SendChatMessage(client->peer_id, line);
2541 else if(command == TOSERVER_DAMAGE)
2543 std::string datastring((char*)&data[2], datasize-2);
2544 std::istringstream is(datastring, std::ios_base::binary);
2545 u8 damage = readU8(is);
2547 if(g_settings->getBool("enable_damage"))
2549 actionstream<<player->getName()<<" damaged by "
2550 <<(int)damage<<" hp at "<<PP(player->getPosition()/BS)
2553 playersao->setHP(playersao->getHP() - damage);
2555 if(playersao->getHP() == 0 && playersao->m_hp_not_sent)
2558 if(playersao->m_hp_not_sent)
2559 SendPlayerHP(peer_id);
2562 else if(command == TOSERVER_PASSWORD)
2565 [0] u16 TOSERVER_PASSWORD
2566 [2] u8[28] old password
2567 [30] u8[28] new password
2570 if(datasize != 2+PASSWORD_SIZE*2)
2572 /*char password[PASSWORD_SIZE];
2573 for(u32 i=0; i<PASSWORD_SIZE-1; i++)
2574 password[i] = data[2+i];
2575 password[PASSWORD_SIZE-1] = 0;*/
2577 for(u32 i=0; i<PASSWORD_SIZE-1; i++)
2585 for(u32 i=0; i<PASSWORD_SIZE-1; i++)
2587 char c = data[2+PASSWORD_SIZE+i];
2593 if(!base64_is_valid(newpwd)){
2594 infostream<<"Server: "<<player->getName()<<" supplied invalid password hash"<<std::endl;
2595 // Wrong old password supplied!!
2596 SendChatMessage(peer_id, L"Invalid new password hash supplied. Password NOT changed.");
2600 infostream<<"Server: Client requests a password change from "
2601 <<"'"<<oldpwd<<"' to '"<<newpwd<<"'"<<std::endl;
2603 std::string playername = player->getName();
2605 std::string checkpwd;
2606 scriptapi_get_auth(m_lua, playername, &checkpwd, NULL);
2608 if(oldpwd != checkpwd)
2610 infostream<<"Server: invalid old password"<<std::endl;
2611 // Wrong old password supplied!!
2612 SendChatMessage(peer_id, L"Invalid old password supplied. Password NOT changed.");
2616 bool success = scriptapi_set_password(m_lua, playername, newpwd);
2618 actionstream<<player->getName()<<" changes password"<<std::endl;
2619 SendChatMessage(peer_id, L"Password change successful.");
2621 actionstream<<player->getName()<<" tries to change password but "
2622 <<"it fails"<<std::endl;
2623 SendChatMessage(peer_id, L"Password change failed or inavailable.");
2626 else if(command == TOSERVER_PLAYERITEM)
2631 u16 item = readU16(&data[2]);
2632 playersao->setWieldIndex(item);
2634 else if(command == TOSERVER_RESPAWN)
2636 if(player->hp != 0 || !g_settings->getBool("enable_damage"))
2639 RespawnPlayer(peer_id);
2641 actionstream<<player->getName()<<" respawns at "
2642 <<PP(player->getPosition()/BS)<<std::endl;
2644 // ActiveObject is added to environment in AsyncRunStep after
2645 // the previous addition has been succesfully removed
2647 else if(command == TOSERVER_REQUEST_MEDIA) {
2648 std::string datastring((char*)&data[2], datasize-2);
2649 std::istringstream is(datastring, std::ios_base::binary);
2651 core::list<MediaRequest> tosend;
2652 u16 numfiles = readU16(is);
2654 infostream<<"Sending "<<numfiles<<" files to "
2655 <<getPlayerName(peer_id)<<std::endl;
2656 verbosestream<<"TOSERVER_REQUEST_MEDIA: "<<std::endl;
2658 for(int i = 0; i < numfiles; i++) {
2659 std::string name = deSerializeString(is);
2660 tosend.push_back(MediaRequest(name));
2661 verbosestream<<"TOSERVER_REQUEST_MEDIA: requested file "
2665 sendRequestedMedia(peer_id, tosend);
2667 // Now the client should know about everything
2668 // (definitions and files)
2669 getClient(peer_id)->definitions_sent = true;
2671 else if(command == TOSERVER_RECEIVED_MEDIA) {
2672 getClient(peer_id)->definitions_sent = true;
2674 else if(command == TOSERVER_INTERACT)
2676 std::string datastring((char*)&data[2], datasize-2);
2677 std::istringstream is(datastring, std::ios_base::binary);
2683 [5] u32 length of the next item
2684 [9] serialized PointedThing
2686 0: start digging (from undersurface) or use
2687 1: stop digging (all parameters ignored)
2688 2: digging completed
2689 3: place block or item (to abovesurface)
2692 u8 action = readU8(is);
2693 u16 item_i = readU16(is);
2694 std::istringstream tmp_is(deSerializeLongString(is), std::ios::binary);
2695 PointedThing pointed;
2696 pointed.deSerialize(tmp_is);
2698 verbosestream<<"TOSERVER_INTERACT: action="<<(int)action<<", item="
2699 <<item_i<<", pointed="<<pointed.dump()<<std::endl;
2703 verbosestream<<"TOSERVER_INTERACT: "<<player->getName()
2704 <<" tried to interact, but is dead!"<<std::endl;
2708 v3f player_pos = playersao->getLastGoodPosition();
2710 // Update wielded item
2711 playersao->setWieldIndex(item_i);
2713 // Get pointed to node (undefined if not POINTEDTYPE_NODE)
2714 v3s16 p_under = pointed.node_undersurface;
2715 v3s16 p_above = pointed.node_abovesurface;
2717 // Get pointed to object (NULL if not POINTEDTYPE_OBJECT)
2718 ServerActiveObject *pointed_object = NULL;
2719 if(pointed.type == POINTEDTHING_OBJECT)
2721 pointed_object = m_env->getActiveObject(pointed.object_id);
2722 if(pointed_object == NULL)
2724 verbosestream<<"TOSERVER_INTERACT: "
2725 "pointed object is NULL"<<std::endl;
2731 v3f pointed_pos_under = player_pos;
2732 v3f pointed_pos_above = player_pos;
2733 if(pointed.type == POINTEDTHING_NODE)
2735 pointed_pos_under = intToFloat(p_under, BS);
2736 pointed_pos_above = intToFloat(p_above, BS);
2738 else if(pointed.type == POINTEDTHING_OBJECT)
2740 pointed_pos_under = pointed_object->getBasePosition();
2741 pointed_pos_above = pointed_pos_under;
2745 Check that target is reasonably close
2746 (only when digging or placing things)
2748 if(action == 0 || action == 2 || action == 3)
2750 float d = player_pos.getDistanceFrom(pointed_pos_under);
2751 float max_d = BS * 14; // Just some large enough value
2753 actionstream<<"Player "<<player->getName()
2754 <<" tried to access "<<pointed.dump()
2756 <<"d="<<d<<", max_d="<<max_d
2757 <<". ignoring."<<std::endl;
2758 // Re-send block to revert change on client-side
2759 RemoteClient *client = getClient(peer_id);
2760 v3s16 blockpos = getNodeBlockPos(floatToInt(pointed_pos_under, BS));
2761 client->SetBlockNotSent(blockpos);
2768 Make sure the player is allowed to do it
2770 if(!checkPriv(player->getName(), "interact"))
2772 actionstream<<player->getName()<<" attempted to interact with "
2773 <<pointed.dump()<<" without 'interact' privilege"
2775 // Re-send block to revert change on client-side
2776 RemoteClient *client = getClient(peer_id);
2777 // Digging completed -> under
2779 v3s16 blockpos = getNodeBlockPos(floatToInt(pointed_pos_under, BS));
2780 client->SetBlockNotSent(blockpos);
2782 // Placement -> above
2784 v3s16 blockpos = getNodeBlockPos(floatToInt(pointed_pos_above, BS));
2785 client->SetBlockNotSent(blockpos);
2791 If something goes wrong, this player is to blame
2793 RollbackScopeActor rollback_scope(m_rollback,
2794 std::string("player:")+player->getName());
2797 0: start digging or punch object
2801 if(pointed.type == POINTEDTHING_NODE)
2804 NOTE: This can be used in the future to check if
2805 somebody is cheating, by checking the timing.
2807 MapNode n(CONTENT_IGNORE);
2810 n = m_env->getMap().getNode(p_under);
2812 catch(InvalidPositionException &e)
2814 infostream<<"Server: Not punching: Node not found."
2815 <<" Adding block to emerge queue."
2817 m_emerge->enqueueBlockEmerge(peer_id, getNodeBlockPos(p_above), false);
2819 if(n.getContent() != CONTENT_IGNORE)
2820 scriptapi_node_on_punch(m_lua, p_under, n, playersao);
2822 playersao->noCheatDigStart(p_under);
2824 else if(pointed.type == POINTEDTHING_OBJECT)
2826 // Skip if object has been removed
2827 if(pointed_object->m_removed)
2830 actionstream<<player->getName()<<" punches object "
2831 <<pointed.object_id<<": "
2832 <<pointed_object->getDescription()<<std::endl;
2834 ItemStack punchitem = playersao->getWieldedItem();
2835 ToolCapabilities toolcap =
2836 punchitem.getToolCapabilities(m_itemdef);
2837 v3f dir = (pointed_object->getBasePosition() -
2838 (player->getPosition() + player->getEyeOffset())
2840 float time_from_last_punch =
2841 playersao->resetTimeFromLastPunch();
2842 pointed_object->punch(dir, &toolcap, playersao,
2843 time_from_last_punch);
2851 else if(action == 1)
2856 2: Digging completed
2858 else if(action == 2)
2860 // Only digging of nodes
2861 if(pointed.type == POINTEDTHING_NODE)
2863 MapNode n(CONTENT_IGNORE);
2866 n = m_env->getMap().getNode(p_under);
2868 catch(InvalidPositionException &e)
2870 infostream<<"Server: Not finishing digging: Node not found."
2871 <<" Adding block to emerge queue."
2873 m_emerge->enqueueBlockEmerge(peer_id, getNodeBlockPos(p_above), false);
2876 /* Cheat prevention */
2877 bool is_valid_dig = true;
2878 if(!isSingleplayer() && !g_settings->getBool("disable_anticheat"))
2880 v3s16 nocheat_p = playersao->getNoCheatDigPos();
2881 float nocheat_t = playersao->getNoCheatDigTime();
2882 playersao->noCheatDigEnd();
2883 // If player didn't start digging this, ignore dig
2884 if(nocheat_p != p_under){
2885 infostream<<"Server: NoCheat: "<<player->getName()
2886 <<" started digging "
2887 <<PP(nocheat_p)<<" and completed digging "
2888 <<PP(p_under)<<"; not digging."<<std::endl;
2889 is_valid_dig = false;
2891 // Get player's wielded item
2892 ItemStack playeritem;
2893 InventoryList *mlist = playersao->getInventory()->getList("main");
2895 playeritem = mlist->getItem(playersao->getWieldIndex());
2896 ToolCapabilities playeritem_toolcap =
2897 playeritem.getToolCapabilities(m_itemdef);
2898 // Get diggability and expected digging time
2899 DigParams params = getDigParams(m_nodedef->get(n).groups,
2900 &playeritem_toolcap);
2901 // If can't dig, try hand
2902 if(!params.diggable){
2903 const ItemDefinition &hand = m_itemdef->get("");
2904 const ToolCapabilities *tp = hand.tool_capabilities;
2906 params = getDigParams(m_nodedef->get(n).groups, tp);
2908 // If can't dig, ignore dig
2909 if(!params.diggable){
2910 infostream<<"Server: NoCheat: "<<player->getName()
2911 <<" completed digging "<<PP(p_under)
2912 <<", which is not diggable with tool. not digging."
2914 is_valid_dig = false;
2916 // If time is considerably too short, ignore dig
2917 // Check time only for medium and slow timed digs
2918 if(params.diggable && params.time > 0.3 && nocheat_t < 0.5 * params.time){
2919 infostream<<"Server: NoCheat: "<<player->getName()
2920 <<" completed digging "
2921 <<PP(p_under)<<" in "<<nocheat_t<<"s; expected "
2922 <<params.time<<"s; not digging."<<std::endl;
2923 is_valid_dig = false;
2927 /* Actually dig node */
2929 if(is_valid_dig && n.getContent() != CONTENT_IGNORE)
2930 scriptapi_node_on_dig(m_lua, p_under, n, playersao);
2932 // Send unusual result (that is, node not being removed)
2933 if(m_env->getMap().getNodeNoEx(p_under).getContent() != CONTENT_AIR)
2935 // Re-send block to revert change on client-side
2936 RemoteClient *client = getClient(peer_id);
2937 v3s16 blockpos = getNodeBlockPos(floatToInt(pointed_pos_under, BS));
2938 client->SetBlockNotSent(blockpos);
2944 3: place block or right-click object
2946 else if(action == 3)
2948 ItemStack item = playersao->getWieldedItem();
2950 // Reset build time counter
2951 if(pointed.type == POINTEDTHING_NODE &&
2952 item.getDefinition(m_itemdef).type == ITEM_NODE)
2953 getClient(peer_id)->m_time_from_building = 0.0;
2955 if(pointed.type == POINTEDTHING_OBJECT)
2957 // Right click object
2959 // Skip if object has been removed
2960 if(pointed_object->m_removed)
2963 actionstream<<player->getName()<<" right-clicks object "
2964 <<pointed.object_id<<": "
2965 <<pointed_object->getDescription()<<std::endl;
2968 pointed_object->rightClick(playersao);
2970 else if(scriptapi_item_on_place(m_lua,
2971 item, playersao, pointed))
2973 // Placement was handled in lua
2975 // Apply returned ItemStack
2976 playersao->setWieldedItem(item);
2979 // If item has node placement prediction, always send the above
2980 // node to make sure the client knows what exactly happened
2981 if(item.getDefinition(m_itemdef).node_placement_prediction != ""){
2982 RemoteClient *client = getClient(peer_id);
2983 v3s16 blockpos = getNodeBlockPos(floatToInt(pointed_pos_above, BS));
2984 client->SetBlockNotSent(blockpos);
2991 else if(action == 4)
2993 ItemStack item = playersao->getWieldedItem();
2995 actionstream<<player->getName()<<" uses "<<item.name
2996 <<", pointing at "<<pointed.dump()<<std::endl;
2998 if(scriptapi_item_on_use(m_lua,
2999 item, playersao, pointed))
3001 // Apply returned ItemStack
3002 playersao->setWieldedItem(item);
3009 Catch invalid actions
3013 infostream<<"WARNING: Server: Invalid action "
3014 <<action<<std::endl;
3017 else if(command == TOSERVER_REMOVED_SOUNDS)
3019 std::string datastring((char*)&data[2], datasize-2);
3020 std::istringstream is(datastring, std::ios_base::binary);
3022 int num = readU16(is);
3023 for(int k=0; k<num; k++){
3024 s32 id = readS32(is);
3025 std::map<s32, ServerPlayingSound>::iterator i =
3026 m_playing_sounds.find(id);
3027 if(i == m_playing_sounds.end())
3029 ServerPlayingSound &psound = i->second;
3030 psound.clients.erase(peer_id);
3031 if(psound.clients.size() == 0)
3032 m_playing_sounds.erase(i++);
3035 else if(command == TOSERVER_NODEMETA_FIELDS)
3037 std::string datastring((char*)&data[2], datasize-2);
3038 std::istringstream is(datastring, std::ios_base::binary);
3040 v3s16 p = readV3S16(is);
3041 std::string formname = deSerializeString(is);
3042 int num = readU16(is);
3043 std::map<std::string, std::string> fields;
3044 for(int k=0; k<num; k++){
3045 std::string fieldname = deSerializeString(is);
3046 std::string fieldvalue = deSerializeLongString(is);
3047 fields[fieldname] = fieldvalue;
3050 // If something goes wrong, this player is to blame
3051 RollbackScopeActor rollback_scope(m_rollback,
3052 std::string("player:")+player->getName());
3054 // Check the target node for rollback data; leave others unnoticed
3055 RollbackNode rn_old(&m_env->getMap(), p, this);
3057 scriptapi_node_on_receive_fields(m_lua, p, formname, fields,
3060 // Report rollback data
3061 RollbackNode rn_new(&m_env->getMap(), p, this);
3062 if(rollback() && rn_new != rn_old){
3063 RollbackAction action;
3064 action.setSetNode(p, rn_old, rn_new);
3065 rollback()->reportAction(action);
3068 else if(command == TOSERVER_INVENTORY_FIELDS)
3070 std::string datastring((char*)&data[2], datasize-2);
3071 std::istringstream is(datastring, std::ios_base::binary);
3073 std::string formname = deSerializeString(is);
3074 int num = readU16(is);
3075 std::map<std::string, std::string> fields;
3076 for(int k=0; k<num; k++){
3077 std::string fieldname = deSerializeString(is);
3078 std::string fieldvalue = deSerializeLongString(is);
3079 fields[fieldname] = fieldvalue;
3082 scriptapi_on_player_receive_fields(m_lua, playersao, formname, fields);
3086 infostream<<"Server::ProcessData(): Ignoring "
3087 "unknown command "<<command<<std::endl;
3091 catch(SendFailedException &e)
3093 errorstream<<"Server::ProcessData(): SendFailedException: "
3099 void Server::onMapEditEvent(MapEditEvent *event)
3101 //infostream<<"Server::onMapEditEvent()"<<std::endl;
3102 if(m_ignore_map_edit_events)
3104 if(m_ignore_map_edit_events_area.contains(event->getArea()))
3106 MapEditEvent *e = event->clone();
3107 m_unsent_map_edit_queue.push_back(e);
3110 Inventory* Server::getInventory(const InventoryLocation &loc)
3113 case InventoryLocation::UNDEFINED:
3116 case InventoryLocation::CURRENT_PLAYER:
3119 case InventoryLocation::PLAYER:
3121 Player *player = m_env->getPlayer(loc.name.c_str());
3124 PlayerSAO *playersao = player->getPlayerSAO();
3127 return playersao->getInventory();
3130 case InventoryLocation::NODEMETA:
3132 NodeMetadata *meta = m_env->getMap().getNodeMetadata(loc.p);
3135 return meta->getInventory();
3138 case InventoryLocation::DETACHED:
3140 if(m_detached_inventories.count(loc.name) == 0)
3142 return m_detached_inventories[loc.name];
3150 void Server::setInventoryModified(const InventoryLocation &loc)
3153 case InventoryLocation::UNDEFINED:
3156 case InventoryLocation::PLAYER:
3158 Player *player = m_env->getPlayer(loc.name.c_str());
3161 PlayerSAO *playersao = player->getPlayerSAO();
3164 playersao->m_inventory_not_sent = true;
3165 playersao->m_wielded_item_not_sent = true;
3168 case InventoryLocation::NODEMETA:
3170 v3s16 blockpos = getNodeBlockPos(loc.p);
3172 MapBlock *block = m_env->getMap().getBlockNoCreateNoEx(blockpos);
3174 block->raiseModified(MOD_STATE_WRITE_NEEDED);
3176 setBlockNotSent(blockpos);
3179 case InventoryLocation::DETACHED:
3181 sendDetachedInventoryToAll(loc.name);
3189 core::list<PlayerInfo> Server::getPlayerInfo()
3191 DSTACK(__FUNCTION_NAME);
3192 JMutexAutoLock envlock(m_env_mutex);
3193 JMutexAutoLock conlock(m_con_mutex);
3195 core::list<PlayerInfo> list;
3197 core::list<Player*> players = m_env->getPlayers();
3199 core::list<Player*>::Iterator i;
3200 for(i = players.begin();
3201 i != players.end(); i++)
3205 Player *player = *i;
3208 // Copy info from connection to info struct
3209 info.id = player->peer_id;
3210 info.address = m_con.GetPeerAddress(player->peer_id);
3211 info.avg_rtt = m_con.GetPeerAvgRTT(player->peer_id);
3213 catch(con::PeerNotFoundException &e)
3215 // Set dummy peer info
3217 info.address = Address(0,0,0,0,0);
3221 snprintf(info.name, PLAYERNAME_SIZE, "%s", player->getName());
3222 info.position = player->getPosition();
3224 list.push_back(info);
3231 void Server::peerAdded(con::Peer *peer)
3233 DSTACK(__FUNCTION_NAME);
3234 verbosestream<<"Server::peerAdded(): peer->id="
3235 <<peer->id<<std::endl;
3238 c.type = PEER_ADDED;
3239 c.peer_id = peer->id;
3241 m_peer_change_queue.push_back(c);
3244 void Server::deletingPeer(con::Peer *peer, bool timeout)
3246 DSTACK(__FUNCTION_NAME);
3247 verbosestream<<"Server::deletingPeer(): peer->id="
3248 <<peer->id<<", timeout="<<timeout<<std::endl;
3251 c.type = PEER_REMOVED;
3252 c.peer_id = peer->id;
3253 c.timeout = timeout;
3254 m_peer_change_queue.push_back(c);
3261 void Server::SendMovement(con::Connection &con, u16 peer_id)
3263 DSTACK(__FUNCTION_NAME);
3264 std::ostringstream os(std::ios_base::binary);
3266 writeU16(os, TOCLIENT_MOVEMENT);
3267 writeF1000(os, g_settings->getFloat("movement_acceleration_default"));
3268 writeF1000(os, g_settings->getFloat("movement_acceleration_air"));
3269 writeF1000(os, g_settings->getFloat("movement_acceleration_fast"));
3270 writeF1000(os, g_settings->getFloat("movement_speed_walk"));
3271 writeF1000(os, g_settings->getFloat("movement_speed_crouch"));
3272 writeF1000(os, g_settings->getFloat("movement_speed_fast"));
3273 writeF1000(os, g_settings->getFloat("movement_speed_climb"));
3274 writeF1000(os, g_settings->getFloat("movement_speed_jump"));
3275 writeF1000(os, g_settings->getFloat("movement_liquid_fluidity"));
3276 writeF1000(os, g_settings->getFloat("movement_liquid_fluidity_smooth"));
3277 writeF1000(os, g_settings->getFloat("movement_liquid_sink"));
3278 writeF1000(os, g_settings->getFloat("movement_gravity"));
3281 std::string s = os.str();
3282 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3284 con.Send(peer_id, 0, data, true);
3287 void Server::SendHP(con::Connection &con, u16 peer_id, u8 hp)
3289 DSTACK(__FUNCTION_NAME);
3290 std::ostringstream os(std::ios_base::binary);
3292 writeU16(os, TOCLIENT_HP);
3296 std::string s = os.str();
3297 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3299 con.Send(peer_id, 0, data, true);
3302 void Server::SendAccessDenied(con::Connection &con, u16 peer_id,
3303 const std::wstring &reason)
3305 DSTACK(__FUNCTION_NAME);
3306 std::ostringstream os(std::ios_base::binary);
3308 writeU16(os, TOCLIENT_ACCESS_DENIED);
3309 os<<serializeWideString(reason);
3312 std::string s = os.str();
3313 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3315 con.Send(peer_id, 0, data, true);
3318 void Server::SendDeathscreen(con::Connection &con, u16 peer_id,
3319 bool set_camera_point_target, v3f camera_point_target)
3321 DSTACK(__FUNCTION_NAME);
3322 std::ostringstream os(std::ios_base::binary);
3324 writeU16(os, TOCLIENT_DEATHSCREEN);
3325 writeU8(os, set_camera_point_target);
3326 writeV3F1000(os, camera_point_target);
3329 std::string s = os.str();
3330 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3332 con.Send(peer_id, 0, data, true);
3335 void Server::SendItemDef(con::Connection &con, u16 peer_id,
3336 IItemDefManager *itemdef)
3338 DSTACK(__FUNCTION_NAME);
3339 std::ostringstream os(std::ios_base::binary);
3343 u32 length of the next item
3344 zlib-compressed serialized ItemDefManager
3346 writeU16(os, TOCLIENT_ITEMDEF);
3347 std::ostringstream tmp_os(std::ios::binary);
3348 itemdef->serialize(tmp_os);
3349 std::ostringstream tmp_os2(std::ios::binary);
3350 compressZlib(tmp_os.str(), tmp_os2);
3351 os<<serializeLongString(tmp_os2.str());
3354 std::string s = os.str();
3355 verbosestream<<"Server: Sending item definitions to id("<<peer_id
3356 <<"): size="<<s.size()<<std::endl;
3357 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3359 con.Send(peer_id, 0, data, true);
3362 void Server::SendNodeDef(con::Connection &con, u16 peer_id,
3363 INodeDefManager *nodedef, u16 protocol_version)
3365 DSTACK(__FUNCTION_NAME);
3366 std::ostringstream os(std::ios_base::binary);
3370 u32 length of the next item
3371 zlib-compressed serialized NodeDefManager
3373 writeU16(os, TOCLIENT_NODEDEF);
3374 std::ostringstream tmp_os(std::ios::binary);
3375 nodedef->serialize(tmp_os, protocol_version);
3376 std::ostringstream tmp_os2(std::ios::binary);
3377 compressZlib(tmp_os.str(), tmp_os2);
3378 os<<serializeLongString(tmp_os2.str());
3381 std::string s = os.str();
3382 verbosestream<<"Server: Sending node definitions to id("<<peer_id
3383 <<"): size="<<s.size()<<std::endl;
3384 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3386 con.Send(peer_id, 0, data, true);
3390 Non-static send methods
3393 void Server::SendInventory(u16 peer_id)
3395 DSTACK(__FUNCTION_NAME);
3397 PlayerSAO *playersao = getPlayerSAO(peer_id);
3400 playersao->m_inventory_not_sent = false;
3406 std::ostringstream os;
3407 playersao->getInventory()->serialize(os);
3409 std::string s = os.str();
3411 SharedBuffer<u8> data(s.size()+2);
3412 writeU16(&data[0], TOCLIENT_INVENTORY);
3413 memcpy(&data[2], s.c_str(), s.size());
3416 m_con.Send(peer_id, 0, data, true);
3419 void Server::SendChatMessage(u16 peer_id, const std::wstring &message)
3421 DSTACK(__FUNCTION_NAME);
3423 std::ostringstream os(std::ios_base::binary);
3427 writeU16(buf, TOCLIENT_CHAT_MESSAGE);
3428 os.write((char*)buf, 2);
3431 writeU16(buf, message.size());
3432 os.write((char*)buf, 2);
3435 for(u32 i=0; i<message.size(); i++)
3439 os.write((char*)buf, 2);
3443 std::string s = os.str();
3444 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3446 m_con.Send(peer_id, 0, data, true);
3448 void Server::SendShowFormspecMessage(u16 peer_id, const std::string formspec, const std::string formname)
3450 DSTACK(__FUNCTION_NAME);
3452 std::ostringstream os(std::ios_base::binary);
3456 writeU16(buf, TOCLIENT_SHOW_FORMSPEC);
3457 os.write((char*)buf, 2);
3458 os<<serializeLongString(formspec);
3459 os<<serializeString(formname);
3462 std::string s = os.str();
3463 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3465 m_con.Send(peer_id, 0, data, true);
3468 void Server::BroadcastChatMessage(const std::wstring &message)
3470 for(core::map<u16, RemoteClient*>::Iterator
3471 i = m_clients.getIterator();
3472 i.atEnd() == false; i++)
3474 // Get client and check that it is valid
3475 RemoteClient *client = i.getNode()->getValue();
3476 assert(client->peer_id == i.getNode()->getKey());
3477 if(client->serialization_version == SER_FMT_VER_INVALID)
3480 SendChatMessage(client->peer_id, message);
3484 void Server::SendPlayerHP(u16 peer_id)
3486 DSTACK(__FUNCTION_NAME);
3487 PlayerSAO *playersao = getPlayerSAO(peer_id);
3489 playersao->m_hp_not_sent = false;
3490 SendHP(m_con, peer_id, playersao->getHP());
3493 void Server::SendMovePlayer(u16 peer_id)
3495 DSTACK(__FUNCTION_NAME);
3496 Player *player = m_env->getPlayer(peer_id);
3499 std::ostringstream os(std::ios_base::binary);
3500 writeU16(os, TOCLIENT_MOVE_PLAYER);
3501 writeV3F1000(os, player->getPosition());
3502 writeF1000(os, player->getPitch());
3503 writeF1000(os, player->getYaw());
3506 v3f pos = player->getPosition();
3507 f32 pitch = player->getPitch();
3508 f32 yaw = player->getYaw();
3509 verbosestream<<"Server: Sending TOCLIENT_MOVE_PLAYER"
3510 <<" pos=("<<pos.X<<","<<pos.Y<<","<<pos.Z<<")"
3517 std::string s = os.str();
3518 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3520 m_con.Send(peer_id, 0, data, true);
3523 void Server::SendPlayerPrivileges(u16 peer_id)
3525 Player *player = m_env->getPlayer(peer_id);
3527 if(player->peer_id == PEER_ID_INEXISTENT)
3530 std::set<std::string> privs;
3531 scriptapi_get_auth(m_lua, player->getName(), NULL, &privs);
3533 std::ostringstream os(std::ios_base::binary);
3534 writeU16(os, TOCLIENT_PRIVILEGES);
3535 writeU16(os, privs.size());
3536 for(std::set<std::string>::const_iterator i = privs.begin();
3537 i != privs.end(); i++){
3538 os<<serializeString(*i);
3542 std::string s = os.str();
3543 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3545 m_con.Send(peer_id, 0, data, true);
3548 void Server::SendPlayerInventoryFormspec(u16 peer_id)
3550 Player *player = m_env->getPlayer(peer_id);
3552 if(player->peer_id == PEER_ID_INEXISTENT)
3555 std::ostringstream os(std::ios_base::binary);
3556 writeU16(os, TOCLIENT_INVENTORY_FORMSPEC);
3557 os<<serializeLongString(player->inventory_formspec);
3560 std::string s = os.str();
3561 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3563 m_con.Send(peer_id, 0, data, true);
3566 s32 Server::playSound(const SimpleSoundSpec &spec,
3567 const ServerSoundParams ¶ms)
3569 // Find out initial position of sound
3570 bool pos_exists = false;
3571 v3f pos = params.getPos(m_env, &pos_exists);
3572 // If position is not found while it should be, cancel sound
3573 if(pos_exists != (params.type != ServerSoundParams::SSP_LOCAL))
3575 // Filter destination clients
3576 std::set<RemoteClient*> dst_clients;
3577 if(params.to_player != "")
3579 Player *player = m_env->getPlayer(params.to_player.c_str());
3581 infostream<<"Server::playSound: Player \""<<params.to_player
3582 <<"\" not found"<<std::endl;
3585 if(player->peer_id == PEER_ID_INEXISTENT){
3586 infostream<<"Server::playSound: Player \""<<params.to_player
3587 <<"\" not connected"<<std::endl;
3590 RemoteClient *client = getClient(player->peer_id);
3591 dst_clients.insert(client);
3595 for(core::map<u16, RemoteClient*>::Iterator
3596 i = m_clients.getIterator(); i.atEnd() == false; i++)
3598 RemoteClient *client = i.getNode()->getValue();
3599 Player *player = m_env->getPlayer(client->peer_id);
3603 if(player->getPosition().getDistanceFrom(pos) >
3604 params.max_hear_distance)
3607 dst_clients.insert(client);
3610 if(dst_clients.size() == 0)
3613 s32 id = m_next_sound_id++;
3614 // The sound will exist as a reference in m_playing_sounds
3615 m_playing_sounds[id] = ServerPlayingSound();
3616 ServerPlayingSound &psound = m_playing_sounds[id];
3617 psound.params = params;
3618 for(std::set<RemoteClient*>::iterator i = dst_clients.begin();
3619 i != dst_clients.end(); i++)
3620 psound.clients.insert((*i)->peer_id);
3622 std::ostringstream os(std::ios_base::binary);
3623 writeU16(os, TOCLIENT_PLAY_SOUND);
3625 os<<serializeString(spec.name);
3626 writeF1000(os, spec.gain * params.gain);
3627 writeU8(os, params.type);
3628 writeV3F1000(os, pos);
3629 writeU16(os, params.object);
3630 writeU8(os, params.loop);
3632 std::string s = os.str();
3633 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3635 for(std::set<RemoteClient*>::iterator i = dst_clients.begin();
3636 i != dst_clients.end(); i++){
3638 m_con.Send((*i)->peer_id, 0, data, true);
3642 void Server::stopSound(s32 handle)
3644 // Get sound reference
3645 std::map<s32, ServerPlayingSound>::iterator i =
3646 m_playing_sounds.find(handle);
3647 if(i == m_playing_sounds.end())
3649 ServerPlayingSound &psound = i->second;
3651 std::ostringstream os(std::ios_base::binary);
3652 writeU16(os, TOCLIENT_STOP_SOUND);
3653 writeS32(os, handle);
3655 std::string s = os.str();
3656 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3658 for(std::set<u16>::iterator i = psound.clients.begin();
3659 i != psound.clients.end(); i++){
3661 m_con.Send(*i, 0, data, true);
3663 // Remove sound reference
3664 m_playing_sounds.erase(i);
3667 void Server::sendRemoveNode(v3s16 p, u16 ignore_id,
3668 core::list<u16> *far_players, float far_d_nodes)
3670 float maxd = far_d_nodes*BS;
3671 v3f p_f = intToFloat(p, BS);
3675 SharedBuffer<u8> reply(replysize);
3676 writeU16(&reply[0], TOCLIENT_REMOVENODE);
3677 writeS16(&reply[2], p.X);
3678 writeS16(&reply[4], p.Y);
3679 writeS16(&reply[6], p.Z);
3681 for(core::map<u16, RemoteClient*>::Iterator
3682 i = m_clients.getIterator();
3683 i.atEnd() == false; i++)
3685 // Get client and check that it is valid
3686 RemoteClient *client = i.getNode()->getValue();
3687 assert(client->peer_id == i.getNode()->getKey());
3688 if(client->serialization_version == SER_FMT_VER_INVALID)
3691 // Don't send if it's the same one
3692 if(client->peer_id == ignore_id)
3698 Player *player = m_env->getPlayer(client->peer_id);
3701 // If player is far away, only set modified blocks not sent
3702 v3f player_pos = player->getPosition();
3703 if(player_pos.getDistanceFrom(p_f) > maxd)
3705 far_players->push_back(client->peer_id);
3712 m_con.Send(client->peer_id, 0, reply, true);
3716 void Server::sendAddNode(v3s16 p, MapNode n, u16 ignore_id,
3717 core::list<u16> *far_players, float far_d_nodes)
3719 float maxd = far_d_nodes*BS;
3720 v3f p_f = intToFloat(p, BS);
3722 for(core::map<u16, RemoteClient*>::Iterator
3723 i = m_clients.getIterator();
3724 i.atEnd() == false; i++)
3726 // Get client and check that it is valid
3727 RemoteClient *client = i.getNode()->getValue();
3728 assert(client->peer_id == i.getNode()->getKey());
3729 if(client->serialization_version == SER_FMT_VER_INVALID)
3732 // Don't send if it's the same one
3733 if(client->peer_id == ignore_id)
3739 Player *player = m_env->getPlayer(client->peer_id);
3742 // If player is far away, only set modified blocks not sent
3743 v3f player_pos = player->getPosition();
3744 if(player_pos.getDistanceFrom(p_f) > maxd)
3746 far_players->push_back(client->peer_id);
3753 u32 replysize = 8 + MapNode::serializedLength(client->serialization_version);
3754 SharedBuffer<u8> reply(replysize);
3755 writeU16(&reply[0], TOCLIENT_ADDNODE);
3756 writeS16(&reply[2], p.X);
3757 writeS16(&reply[4], p.Y);
3758 writeS16(&reply[6], p.Z);
3759 n.serialize(&reply[8], client->serialization_version);
3762 m_con.Send(client->peer_id, 0, reply, true);
3766 void Server::setBlockNotSent(v3s16 p)
3768 for(core::map<u16, RemoteClient*>::Iterator
3769 i = m_clients.getIterator();
3770 i.atEnd()==false; i++)
3772 RemoteClient *client = i.getNode()->getValue();
3773 client->SetBlockNotSent(p);
3777 void Server::SendBlockNoLock(u16 peer_id, MapBlock *block, u8 ver)
3779 DSTACK(__FUNCTION_NAME);
3781 v3s16 p = block->getPos();
3785 bool completely_air = true;
3786 for(s16 z0=0; z0<MAP_BLOCKSIZE; z0++)
3787 for(s16 x0=0; x0<MAP_BLOCKSIZE; x0++)
3788 for(s16 y0=0; y0<MAP_BLOCKSIZE; y0++)
3790 if(block->getNodeNoEx(v3s16(x0,y0,z0)).d != CONTENT_AIR)
3792 completely_air = false;
3793 x0 = y0 = z0 = MAP_BLOCKSIZE; // Break out
3798 infostream<<"Server: Sending block ("<<p.X<<","<<p.Y<<","<<p.Z<<"): ";
3800 infostream<<"[completely air] ";
3801 infostream<<std::endl;
3805 Create a packet with the block in the right format
3808 std::ostringstream os(std::ios_base::binary);
3809 block->serialize(os, ver, false);
3810 std::string s = os.str();
3811 SharedBuffer<u8> blockdata((u8*)s.c_str(), s.size());
3813 u32 replysize = 8 + blockdata.getSize();
3814 SharedBuffer<u8> reply(replysize);
3815 writeU16(&reply[0], TOCLIENT_BLOCKDATA);
3816 writeS16(&reply[2], p.X);
3817 writeS16(&reply[4], p.Y);
3818 writeS16(&reply[6], p.Z);
3819 memcpy(&reply[8], *blockdata, blockdata.getSize());
3821 /*infostream<<"Server: Sending block ("<<p.X<<","<<p.Y<<","<<p.Z<<")"
3822 <<": \tpacket size: "<<replysize<<std::endl;*/
3827 m_con.Send(peer_id, 1, reply, true);
3830 void Server::SendBlocks(float dtime)
3832 DSTACK(__FUNCTION_NAME);
3834 JMutexAutoLock envlock(m_env_mutex);
3835 JMutexAutoLock conlock(m_con_mutex);
3837 ScopeProfiler sp(g_profiler, "Server: sel and send blocks to clients");
3839 core::array<PrioritySortedBlockTransfer> queue;
3841 s32 total_sending = 0;
3844 ScopeProfiler sp(g_profiler, "Server: selecting blocks for sending");
3846 for(core::map<u16, RemoteClient*>::Iterator
3847 i = m_clients.getIterator();
3848 i.atEnd() == false; i++)
3850 RemoteClient *client = i.getNode()->getValue();
3851 assert(client->peer_id == i.getNode()->getKey());
3853 // If definitions and textures have not been sent, don't
3854 // send MapBlocks either
3855 if(!client->definitions_sent)
3858 total_sending += client->SendingCount();
3860 if(client->serialization_version == SER_FMT_VER_INVALID)
3863 client->GetNextBlocks(this, dtime, queue);
3868 // Lowest priority number comes first.
3869 // Lowest is most important.
3872 for(u32 i=0; i<queue.size(); i++)
3874 //TODO: Calculate limit dynamically
3875 if(total_sending >= g_settings->getS32
3876 ("max_simultaneous_block_sends_server_total"))
3879 PrioritySortedBlockTransfer q = queue[i];
3881 MapBlock *block = NULL;
3884 block = m_env->getMap().getBlockNoCreate(q.pos);
3886 catch(InvalidPositionException &e)
3891 RemoteClient *client = getClient(q.peer_id);
3893 SendBlockNoLock(q.peer_id, block, client->serialization_version);
3895 client->SentBlock(q.pos);
3901 void Server::fillMediaCache()
3903 DSTACK(__FUNCTION_NAME);
3905 infostream<<"Server: Calculating media file checksums"<<std::endl;
3907 // Collect all media file paths
3908 std::list<std::string> paths;
3909 for(std::vector<ModSpec>::iterator i = m_mods.begin();
3910 i != m_mods.end(); i++){
3911 const ModSpec &mod = *i;
3912 paths.push_back(mod.path + DIR_DELIM + "textures");
3913 paths.push_back(mod.path + DIR_DELIM + "sounds");
3914 paths.push_back(mod.path + DIR_DELIM + "media");
3915 paths.push_back(mod.path + DIR_DELIM + "models");
3917 std::string path_all = "textures";
3918 paths.push_back(path_all + DIR_DELIM + "all");
3920 // Collect media file information from paths into cache
3921 for(std::list<std::string>::iterator i = paths.begin();
3922 i != paths.end(); i++)
3924 std::string mediapath = *i;
3925 std::vector<fs::DirListNode> dirlist = fs::GetDirListing(mediapath);
3926 for(u32 j=0; j<dirlist.size(); j++){
3927 if(dirlist[j].dir) // Ignode dirs
3929 std::string filename = dirlist[j].name;
3930 // If name contains illegal characters, ignore the file
3931 if(!string_allowed(filename, TEXTURENAME_ALLOWED_CHARS)){
3932 infostream<<"Server: ignoring illegal file name: \""
3933 <<filename<<"\""<<std::endl;
3936 // If name is not in a supported format, ignore it
3937 const char *supported_ext[] = {
3938 ".png", ".jpg", ".bmp", ".tga",
3939 ".pcx", ".ppm", ".psd", ".wal", ".rgb",
3941 ".x", ".b3d", ".md2", ".obj",
3944 if(removeStringEnd(filename, supported_ext) == ""){
3945 infostream<<"Server: ignoring unsupported file extension: \""
3946 <<filename<<"\""<<std::endl;
3949 // Ok, attempt to load the file and add to cache
3950 std::string filepath = mediapath + DIR_DELIM + filename;
3952 std::ifstream fis(filepath.c_str(), std::ios_base::binary);
3953 if(fis.good() == false){
3954 errorstream<<"Server::fillMediaCache(): Could not open \""
3955 <<filename<<"\" for reading"<<std::endl;
3958 std::ostringstream tmp_os(std::ios_base::binary);
3962 fis.read(buf, 1024);
3963 std::streamsize len = fis.gcount();
3964 tmp_os.write(buf, len);
3973 errorstream<<"Server::fillMediaCache(): Failed to read \""
3974 <<filename<<"\""<<std::endl;
3977 if(tmp_os.str().length() == 0){
3978 errorstream<<"Server::fillMediaCache(): Empty file \""
3979 <<filepath<<"\""<<std::endl;
3984 sha1.addBytes(tmp_os.str().c_str(), tmp_os.str().length());
3986 unsigned char *digest = sha1.getDigest();
3987 std::string sha1_base64 = base64_encode(digest, 20);
3988 std::string sha1_hex = hex_encode((char*)digest, 20);
3992 this->m_media[filename] = MediaInfo(filepath, sha1_base64);
3993 verbosestream<<"Server: "<<sha1_hex<<" is "<<filename<<std::endl;
3998 struct SendableMediaAnnouncement
4001 std::string sha1_digest;
4003 SendableMediaAnnouncement(const std::string name_="",
4004 const std::string sha1_digest_=""):
4006 sha1_digest(sha1_digest_)
4010 void Server::sendMediaAnnouncement(u16 peer_id)
4012 DSTACK(__FUNCTION_NAME);
4014 verbosestream<<"Server: Announcing files to id("<<peer_id<<")"
4017 core::list<SendableMediaAnnouncement> file_announcements;
4019 for(std::map<std::string, MediaInfo>::iterator i = m_media.begin();
4020 i != m_media.end(); i++){
4022 file_announcements.push_back(
4023 SendableMediaAnnouncement(i->first, i->second.sha1_digest));
4027 std::ostringstream os(std::ios_base::binary);
4035 u16 length of sha1_digest
4040 writeU16(os, TOCLIENT_ANNOUNCE_MEDIA);
4041 writeU16(os, file_announcements.size());
4043 for(core::list<SendableMediaAnnouncement>::Iterator
4044 j = file_announcements.begin();
4045 j != file_announcements.end(); j++){
4046 os<<serializeString(j->name);
4047 os<<serializeString(j->sha1_digest);
4049 os<<serializeString(g_settings->get("remote_media"));
4052 std::string s = os.str();
4053 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
4056 m_con.Send(peer_id, 0, data, true);
4059 struct SendableMedia
4065 SendableMedia(const std::string &name_="", const std::string path_="",
4066 const std::string &data_=""):
4073 void Server::sendRequestedMedia(u16 peer_id,
4074 const core::list<MediaRequest> &tosend)
4076 DSTACK(__FUNCTION_NAME);
4078 verbosestream<<"Server::sendRequestedMedia(): "
4079 <<"Sending files to client"<<std::endl;
4083 // Put 5kB in one bunch (this is not accurate)
4084 u32 bytes_per_bunch = 5000;
4086 core::array< core::list<SendableMedia> > file_bunches;
4087 file_bunches.push_back(core::list<SendableMedia>());
4089 u32 file_size_bunch_total = 0;
4091 for(core::list<MediaRequest>::ConstIterator i = tosend.begin();
4092 i != tosend.end(); i++)
4094 if(m_media.find(i->name) == m_media.end()){
4095 errorstream<<"Server::sendRequestedMedia(): Client asked for "
4096 <<"unknown file \""<<(i->name)<<"\""<<std::endl;
4100 //TODO get path + name
4101 std::string tpath = m_media[(*i).name].path;
4104 std::ifstream fis(tpath.c_str(), std::ios_base::binary);
4105 if(fis.good() == false){
4106 errorstream<<"Server::sendRequestedMedia(): Could not open \""
4107 <<tpath<<"\" for reading"<<std::endl;
4110 std::ostringstream tmp_os(std::ios_base::binary);
4114 fis.read(buf, 1024);
4115 std::streamsize len = fis.gcount();
4116 tmp_os.write(buf, len);
4117 file_size_bunch_total += len;
4126 errorstream<<"Server::sendRequestedMedia(): Failed to read \""
4127 <<(*i).name<<"\""<<std::endl;
4130 /*infostream<<"Server::sendRequestedMedia(): Loaded \""
4131 <<tname<<"\""<<std::endl;*/
4133 file_bunches[file_bunches.size()-1].push_back(
4134 SendableMedia((*i).name, tpath, tmp_os.str()));
4136 // Start next bunch if got enough data
4137 if(file_size_bunch_total >= bytes_per_bunch){
4138 file_bunches.push_back(core::list<SendableMedia>());
4139 file_size_bunch_total = 0;
4144 /* Create and send packets */
4146 u32 num_bunches = file_bunches.size();
4147 for(u32 i=0; i<num_bunches; i++)
4149 std::ostringstream os(std::ios_base::binary);
4153 u16 total number of texture bunches
4154 u16 index of this bunch
4155 u32 number of files in this bunch
4164 writeU16(os, TOCLIENT_MEDIA);
4165 writeU16(os, num_bunches);
4167 writeU32(os, file_bunches[i].size());
4169 for(core::list<SendableMedia>::Iterator
4170 j = file_bunches[i].begin();
4171 j != file_bunches[i].end(); j++){
4172 os<<serializeString(j->name);
4173 os<<serializeLongString(j->data);
4177 std::string s = os.str();
4178 verbosestream<<"Server::sendRequestedMedia(): bunch "
4179 <<i<<"/"<<num_bunches
4180 <<" files="<<file_bunches[i].size()
4181 <<" size=" <<s.size()<<std::endl;
4182 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
4184 m_con.Send(peer_id, 0, data, true);
4188 void Server::sendDetachedInventory(const std::string &name, u16 peer_id)
4190 if(m_detached_inventories.count(name) == 0){
4191 errorstream<<__FUNCTION_NAME<<": \""<<name<<"\" not found"<<std::endl;
4194 Inventory *inv = m_detached_inventories[name];
4196 std::ostringstream os(std::ios_base::binary);
4197 writeU16(os, TOCLIENT_DETACHED_INVENTORY);
4198 os<<serializeString(name);
4202 std::string s = os.str();
4203 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
4205 m_con.Send(peer_id, 0, data, true);
4208 void Server::sendDetachedInventoryToAll(const std::string &name)
4210 DSTACK(__FUNCTION_NAME);
4212 for(core::map<u16, RemoteClient*>::Iterator
4213 i = m_clients.getIterator();
4214 i.atEnd() == false; i++){
4215 RemoteClient *client = i.getNode()->getValue();
4216 sendDetachedInventory(name, client->peer_id);
4220 void Server::sendDetachedInventories(u16 peer_id)
4222 DSTACK(__FUNCTION_NAME);
4224 for(std::map<std::string, Inventory*>::iterator
4225 i = m_detached_inventories.begin();
4226 i != m_detached_inventories.end(); i++){
4227 const std::string &name = i->first;
4228 //Inventory *inv = i->second;
4229 sendDetachedInventory(name, peer_id);
4237 void Server::DiePlayer(u16 peer_id)
4239 DSTACK(__FUNCTION_NAME);
4241 PlayerSAO *playersao = getPlayerSAO(peer_id);
4244 infostream<<"Server::DiePlayer(): Player "
4245 <<playersao->getPlayer()->getName()
4246 <<" dies"<<std::endl;
4248 playersao->setHP(0);
4250 // Trigger scripted stuff
4251 scriptapi_on_dieplayer(m_lua, playersao);
4253 SendPlayerHP(peer_id);
4254 SendDeathscreen(m_con, peer_id, false, v3f(0,0,0));
4257 void Server::RespawnPlayer(u16 peer_id)
4259 DSTACK(__FUNCTION_NAME);
4261 PlayerSAO *playersao = getPlayerSAO(peer_id);
4264 infostream<<"Server::RespawnPlayer(): Player "
4265 <<playersao->getPlayer()->getName()
4266 <<" respawns"<<std::endl;
4268 playersao->setHP(PLAYER_MAX_HP);
4270 bool repositioned = scriptapi_on_respawnplayer(m_lua, playersao);
4272 v3f pos = findSpawnPos(m_env->getServerMap());
4273 playersao->setPos(pos);
4277 void Server::UpdateCrafting(u16 peer_id)
4279 DSTACK(__FUNCTION_NAME);
4281 Player* player = m_env->getPlayer(peer_id);
4284 // Get a preview for crafting
4286 getCraftingResult(&player->inventory, preview, false, this);
4288 // Put the new preview in
4289 InventoryList *plist = player->inventory.getList("craftpreview");
4291 assert(plist->getSize() >= 1);
4292 plist->changeItem(0, preview);
4295 RemoteClient* Server::getClient(u16 peer_id)
4297 DSTACK(__FUNCTION_NAME);
4298 //JMutexAutoLock lock(m_con_mutex);
4299 core::map<u16, RemoteClient*>::Node *n;
4300 n = m_clients.find(peer_id);
4301 // A client should exist for all peers
4303 return n->getValue();
4306 std::wstring Server::getStatusString()
4308 std::wostringstream os(std::ios_base::binary);
4311 os<<L"version="<<narrow_to_wide(VERSION_STRING);
4313 os<<L", uptime="<<m_uptime.get();
4314 // Information about clients
4315 core::map<u16, RemoteClient*>::Iterator i;
4318 for(i = m_clients.getIterator(), first = true;
4319 i.atEnd() == false; i++)
4321 // Get client and check that it is valid
4322 RemoteClient *client = i.getNode()->getValue();
4323 assert(client->peer_id == i.getNode()->getKey());
4324 if(client->serialization_version == SER_FMT_VER_INVALID)
4327 Player *player = m_env->getPlayer(client->peer_id);
4328 // Get name of player
4329 std::wstring name = L"unknown";
4331 name = narrow_to_wide(player->getName());
4332 // Add name to information string
4340 if(((ServerMap*)(&m_env->getMap()))->isSavingEnabled() == false)
4341 os<<std::endl<<L"# Server: "<<" WARNING: Map saving is disabled.";
4342 if(g_settings->get("motd") != "")
4343 os<<std::endl<<L"# Server: "<<narrow_to_wide(g_settings->get("motd"));
4347 std::set<std::string> Server::getPlayerEffectivePrivs(const std::string &name)
4349 std::set<std::string> privs;
4350 scriptapi_get_auth(m_lua, name, NULL, &privs);
4354 bool Server::checkPriv(const std::string &name, const std::string &priv)
4356 std::set<std::string> privs = getPlayerEffectivePrivs(name);
4357 return (privs.count(priv) != 0);
4360 void Server::reportPrivsModified(const std::string &name)
4363 for(core::map<u16, RemoteClient*>::Iterator
4364 i = m_clients.getIterator();
4365 i.atEnd() == false; i++){
4366 RemoteClient *client = i.getNode()->getValue();
4367 Player *player = m_env->getPlayer(client->peer_id);
4368 reportPrivsModified(player->getName());
4371 Player *player = m_env->getPlayer(name.c_str());
4374 SendPlayerPrivileges(player->peer_id);
4375 PlayerSAO *sao = player->getPlayerSAO();
4378 sao->updatePrivileges(
4379 getPlayerEffectivePrivs(name),
4384 void Server::reportInventoryFormspecModified(const std::string &name)
4386 Player *player = m_env->getPlayer(name.c_str());
4389 SendPlayerInventoryFormspec(player->peer_id);
4392 // Saves g_settings to configpath given at initialization
4393 void Server::saveConfig()
4395 if(m_path_config != "")
4396 g_settings->updateConfigFile(m_path_config.c_str());
4399 void Server::notifyPlayer(const char *name, const std::wstring msg)
4401 Player *player = m_env->getPlayer(name);
4404 SendChatMessage(player->peer_id, std::wstring(L"Server: -!- ")+msg);
4407 bool Server::showFormspec(const char *playername, const std::string &formspec, const std::string &formname)
4409 Player *player = m_env->getPlayer(playername);
4413 infostream<<"showFormspec: couldn't find player:"<<playername<<std::endl;
4417 SendShowFormspecMessage(player->peer_id, formspec, formname);
4421 void Server::notifyPlayers(const std::wstring msg)
4423 BroadcastChatMessage(msg);
4426 void Server::queueBlockEmerge(v3s16 blockpos, bool allow_generate)
4428 m_emerge->enqueueBlockEmerge(PEER_ID_INEXISTENT, blockpos, allow_generate);
4431 Inventory* Server::createDetachedInventory(const std::string &name)
4433 if(m_detached_inventories.count(name) > 0){
4434 infostream<<"Server clearing detached inventory \""<<name<<"\""<<std::endl;
4435 delete m_detached_inventories[name];
4437 infostream<<"Server creating detached inventory \""<<name<<"\""<<std::endl;
4439 Inventory *inv = new Inventory(m_itemdef);
4441 m_detached_inventories[name] = inv;
4442 sendDetachedInventoryToAll(name);
4449 BoolScopeSet(bool *dst, bool val):
4452 m_orig_state = *m_dst;
4457 *m_dst = m_orig_state;
4464 // actions: time-reversed list
4465 // Return value: success/failure
4466 bool Server::rollbackRevertActions(const std::list<RollbackAction> &actions,
4467 std::list<std::string> *log)
4469 infostream<<"Server::rollbackRevertActions(len="<<actions.size()<<")"<<std::endl;
4470 ServerMap *map = (ServerMap*)(&m_env->getMap());
4471 // Disable rollback report sink while reverting
4472 BoolScopeSet rollback_scope_disable(&m_rollback_sink_enabled, false);
4474 // Fail if no actions to handle
4475 if(actions.empty()){
4476 log->push_back("Nothing to do.");
4483 for(std::list<RollbackAction>::const_iterator
4484 i = actions.begin();
4485 i != actions.end(); i++)
4487 const RollbackAction &action = *i;
4489 bool success = action.applyRevert(map, this, this);
4492 std::ostringstream os;
4493 os<<"Revert of step ("<<num_tried<<") "<<action.toString()<<" failed";
4494 infostream<<"Map::rollbackRevertActions(): "<<os.str()<<std::endl;
4496 log->push_back(os.str());
4498 std::ostringstream os;
4499 os<<"Successfully reverted step ("<<num_tried<<") "<<action.toString();
4500 infostream<<"Map::rollbackRevertActions(): "<<os.str()<<std::endl;
4502 log->push_back(os.str());
4506 infostream<<"Map::rollbackRevertActions(): "<<num_failed<<"/"<<num_tried
4507 <<" failed"<<std::endl;
4509 // Call it done if less than half failed
4510 return num_failed <= num_tried/2;
4513 // IGameDef interface
4515 IItemDefManager* Server::getItemDefManager()
4519 INodeDefManager* Server::getNodeDefManager()
4523 ICraftDefManager* Server::getCraftDefManager()
4527 ITextureSource* Server::getTextureSource()
4531 IShaderSource* Server::getShaderSource()
4535 u16 Server::allocateUnknownNodeId(const std::string &name)
4537 return m_nodedef->allocateDummy(name);
4539 ISoundManager* Server::getSoundManager()
4541 return &dummySoundManager;
4543 MtEventManager* Server::getEventManager()
4547 IRollbackReportSink* Server::getRollbackReportSink()
4549 if(!m_enable_rollback_recording)
4551 if(!m_rollback_sink_enabled)
4556 IWritableItemDefManager* Server::getWritableItemDefManager()
4560 IWritableNodeDefManager* Server::getWritableNodeDefManager()
4564 IWritableCraftDefManager* Server::getWritableCraftDefManager()
4569 const ModSpec* Server::getModSpec(const std::string &modname)
4571 for(std::vector<ModSpec>::iterator i = m_mods.begin();
4572 i != m_mods.end(); i++){
4573 const ModSpec &mod = *i;
4574 if(mod.name == modname)
4579 void Server::getModNames(core::list<std::string> &modlist)
4581 for(std::vector<ModSpec>::iterator i = m_mods.begin(); i != m_mods.end(); i++)
4583 modlist.push_back((*i).name);
4586 std::string Server::getBuiltinLuaPath()
4588 return porting::path_share + DIR_DELIM + "builtin";
4591 v3f findSpawnPos(ServerMap &map)
4593 //return v3f(50,50,50)*BS;
4598 nodepos = v2s16(0,0);
4603 s16 water_level = map.m_mgparams->water_level;
4605 // Try to find a good place a few times
4606 for(s32 i=0; i<1000; i++)
4609 // We're going to try to throw the player to this position
4610 v2s16 nodepos2d = v2s16(-range + (myrand()%(range*2)),
4611 -range + (myrand()%(range*2)));
4612 //v2s16 sectorpos = getNodeSectorPos(nodepos2d);
4613 // Get ground height at point (fallbacks to heightmap function)
4614 s16 groundheight = map.findGroundLevel(nodepos2d);
4615 // Don't go underwater
4616 if(groundheight <= water_level)
4618 //infostream<<"-> Underwater"<<std::endl;
4621 // Don't go to high places
4622 if(groundheight > water_level + 6)
4624 //infostream<<"-> Underwater"<<std::endl;
4628 nodepos = v3s16(nodepos2d.X, groundheight-2, nodepos2d.Y);
4629 bool is_good = false;
4631 for(s32 i=0; i<10; i++){
4632 v3s16 blockpos = getNodeBlockPos(nodepos);
4633 map.emergeBlock(blockpos, true);
4634 MapNode n = map.getNodeNoEx(nodepos);
4635 if(n.getContent() == CONTENT_AIR){
4646 // Found a good place
4647 //infostream<<"Searched through "<<i<<" places."<<std::endl;
4653 return intToFloat(nodepos, BS);
4656 PlayerSAO* Server::emergePlayer(const char *name, u16 peer_id)
4658 RemotePlayer *player = NULL;
4659 bool newplayer = false;
4662 Try to get an existing player
4664 player = static_cast<RemotePlayer*>(m_env->getPlayer(name));
4666 // If player is already connected, cancel
4667 if(player != NULL && player->peer_id != 0)
4669 infostream<<"emergePlayer(): Player already connected"<<std::endl;
4674 If player with the wanted peer_id already exists, cancel.
4676 if(m_env->getPlayer(peer_id) != NULL)
4678 infostream<<"emergePlayer(): Player with wrong name but same"
4679 " peer_id already exists"<<std::endl;
4684 Create a new player if it doesn't exist yet
4689 player = new RemotePlayer(this);
4690 player->updateName(name);
4692 /* Set player position */
4693 infostream<<"Server: Finding spawn place for player \""
4694 <<name<<"\""<<std::endl;
4695 v3f pos = findSpawnPos(m_env->getServerMap());
4696 player->setPosition(pos);
4698 /* Add player to environment */
4699 m_env->addPlayer(player);
4703 Create a new player active object
4705 PlayerSAO *playersao = new PlayerSAO(m_env, player, peer_id,
4706 getPlayerEffectivePrivs(player->getName()),
4709 /* Add object to environment */
4710 m_env->addActiveObject(playersao);
4714 scriptapi_on_newplayer(m_lua, playersao);
4716 scriptapi_on_joinplayer(m_lua, playersao);
4721 void Server::handlePeerChange(PeerChange &c)
4723 JMutexAutoLock envlock(m_env_mutex);
4724 JMutexAutoLock conlock(m_con_mutex);
4726 if(c.type == PEER_ADDED)
4733 core::map<u16, RemoteClient*>::Node *n;
4734 n = m_clients.find(c.peer_id);
4735 // The client shouldn't already exist
4739 RemoteClient *client = new RemoteClient();
4740 client->peer_id = c.peer_id;
4741 m_clients.insert(client->peer_id, client);
4744 else if(c.type == PEER_REMOVED)
4751 core::map<u16, RemoteClient*>::Node *n;
4752 n = m_clients.find(c.peer_id);
4753 // The client should exist
4757 Mark objects to be not known by the client
4759 RemoteClient *client = n->getValue();
4761 for(core::map<u16, bool>::Iterator
4762 i = client->m_known_objects.getIterator();
4763 i.atEnd()==false; i++)
4766 u16 id = i.getNode()->getKey();
4767 ServerActiveObject* obj = m_env->getActiveObject(id);
4769 if(obj && obj->m_known_by_count > 0)
4770 obj->m_known_by_count--;
4774 Clear references to playing sounds
4776 for(std::map<s32, ServerPlayingSound>::iterator
4777 i = m_playing_sounds.begin();
4778 i != m_playing_sounds.end();)
4780 ServerPlayingSound &psound = i->second;
4781 psound.clients.erase(c.peer_id);
4782 if(psound.clients.size() == 0)
4783 m_playing_sounds.erase(i++);
4788 Player *player = m_env->getPlayer(c.peer_id);
4790 // Collect information about leaving in chat
4791 std::wstring message;
4795 std::wstring name = narrow_to_wide(player->getName());
4798 message += L" left the game.";
4800 message += L" (timed out)";
4804 /* Run scripts and remove from environment */
4808 PlayerSAO *playersao = player->getPlayerSAO();
4811 scriptapi_on_leaveplayer(m_lua, playersao);
4813 playersao->disconnected();
4823 std::ostringstream os(std::ios_base::binary);
4824 for(core::map<u16, RemoteClient*>::Iterator
4825 i = m_clients.getIterator();
4826 i.atEnd() == false; i++)
4828 RemoteClient *client = i.getNode()->getValue();
4829 assert(client->peer_id == i.getNode()->getKey());
4830 if(client->serialization_version == SER_FMT_VER_INVALID)
4833 Player *player = m_env->getPlayer(client->peer_id);
4836 // Get name of player
4837 os<<player->getName()<<" ";
4840 actionstream<<player->getName()<<" "
4841 <<(c.timeout?"times out.":"leaves game.")
4842 <<" List of players: "
4843 <<os.str()<<std::endl;
4848 delete m_clients[c.peer_id];
4849 m_clients.remove(c.peer_id);
4851 // Send player info to all remaining clients
4852 //SendPlayerInfos();
4854 // Send leave chat message to all remaining clients
4855 if(message.length() != 0)
4856 BroadcastChatMessage(message);
4865 void Server::handlePeerChanges()
4867 while(m_peer_change_queue.size() > 0)
4869 PeerChange c = m_peer_change_queue.pop_front();
4871 verbosestream<<"Server: Handling peer change: "
4872 <<"id="<<c.peer_id<<", timeout="<<c.timeout
4875 handlePeerChange(c);
4879 void dedicated_server_loop(Server &server, bool &kill)
4881 DSTACK(__FUNCTION_NAME);
4883 verbosestream<<"dedicated_server_loop()"<<std::endl;
4885 IntervalLimiter m_profiler_interval;
4889 float steplen = g_settings->getFloat("dedicated_server_step");
4890 // This is kind of a hack but can be done like this
4891 // because server.step() is very light
4893 ScopeProfiler sp(g_profiler, "dedicated server sleep");
4894 sleep_ms((int)(steplen*1000.0));
4896 server.step(steplen);
4898 if(server.getShutdownRequested() || kill)
4900 infostream<<"Dedicated server quitting"<<std::endl;
4902 if(g_settings->getBool("server_announce") == true)
4903 ServerList::sendAnnounce("delete");
4911 float profiler_print_interval =
4912 g_settings->getFloat("profiler_print_interval");
4913 if(profiler_print_interval != 0)
4915 if(m_profiler_interval.step(steplen, profiler_print_interval))
4917 infostream<<"Profiler:"<<std::endl;
4918 g_profiler->print(infostream);
4919 g_profiler->clear();