3 Copyright (C) 2010-2013 celeron55, Perttu Ahola <celeron55@gmail.com>
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU Lesser General Public License as published by
7 the Free Software Foundation; either version 2.1 of the License, or
8 (at your option) any later version.
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU Lesser General Public License for more details.
15 You should have received a copy of the GNU Lesser General Public License along
16 with this program; if not, write to the Free Software Foundation, Inc.,
17 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
24 #include "clientserver.h"
26 #include "environment.h"
28 #include "jmutexautolock.h"
30 #include "constants.h"
35 #include "serverobject.h"
36 #include "genericobject.h"
40 #include "scripting_game.h"
47 #include "content_mapnode.h"
48 #include "content_nodemeta.h"
49 #include "content_abm.h"
50 #include "content_sao.h"
55 #include "sound.h" // dummySoundManager
56 #include "event_manager.h"
58 #include "serverlist.h"
59 #include "util/string.h"
60 #include "util/pointedthing.h"
61 #include "util/mathconstants.h"
63 #include "util/serialize.h"
64 #include "util/thread.h"
65 #include "defaultsettings.h"
67 class ClientNotFoundException : public BaseException
70 ClientNotFoundException(const char *s):
75 class ServerThread : public SimpleThread
81 ServerThread(Server *server):
90 void * ServerThread::Thread()
94 log_register_thread("ServerThread");
96 DSTACK(__FUNCTION_NAME);
98 BEGIN_DEBUG_EXCEPTION_HANDLER
103 //TimeTaker timer("AsyncRunStep() + Receive()");
106 //TimeTaker timer("AsyncRunStep()");
107 m_server->AsyncRunStep();
110 //infostream<<"Running m_server->Receive()"<<std::endl;
113 catch(con::NoIncomingDataException &e)
116 catch(con::PeerNotFoundException &e)
118 infostream<<"Server: PeerNotFoundException"<<std::endl;
120 catch(ClientNotFoundException &e)
123 catch(con::ConnectionBindFailed &e)
125 m_server->setAsyncFatalError(e.what());
129 m_server->setAsyncFatalError(e.what());
133 END_DEBUG_EXCEPTION_HANDLER(errorstream)
138 v3f ServerSoundParams::getPos(ServerEnvironment *env, bool *pos_exists) const
140 if(pos_exists) *pos_exists = false;
145 if(pos_exists) *pos_exists = true;
150 ServerActiveObject *sao = env->getActiveObject(object);
153 if(pos_exists) *pos_exists = true;
154 return sao->getBasePosition(); }
159 void RemoteClient::GetNextBlocks(Server *server, float dtime,
160 std::vector<PrioritySortedBlockTransfer> &dest)
162 DSTACK(__FUNCTION_NAME);
165 TimeTaker timer("RemoteClient::GetNextBlocks", &timer_result);*/
168 m_nothing_to_send_pause_timer -= dtime;
169 m_nearest_unsent_reset_timer += dtime;
171 if(m_nothing_to_send_pause_timer >= 0)
174 Player *player = server->m_env->getPlayer(peer_id);
175 // This can happen sometimes; clients and players are not in perfect sync.
179 // Won't send anything if already sending
180 if(m_blocks_sending.size() >= g_settings->getU16
181 ("max_simultaneous_block_sends_per_client"))
183 //infostream<<"Not sending any blocks, Queue full."<<std::endl;
187 //TimeTaker timer("RemoteClient::GetNextBlocks");
189 v3f playerpos = player->getPosition();
190 v3f playerspeed = player->getSpeed();
191 v3f playerspeeddir(0,0,0);
192 if(playerspeed.getLength() > 1.0*BS)
193 playerspeeddir = playerspeed / playerspeed.getLength();
194 // Predict to next block
195 v3f playerpos_predicted = playerpos + playerspeeddir*MAP_BLOCKSIZE*BS;
197 v3s16 center_nodepos = floatToInt(playerpos_predicted, BS);
199 v3s16 center = getNodeBlockPos(center_nodepos);
201 // Camera position and direction
202 v3f camera_pos = player->getEyePosition();
203 v3f camera_dir = v3f(0,0,1);
204 camera_dir.rotateYZBy(player->getPitch());
205 camera_dir.rotateXZBy(player->getYaw());
207 /*infostream<<"camera_dir=("<<camera_dir.X<<","<<camera_dir.Y<<","
208 <<camera_dir.Z<<")"<<std::endl;*/
211 Get the starting value of the block finder radius.
214 if(m_last_center != center)
216 m_nearest_unsent_d = 0;
217 m_last_center = center;
220 /*infostream<<"m_nearest_unsent_reset_timer="
221 <<m_nearest_unsent_reset_timer<<std::endl;*/
223 // Reset periodically to workaround for some bugs or stuff
224 if(m_nearest_unsent_reset_timer > 20.0)
226 m_nearest_unsent_reset_timer = 0;
227 m_nearest_unsent_d = 0;
228 //infostream<<"Resetting m_nearest_unsent_d for "
229 // <<server->getPlayerName(peer_id)<<std::endl;
232 //s16 last_nearest_unsent_d = m_nearest_unsent_d;
233 s16 d_start = m_nearest_unsent_d;
235 //infostream<<"d_start="<<d_start<<std::endl;
237 u16 max_simul_sends_setting = g_settings->getU16
238 ("max_simultaneous_block_sends_per_client");
239 u16 max_simul_sends_usually = max_simul_sends_setting;
242 Check the time from last addNode/removeNode.
244 Decrease send rate if player is building stuff.
246 m_time_from_building += dtime;
247 if(m_time_from_building < g_settings->getFloat(
248 "full_block_send_enable_min_time_from_building"))
250 max_simul_sends_usually
251 = LIMITED_MAX_SIMULTANEOUS_BLOCK_SENDS;
255 Number of blocks sending + number of blocks selected for sending
257 u32 num_blocks_selected = m_blocks_sending.size();
260 next time d will be continued from the d from which the nearest
261 unsent block was found this time.
263 This is because not necessarily any of the blocks found this
264 time are actually sent.
266 s32 new_nearest_unsent_d = -1;
268 s16 d_max = g_settings->getS16("max_block_send_distance");
269 s16 d_max_gen = g_settings->getS16("max_block_generate_distance");
271 // Don't loop very much at a time
272 s16 max_d_increment_at_time = 2;
273 if(d_max > d_start + max_d_increment_at_time)
274 d_max = d_start + max_d_increment_at_time;
275 /*if(d_max_gen > d_start+2)
276 d_max_gen = d_start+2;*/
278 //infostream<<"Starting from "<<d_start<<std::endl;
280 s32 nearest_emerged_d = -1;
281 s32 nearest_emergefull_d = -1;
282 s32 nearest_sent_d = -1;
283 bool queue_is_full = false;
286 for(d = d_start; d <= d_max; d++)
288 /*errorstream<<"checking d="<<d<<" for "
289 <<server->getPlayerName(peer_id)<<std::endl;*/
290 //infostream<<"RemoteClient::SendBlocks(): d="<<d<<std::endl;
293 If m_nearest_unsent_d was changed by the EmergeThread
294 (it can change it to 0 through SetBlockNotSent),
296 Else update m_nearest_unsent_d
298 /*if(m_nearest_unsent_d != last_nearest_unsent_d)
300 d = m_nearest_unsent_d;
301 last_nearest_unsent_d = m_nearest_unsent_d;
305 Get the border/face dot coordinates of a "d-radiused"
308 std::list<v3s16> list;
309 getFacePositions(list, d);
311 std::list<v3s16>::iterator li;
312 for(li=list.begin(); li!=list.end(); ++li)
314 v3s16 p = *li + center;
318 - Don't allow too many simultaneous transfers
319 - EXCEPT when the blocks are very close
321 Also, don't send blocks that are already flying.
324 // Start with the usual maximum
325 u16 max_simul_dynamic = max_simul_sends_usually;
327 // If block is very close, allow full maximum
328 if(d <= BLOCK_SEND_DISABLE_LIMITS_MAX_D)
329 max_simul_dynamic = max_simul_sends_setting;
331 // Don't select too many blocks for sending
332 if(num_blocks_selected >= max_simul_dynamic)
334 queue_is_full = true;
335 goto queue_full_break;
338 // Don't send blocks that are currently being transferred
339 if(m_blocks_sending.find(p) != m_blocks_sending.end())
345 if(p.X < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
346 || p.X > MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
347 || p.Y < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
348 || p.Y > MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
349 || p.Z < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
350 || p.Z > MAP_GENERATION_LIMIT / MAP_BLOCKSIZE)
353 // If this is true, inexistent block will be made from scratch
354 bool generate = d <= d_max_gen;
357 /*// Limit the generating area vertically to 2/3
358 if(abs(p.Y - center.Y) > d_max_gen - d_max_gen / 3)
361 // Limit the send area vertically to 1/2
362 if(abs(p.Y - center.Y) > d_max / 2)
368 If block is far away, don't generate it unless it is
374 // Block center y in nodes
375 f32 y = (f32)(p.Y * MAP_BLOCKSIZE + MAP_BLOCKSIZE/2);
376 // Don't generate if it's very high or very low
377 if(y < -64 || y > 64)
381 v2s16 p2d_nodes_center(
385 // Get ground height in nodes
386 s16 gh = server->m_env->getServerMap().findGroundLevel(
389 // If differs a lot, don't generate
390 if(fabs(gh - y) > MAP_BLOCKSIZE*2)
392 // Actually, don't even send it
398 //infostream<<"d="<<d<<std::endl;
401 Don't generate or send if not in sight
402 FIXME This only works if the client uses a small enough
403 FOV setting. The default of 72 degrees is fine.
406 float camera_fov = (72.0*M_PI/180) * 4./3.;
407 if(isBlockInSight(p, camera_pos, camera_dir, camera_fov, 10000*BS) == false)
413 Don't send already sent blocks
416 if(m_blocks_sent.find(p) != m_blocks_sent.end())
423 Check if map has this block
425 MapBlock *block = server->m_env->getMap().getBlockNoCreateNoEx(p);
427 bool surely_not_found_on_disk = false;
428 bool block_is_invalid = false;
431 // Reset usage timer, this block will be of use in the future.
432 block->resetUsageTimer();
434 // Block is dummy if data doesn't exist.
435 // It means it has been not found from disk and not generated
438 surely_not_found_on_disk = true;
441 // Block is valid if lighting is up-to-date and data exists
442 if(block->isValid() == false)
444 block_is_invalid = true;
447 /*if(block->isFullyGenerated() == false)
449 block_is_invalid = true;
454 ServerMap *map = (ServerMap*)(&server->m_env->getMap());
455 v2s16 chunkpos = map->sector_to_chunk(p2d);
456 if(map->chunkNonVolatile(chunkpos) == false)
457 block_is_invalid = true;
459 if(block->isGenerated() == false)
460 block_is_invalid = true;
463 If block is not close, don't send it unless it is near
466 Block is near ground level if night-time mesh
467 differs from day-time mesh.
471 if(block->getDayNightDiff() == false)
478 If block has been marked to not exist on disk (dummy)
479 and generating new ones is not wanted, skip block.
481 if(generate == false && surely_not_found_on_disk == true)
488 Add inexistent block to emerge queue.
490 if(block == NULL || surely_not_found_on_disk || block_is_invalid)
492 /* //TODO: Get value from somewhere
493 // Allow only one block in emerge queue
494 //if(server->m_emerge_queue.peerItemCount(peer_id) < 1)
495 // Allow two blocks in queue per client
496 //if(server->m_emerge_queue.peerItemCount(peer_id) < 2)
498 // Make it more responsive when needing to generate stuff
499 if(surely_not_found_on_disk)
501 if(server->m_emerge_queue.peerItemCount(peer_id) < max_emerge)
503 //infostream<<"Adding block to emerge queue"<<std::endl;
505 // Add it to the emerge queue and trigger the thread
508 if(generate == false)
509 flags |= BLOCK_EMERGE_FLAG_FROMDISK;
511 server->m_emerge_queue.addBlock(peer_id, p, flags);
512 server->m_emergethread.trigger();
514 if(nearest_emerged_d == -1)
515 nearest_emerged_d = d;
517 if(nearest_emergefull_d == -1)
518 nearest_emergefull_d = d;
519 goto queue_full_break;
523 if (server->m_emerge->enqueueBlockEmerge(peer_id, p, generate)) {
524 if (nearest_emerged_d == -1)
525 nearest_emerged_d = d;
527 if (nearest_emergefull_d == -1)
528 nearest_emergefull_d = d;
529 goto queue_full_break;
536 if(nearest_sent_d == -1)
540 Add block to send queue
543 /*errorstream<<"sending from d="<<d<<" to "
544 <<server->getPlayerName(peer_id)<<std::endl;*/
546 PrioritySortedBlockTransfer q((float)d, p, peer_id);
550 num_blocks_selected += 1;
555 //infostream<<"Stopped at "<<d<<std::endl;
557 // If nothing was found for sending and nothing was queued for
558 // emerging, continue next time browsing from here
559 if(nearest_emerged_d != -1){
560 new_nearest_unsent_d = nearest_emerged_d;
561 } else if(nearest_emergefull_d != -1){
562 new_nearest_unsent_d = nearest_emergefull_d;
564 if(d > g_settings->getS16("max_block_send_distance")){
565 new_nearest_unsent_d = 0;
566 m_nothing_to_send_pause_timer = 2.0;
567 /*infostream<<"GetNextBlocks(): d wrapped around for "
568 <<server->getPlayerName(peer_id)
569 <<"; setting to 0 and pausing"<<std::endl;*/
571 if(nearest_sent_d != -1)
572 new_nearest_unsent_d = nearest_sent_d;
574 new_nearest_unsent_d = d;
578 if(new_nearest_unsent_d != -1)
579 m_nearest_unsent_d = new_nearest_unsent_d;
581 /*timer_result = timer.stop(true);
582 if(timer_result != 0)
583 infostream<<"GetNextBlocks timeout: "<<timer_result<<" (!=0)"<<std::endl;*/
586 void RemoteClient::GotBlock(v3s16 p)
588 if(m_blocks_sending.find(p) != m_blocks_sending.end())
589 m_blocks_sending.erase(p);
592 /*infostream<<"RemoteClient::GotBlock(): Didn't find in"
593 " m_blocks_sending"<<std::endl;*/
594 m_excess_gotblocks++;
596 m_blocks_sent.insert(p);
599 void RemoteClient::SentBlock(v3s16 p)
601 if(m_blocks_sending.find(p) == m_blocks_sending.end())
602 m_blocks_sending[p] = 0.0;
604 infostream<<"RemoteClient::SentBlock(): Sent block"
605 " already in m_blocks_sending"<<std::endl;
608 void RemoteClient::SetBlockNotSent(v3s16 p)
610 m_nearest_unsent_d = 0;
612 if(m_blocks_sending.find(p) != m_blocks_sending.end())
613 m_blocks_sending.erase(p);
614 if(m_blocks_sent.find(p) != m_blocks_sent.end())
615 m_blocks_sent.erase(p);
618 void RemoteClient::SetBlocksNotSent(std::map<v3s16, MapBlock*> &blocks)
620 m_nearest_unsent_d = 0;
622 for(std::map<v3s16, MapBlock*>::iterator
624 i != blocks.end(); ++i)
628 if(m_blocks_sending.find(p) != m_blocks_sending.end())
629 m_blocks_sending.erase(p);
630 if(m_blocks_sent.find(p) != m_blocks_sent.end())
631 m_blocks_sent.erase(p);
640 const std::string &path_world,
641 const SubgameSpec &gamespec,
642 bool simple_singleplayer_mode
644 m_path_world(path_world),
645 m_gamespec(gamespec),
646 m_simple_singleplayer_mode(simple_singleplayer_mode),
647 m_async_fatal_error(""),
649 m_con(PROTOCOL_ID, 512, CONNECTION_TIMEOUT,
650 g_settings->getBool("enable_ipv6") && g_settings->getBool("ipv6_server"), this),
653 m_rollback_sink_enabled(true),
654 m_enable_rollback_recording(false),
657 m_itemdef(createItemDefManager()),
658 m_nodedef(createNodeDefManager()),
659 m_craftdef(createCraftDefManager()),
660 m_event(new EventManager()),
662 m_time_of_day_send_timer(0),
664 m_shutdown_requested(false),
665 m_ignore_map_edit_events(false),
666 m_ignore_map_edit_events_peer_id(0)
668 m_liquid_transform_timer = 0.0;
669 m_liquid_transform_every = 1.0;
670 m_print_info_timer = 0.0;
671 m_masterserver_timer = 0.0;
672 m_objectdata_timer = 0.0;
673 m_emergethread_trigger_timer = 0.0;
674 m_savemap_timer = 0.0;
675 m_clients_number = 0;
679 m_step_dtime_mutex.Init();
683 throw ServerError("Supplied empty world path");
685 if(!gamespec.isValid())
686 throw ServerError("Supplied invalid gamespec");
688 infostream<<"Server created for gameid \""<<m_gamespec.id<<"\"";
689 if(m_simple_singleplayer_mode)
690 infostream<<" in simple singleplayer mode"<<std::endl;
692 infostream<<std::endl;
693 infostream<<"- world: "<<m_path_world<<std::endl;
694 infostream<<"- game: "<<m_gamespec.path<<std::endl;
696 // Initialize default settings and override defaults with those provided
698 set_default_settings(g_settings);
699 Settings gamedefaults;
700 getGameMinetestConfig(gamespec.path, gamedefaults);
701 override_default_settings(g_settings, &gamedefaults);
703 // Create server thread
704 m_thread = new ServerThread(this);
706 // Create emerge manager
707 m_emerge = new EmergeManager(this);
709 // Create ban manager
710 std::string ban_path = m_path_world+DIR_DELIM+"ipban.txt";
711 m_banmanager = new BanManager(ban_path);
713 // Create rollback manager
714 std::string rollback_path = m_path_world+DIR_DELIM+"rollback.txt";
715 m_rollback = createRollbackManager(rollback_path, this);
717 // Create world if it doesn't exist
718 if(!initializeWorld(m_path_world, m_gamespec.id))
719 throw ServerError("Failed to initialize world");
721 ModConfiguration modconf(m_path_world);
722 m_mods = modconf.getMods();
723 std::vector<ModSpec> unsatisfied_mods = modconf.getUnsatisfiedMods();
724 // complain about mods with unsatisfied dependencies
725 if(!modconf.isConsistent())
727 for(std::vector<ModSpec>::iterator it = unsatisfied_mods.begin();
728 it != unsatisfied_mods.end(); ++it)
731 errorstream << "mod \"" << mod.name << "\" has unsatisfied dependencies: ";
732 for(std::set<std::string>::iterator dep_it = mod.unsatisfied_depends.begin();
733 dep_it != mod.unsatisfied_depends.end(); ++dep_it)
734 errorstream << " \"" << *dep_it << "\"";
735 errorstream << std::endl;
739 Settings worldmt_settings;
740 std::string worldmt = m_path_world + DIR_DELIM + "world.mt";
741 worldmt_settings.readConfigFile(worldmt.c_str());
742 std::vector<std::string> names = worldmt_settings.getNames();
743 std::set<std::string> load_mod_names;
744 for(std::vector<std::string>::iterator it = names.begin();
745 it != names.end(); ++it)
747 std::string name = *it;
748 if(name.compare(0,9,"load_mod_")==0 && worldmt_settings.getBool(name))
749 load_mod_names.insert(name.substr(9));
751 // complain about mods declared to be loaded, but not found
752 for(std::vector<ModSpec>::iterator it = m_mods.begin();
753 it != m_mods.end(); ++it)
754 load_mod_names.erase((*it).name);
755 for(std::vector<ModSpec>::iterator it = unsatisfied_mods.begin();
756 it != unsatisfied_mods.end(); ++it)
757 load_mod_names.erase((*it).name);
758 if(!load_mod_names.empty())
760 errorstream << "The following mods could not be found:";
761 for(std::set<std::string>::iterator it = load_mod_names.begin();
762 it != load_mod_names.end(); ++it)
763 errorstream << " \"" << (*it) << "\"";
764 errorstream << std::endl;
767 // Path to builtin.lua
768 std::string builtinpath = getBuiltinLuaPath() + DIR_DELIM + "builtin.lua";
771 JMutexAutoLock envlock(m_env_mutex);
772 JMutexAutoLock conlock(m_con_mutex);
774 // Initialize scripting
776 infostream<<"Server: Initializing Lua"<<std::endl;
778 m_script = new GameScripting(this);
781 // Load and run builtin.lua
782 infostream<<"Server: Loading builtin.lua [\""
783 <<builtinpath<<"\"]"<<std::endl;
784 bool success = m_script->loadMod(builtinpath, "__builtin");
786 errorstream<<"Server: Failed to load and run "
787 <<builtinpath<<std::endl;
788 throw ModError("Failed to load and run "+builtinpath);
791 infostream<<"Server: Loading mods: ";
792 for(std::vector<ModSpec>::iterator i = m_mods.begin();
793 i != m_mods.end(); i++){
794 const ModSpec &mod = *i;
795 infostream<<mod.name<<" ";
797 infostream<<std::endl;
798 // Load and run "mod" scripts
799 for(std::vector<ModSpec>::iterator i = m_mods.begin();
800 i != m_mods.end(); i++){
801 const ModSpec &mod = *i;
802 std::string scriptpath = mod.path + DIR_DELIM + "init.lua";
803 infostream<<" ["<<padStringRight(mod.name, 12)<<"] [\""
804 <<scriptpath<<"\"]"<<std::endl;
805 bool success = m_script->loadMod(scriptpath, mod.name);
807 errorstream<<"Server: Failed to load and run "
808 <<scriptpath<<std::endl;
809 throw ModError("Failed to load and run "+scriptpath);
813 // Read Textures and calculate sha1 sums
816 // Apply item aliases in the node definition manager
817 m_nodedef->updateAliases(m_itemdef);
819 // Initialize Environment
820 ServerMap *servermap = new ServerMap(path_world, this, m_emerge);
821 m_env = new ServerEnvironment(servermap, m_script, this, m_emerge);
823 // Run some callbacks after the MG params have been set up but before activation
824 MapgenParams *mgparams = servermap->getMapgenParams();
825 m_script->environment_OnMapgenInit(mgparams);
827 // Initialize mapgens
828 m_emerge->initMapgens(mgparams);
830 // Give environment reference to scripting api
831 m_script->initializeEnvironment(m_env);
833 // Register us to receive map edit events
834 servermap->addEventReceiver(this);
836 // If file exists, load environment metadata
837 if(fs::PathExists(m_path_world+DIR_DELIM+"env_meta.txt"))
839 infostream<<"Server: Loading environment metadata"<<std::endl;
840 m_env->loadMeta(m_path_world);
844 infostream<<"Server: Loading players"<<std::endl;
845 m_env->deSerializePlayers(m_path_world);
848 Add some test ActiveBlockModifiers to environment
850 add_legacy_abms(m_env, m_nodedef);
852 m_liquid_transform_every = g_settings->getFloat("liquid_update");
857 infostream<<"Server destructing"<<std::endl;
860 Send shutdown message
863 JMutexAutoLock conlock(m_con_mutex);
865 std::wstring line = L"*** Server shutting down";
868 Send the message to clients
870 for(std::map<u16, RemoteClient*>::iterator
871 i = m_clients.begin();
872 i != m_clients.end(); ++i)
874 // Get client and check that it is valid
875 RemoteClient *client = i->second;
876 assert(client->peer_id == i->first);
877 if(client->serialization_version == SER_FMT_VER_INVALID)
881 SendChatMessage(client->peer_id, line);
883 catch(con::PeerNotFoundException &e)
889 JMutexAutoLock envlock(m_env_mutex);
890 JMutexAutoLock conlock(m_con_mutex);
893 Execute script shutdown hooks
895 m_script->on_shutdown();
899 JMutexAutoLock envlock(m_env_mutex);
904 infostream<<"Server: Saving players"<<std::endl;
905 m_env->serializePlayers(m_path_world);
908 Save environment metadata
910 infostream<<"Server: Saving environment metadata"<<std::endl;
911 m_env->saveMeta(m_path_world);
920 //shutdown all emerge threads first!
927 JMutexAutoLock clientslock(m_con_mutex);
929 for(std::map<u16, RemoteClient*>::iterator
930 i = m_clients.begin();
931 i != m_clients.end(); ++i)
939 // Delete things in the reverse order of creation
948 // Deinitialize scripting
949 infostream<<"Server: Deinitializing scripting"<<std::endl;
952 // Delete detached inventories
954 for(std::map<std::string, Inventory*>::iterator
955 i = m_detached_inventories.begin();
956 i != m_detached_inventories.end(); i++){
962 void Server::start(unsigned short port)
964 DSTACK(__FUNCTION_NAME);
965 infostream<<"Starting server on port "<<port<<"..."<<std::endl;
967 // Stop thread if already running
970 // Initialize connection
971 m_con.SetTimeoutMs(30);
975 m_thread->setRun(true);
978 // ASCII art for the win!
980 <<" .__ __ __ "<<std::endl
981 <<" _____ |__| ____ _____/ |_ ____ _______/ |_ "<<std::endl
982 <<" / \\| |/ \\_/ __ \\ __\\/ __ \\ / ___/\\ __\\"<<std::endl
983 <<"| Y Y \\ | | \\ ___/| | \\ ___/ \\___ \\ | | "<<std::endl
984 <<"|__|_| /__|___| /\\___ >__| \\___ >____ > |__| "<<std::endl
985 <<" \\/ \\/ \\/ \\/ \\/ "<<std::endl;
986 actionstream<<"World at ["<<m_path_world<<"]"<<std::endl;
987 actionstream<<"Server for gameid=\""<<m_gamespec.id
988 <<"\" listening on port "<<port<<"."<<std::endl;
993 DSTACK(__FUNCTION_NAME);
995 infostream<<"Server: Stopping and waiting threads"<<std::endl;
997 // Stop threads (set run=false first so both start stopping)
998 m_thread->setRun(false);
999 //m_emergethread.setRun(false);
1001 //m_emergethread.stop();
1003 infostream<<"Server: Threads stopped"<<std::endl;
1006 void Server::step(float dtime)
1008 DSTACK(__FUNCTION_NAME);
1013 JMutexAutoLock lock(m_step_dtime_mutex);
1014 m_step_dtime += dtime;
1016 // Throw if fatal error occurred in thread
1017 std::string async_err = m_async_fatal_error.get();
1018 if(async_err != ""){
1019 throw ServerError(async_err);
1023 void Server::AsyncRunStep()
1025 DSTACK(__FUNCTION_NAME);
1027 g_profiler->add("Server::AsyncRunStep (num)", 1);
1031 JMutexAutoLock lock1(m_step_dtime_mutex);
1032 dtime = m_step_dtime;
1036 // Send blocks to clients
1043 g_profiler->add("Server::AsyncRunStep with dtime (num)", 1);
1045 //infostream<<"Server steps "<<dtime<<std::endl;
1046 //infostream<<"Server::AsyncRunStep(): dtime="<<dtime<<std::endl;
1049 JMutexAutoLock lock1(m_step_dtime_mutex);
1050 m_step_dtime -= dtime;
1057 m_uptime.set(m_uptime.get() + dtime);
1061 // Process connection's timeouts
1062 JMutexAutoLock lock2(m_con_mutex);
1063 ScopeProfiler sp(g_profiler, "Server: connection timeout processing");
1064 m_con.RunTimeouts(dtime);
1068 // This has to be called so that the client list gets synced
1069 // with the peer list of the connection
1070 handlePeerChanges();
1074 Update time of day and overall game time
1077 JMutexAutoLock envlock(m_env_mutex);
1079 m_env->setTimeOfDaySpeed(g_settings->getFloat("time_speed"));
1082 Send to clients at constant intervals
1085 m_time_of_day_send_timer -= dtime;
1086 if(m_time_of_day_send_timer < 0.0)
1088 m_time_of_day_send_timer = g_settings->getFloat("time_send_interval");
1090 //JMutexAutoLock envlock(m_env_mutex);
1091 JMutexAutoLock conlock(m_con_mutex);
1093 u16 time = m_env->getTimeOfDay();
1094 float time_speed = g_settings->getFloat("time_speed");
1096 for(std::map<u16, RemoteClient*>::iterator
1097 i = m_clients.begin();
1098 i != m_clients.end(); ++i)
1100 RemoteClient *client = i->second;
1101 SendTimeOfDay(client->peer_id, time, time_speed);
1107 JMutexAutoLock lock(m_env_mutex);
1108 // Figure out and report maximum lag to environment
1109 float max_lag = m_env->getMaxLagEstimate();
1110 max_lag *= 0.9998; // Decrease slowly (about half per 5 minutes)
1111 if(dtime > max_lag){
1112 if(dtime > 0.1 && dtime > max_lag * 2.0)
1113 infostream<<"Server: Maximum lag peaked to "<<dtime
1117 m_env->reportMaxLagEstimate(max_lag);
1119 ScopeProfiler sp(g_profiler, "SEnv step");
1120 ScopeProfiler sp2(g_profiler, "SEnv step avg", SPT_AVG);
1124 const float map_timer_and_unload_dtime = 2.92;
1125 if(m_map_timer_and_unload_interval.step(dtime, map_timer_and_unload_dtime))
1127 JMutexAutoLock lock(m_env_mutex);
1128 // Run Map's timers and unload unused data
1129 ScopeProfiler sp(g_profiler, "Server: map timer and unload");
1130 m_env->getMap().timerUpdate(map_timer_and_unload_dtime,
1131 g_settings->getFloat("server_unload_unused_data_timeout"));
1142 JMutexAutoLock lock(m_env_mutex);
1143 JMutexAutoLock lock2(m_con_mutex);
1145 ScopeProfiler sp(g_profiler, "Server: handle players");
1147 for(std::map<u16, RemoteClient*>::iterator
1148 i = m_clients.begin();
1149 i != m_clients.end(); ++i)
1151 RemoteClient *client = i->second;
1152 PlayerSAO *playersao = getPlayerSAO(client->peer_id);
1153 if(playersao == NULL)
1157 Handle player HPs (die if hp=0)
1159 if(playersao->m_hp_not_sent && g_settings->getBool("enable_damage"))
1161 if(playersao->getHP() == 0)
1162 DiePlayer(client->peer_id);
1164 SendPlayerHP(client->peer_id);
1168 Send player breath if changed
1170 if(playersao->m_breath_not_sent){
1171 SendPlayerBreath(client->peer_id);
1175 Send player inventories if necessary
1177 if(playersao->m_moved){
1178 SendMovePlayer(client->peer_id);
1179 playersao->m_moved = false;
1181 if(playersao->m_inventory_not_sent){
1182 UpdateCrafting(client->peer_id);
1183 SendInventory(client->peer_id);
1188 /* Transform liquids */
1189 m_liquid_transform_timer += dtime;
1190 if(m_liquid_transform_timer >= m_liquid_transform_every)
1192 m_liquid_transform_timer -= m_liquid_transform_every;
1194 JMutexAutoLock lock(m_env_mutex);
1196 ScopeProfiler sp(g_profiler, "Server: liquid transform");
1198 std::map<v3s16, MapBlock*> modified_blocks;
1199 m_env->getMap().transformLiquids(modified_blocks);
1204 core::map<v3s16, MapBlock*> lighting_modified_blocks;
1205 ServerMap &map = ((ServerMap&)m_env->getMap());
1206 map.updateLighting(modified_blocks, lighting_modified_blocks);
1208 // Add blocks modified by lighting to modified_blocks
1209 for(core::map<v3s16, MapBlock*>::Iterator
1210 i = lighting_modified_blocks.getIterator();
1211 i.atEnd() == false; i++)
1213 MapBlock *block = i.getNode()->getValue();
1214 modified_blocks.insert(block->getPos(), block);
1218 Set the modified blocks unsent for all the clients
1221 JMutexAutoLock lock2(m_con_mutex);
1223 for(std::map<u16, RemoteClient*>::iterator
1224 i = m_clients.begin();
1225 i != m_clients.end(); ++i)
1227 RemoteClient *client = i->second;
1229 if(modified_blocks.size() > 0)
1231 // Remove block from sent history
1232 client->SetBlocksNotSent(modified_blocks);
1237 // Periodically print some info
1239 float &counter = m_print_info_timer;
1245 JMutexAutoLock lock2(m_con_mutex);
1246 m_clients_number = 0;
1247 if(m_clients.size() != 0)
1248 infostream<<"Players:"<<std::endl;
1249 for(std::map<u16, RemoteClient*>::iterator
1250 i = m_clients.begin();
1251 i != m_clients.end(); ++i)
1253 //u16 peer_id = i.getNode()->getKey();
1254 RemoteClient *client = i->second;
1255 Player *player = m_env->getPlayer(client->peer_id);
1258 infostream<<"* "<<player->getName()<<"\t";
1259 client->PrintInfo(infostream);
1267 // send masterserver announce
1269 float &counter = m_masterserver_timer;
1270 if(!isSingleplayer() && (!counter || counter >= 300.0) && g_settings->getBool("server_announce") == true)
1272 ServerList::sendAnnounce(!counter ? "start" : "update", m_clients_number, m_uptime.get(), m_gamespec.id, m_mods);
1279 //if(g_settings->getBool("enable_experimental"))
1283 Check added and deleted active objects
1286 //infostream<<"Server: Checking added and deleted active objects"<<std::endl;
1287 JMutexAutoLock envlock(m_env_mutex);
1288 JMutexAutoLock conlock(m_con_mutex);
1290 ScopeProfiler sp(g_profiler, "Server: checking added and deleted objs");
1292 // Radius inside which objects are active
1293 s16 radius = g_settings->getS16("active_object_send_range_blocks");
1294 radius *= MAP_BLOCKSIZE;
1296 for(std::map<u16, RemoteClient*>::iterator
1297 i = m_clients.begin();
1298 i != m_clients.end(); ++i)
1300 RemoteClient *client = i->second;
1302 // If definitions and textures have not been sent, don't
1303 // send objects either
1304 if(!client->definitions_sent)
1307 Player *player = m_env->getPlayer(client->peer_id);
1310 // This can happen if the client timeouts somehow
1311 /*infostream<<"WARNING: "<<__FUNCTION_NAME<<": Client "
1313 <<" has no associated player"<<std::endl;*/
1316 v3s16 pos = floatToInt(player->getPosition(), BS);
1318 std::set<u16> removed_objects;
1319 std::set<u16> added_objects;
1320 m_env->getRemovedActiveObjects(pos, radius,
1321 client->m_known_objects, removed_objects);
1322 m_env->getAddedActiveObjects(pos, radius,
1323 client->m_known_objects, added_objects);
1325 // Ignore if nothing happened
1326 if(removed_objects.size() == 0 && added_objects.size() == 0)
1328 //infostream<<"active objects: none changed"<<std::endl;
1332 std::string data_buffer;
1336 // Handle removed objects
1337 writeU16((u8*)buf, removed_objects.size());
1338 data_buffer.append(buf, 2);
1339 for(std::set<u16>::iterator
1340 i = removed_objects.begin();
1341 i != removed_objects.end(); ++i)
1345 ServerActiveObject* obj = m_env->getActiveObject(id);
1347 // Add to data buffer for sending
1348 writeU16((u8*)buf, id);
1349 data_buffer.append(buf, 2);
1351 // Remove from known objects
1352 client->m_known_objects.erase(id);
1354 if(obj && obj->m_known_by_count > 0)
1355 obj->m_known_by_count--;
1358 // Handle added objects
1359 writeU16((u8*)buf, added_objects.size());
1360 data_buffer.append(buf, 2);
1361 for(std::set<u16>::iterator
1362 i = added_objects.begin();
1363 i != added_objects.end(); ++i)
1367 ServerActiveObject* obj = m_env->getActiveObject(id);
1370 u8 type = ACTIVEOBJECT_TYPE_INVALID;
1372 infostream<<"WARNING: "<<__FUNCTION_NAME
1373 <<": NULL object"<<std::endl;
1375 type = obj->getSendType();
1377 // Add to data buffer for sending
1378 writeU16((u8*)buf, id);
1379 data_buffer.append(buf, 2);
1380 writeU8((u8*)buf, type);
1381 data_buffer.append(buf, 1);
1384 data_buffer.append(serializeLongString(
1385 obj->getClientInitializationData(client->net_proto_version)));
1387 data_buffer.append(serializeLongString(""));
1389 // Add to known objects
1390 client->m_known_objects.insert(id);
1393 obj->m_known_by_count++;
1397 SharedBuffer<u8> reply(2 + data_buffer.size());
1398 writeU16(&reply[0], TOCLIENT_ACTIVE_OBJECT_REMOVE_ADD);
1399 memcpy((char*)&reply[2], data_buffer.c_str(),
1400 data_buffer.size());
1402 m_con.Send(client->peer_id, 0, reply, true);
1404 verbosestream<<"Server: Sent object remove/add: "
1405 <<removed_objects.size()<<" removed, "
1406 <<added_objects.size()<<" added, "
1407 <<"packet size is "<<reply.getSize()<<std::endl;
1412 Collect a list of all the objects known by the clients
1413 and report it back to the environment.
1416 core::map<u16, bool> all_known_objects;
1418 for(core::map<u16, RemoteClient*>::Iterator
1419 i = m_clients.getIterator();
1420 i.atEnd() == false; i++)
1422 RemoteClient *client = i.getNode()->getValue();
1423 // Go through all known objects of client
1424 for(core::map<u16, bool>::Iterator
1425 i = client->m_known_objects.getIterator();
1426 i.atEnd()==false; i++)
1428 u16 id = i.getNode()->getKey();
1429 all_known_objects[id] = true;
1433 m_env->setKnownActiveObjects(whatever);
1439 Send object messages
1442 JMutexAutoLock envlock(m_env_mutex);
1443 JMutexAutoLock conlock(m_con_mutex);
1445 ScopeProfiler sp(g_profiler, "Server: sending object messages");
1448 // Value = data sent by object
1449 std::map<u16, std::list<ActiveObjectMessage>* > buffered_messages;
1451 // Get active object messages from environment
1454 ActiveObjectMessage aom = m_env->getActiveObjectMessage();
1458 std::list<ActiveObjectMessage>* message_list = NULL;
1459 std::map<u16, std::list<ActiveObjectMessage>* >::iterator n;
1460 n = buffered_messages.find(aom.id);
1461 if(n == buffered_messages.end())
1463 message_list = new std::list<ActiveObjectMessage>;
1464 buffered_messages[aom.id] = message_list;
1468 message_list = n->second;
1470 message_list->push_back(aom);
1473 // Route data to every client
1474 for(std::map<u16, RemoteClient*>::iterator
1475 i = m_clients.begin();
1476 i != m_clients.end(); ++i)
1478 RemoteClient *client = i->second;
1479 std::string reliable_data;
1480 std::string unreliable_data;
1481 // Go through all objects in message buffer
1482 for(std::map<u16, std::list<ActiveObjectMessage>* >::iterator
1483 j = buffered_messages.begin();
1484 j != buffered_messages.end(); ++j)
1486 // If object is not known by client, skip it
1488 if(client->m_known_objects.find(id) == client->m_known_objects.end())
1490 // Get message list of object
1491 std::list<ActiveObjectMessage>* list = j->second;
1492 // Go through every message
1493 for(std::list<ActiveObjectMessage>::iterator
1494 k = list->begin(); k != list->end(); ++k)
1496 // Compose the full new data with header
1497 ActiveObjectMessage aom = *k;
1498 std::string new_data;
1501 writeU16((u8*)&buf[0], aom.id);
1502 new_data.append(buf, 2);
1504 new_data += serializeString(aom.datastring);
1505 // Add data to buffer
1507 reliable_data += new_data;
1509 unreliable_data += new_data;
1513 reliable_data and unreliable_data are now ready.
1516 if(reliable_data.size() > 0)
1518 SharedBuffer<u8> reply(2 + reliable_data.size());
1519 writeU16(&reply[0], TOCLIENT_ACTIVE_OBJECT_MESSAGES);
1520 memcpy((char*)&reply[2], reliable_data.c_str(),
1521 reliable_data.size());
1523 m_con.Send(client->peer_id, 0, reply, true);
1525 if(unreliable_data.size() > 0)
1527 SharedBuffer<u8> reply(2 + unreliable_data.size());
1528 writeU16(&reply[0], TOCLIENT_ACTIVE_OBJECT_MESSAGES);
1529 memcpy((char*)&reply[2], unreliable_data.c_str(),
1530 unreliable_data.size());
1531 // Send as unreliable
1532 m_con.Send(client->peer_id, 0, reply, false);
1535 /*if(reliable_data.size() > 0 || unreliable_data.size() > 0)
1537 infostream<<"Server: Size of object message data: "
1538 <<"reliable: "<<reliable_data.size()
1539 <<", unreliable: "<<unreliable_data.size()
1544 // Clear buffered_messages
1545 for(std::map<u16, std::list<ActiveObjectMessage>* >::iterator
1546 i = buffered_messages.begin();
1547 i != buffered_messages.end(); ++i)
1553 } // enable_experimental
1556 Send queued-for-sending map edit events.
1559 // We will be accessing the environment and the connection
1560 JMutexAutoLock lock(m_env_mutex);
1561 JMutexAutoLock conlock(m_con_mutex);
1563 // Don't send too many at a time
1566 // Single change sending is disabled if queue size is not small
1567 bool disable_single_change_sending = false;
1568 if(m_unsent_map_edit_queue.size() >= 4)
1569 disable_single_change_sending = true;
1571 int event_count = m_unsent_map_edit_queue.size();
1573 // We'll log the amount of each
1576 while(m_unsent_map_edit_queue.size() != 0)
1578 MapEditEvent* event = m_unsent_map_edit_queue.pop_front();
1580 // Players far away from the change are stored here.
1581 // Instead of sending the changes, MapBlocks are set not sent
1583 std::list<u16> far_players;
1585 if(event->type == MEET_ADDNODE)
1587 //infostream<<"Server: MEET_ADDNODE"<<std::endl;
1588 prof.add("MEET_ADDNODE", 1);
1589 if(disable_single_change_sending)
1590 sendAddNode(event->p, event->n, event->already_known_by_peer,
1593 sendAddNode(event->p, event->n, event->already_known_by_peer,
1596 else if(event->type == MEET_REMOVENODE)
1598 //infostream<<"Server: MEET_REMOVENODE"<<std::endl;
1599 prof.add("MEET_REMOVENODE", 1);
1600 if(disable_single_change_sending)
1601 sendRemoveNode(event->p, event->already_known_by_peer,
1604 sendRemoveNode(event->p, event->already_known_by_peer,
1607 else if(event->type == MEET_BLOCK_NODE_METADATA_CHANGED)
1609 infostream<<"Server: MEET_BLOCK_NODE_METADATA_CHANGED"<<std::endl;
1610 prof.add("MEET_BLOCK_NODE_METADATA_CHANGED", 1);
1611 setBlockNotSent(event->p);
1613 else if(event->type == MEET_OTHER)
1615 infostream<<"Server: MEET_OTHER"<<std::endl;
1616 prof.add("MEET_OTHER", 1);
1617 for(std::set<v3s16>::iterator
1618 i = event->modified_blocks.begin();
1619 i != event->modified_blocks.end(); ++i)
1621 setBlockNotSent(*i);
1626 prof.add("unknown", 1);
1627 infostream<<"WARNING: Server: Unknown MapEditEvent "
1628 <<((u32)event->type)<<std::endl;
1632 Set blocks not sent to far players
1634 if(far_players.size() > 0)
1636 // Convert list format to that wanted by SetBlocksNotSent
1637 std::map<v3s16, MapBlock*> modified_blocks2;
1638 for(std::set<v3s16>::iterator
1639 i = event->modified_blocks.begin();
1640 i != event->modified_blocks.end(); ++i)
1642 modified_blocks2[*i] =
1643 m_env->getMap().getBlockNoCreateNoEx(*i);
1645 // Set blocks not sent
1646 for(std::list<u16>::iterator
1647 i = far_players.begin();
1648 i != far_players.end(); ++i)
1651 RemoteClient *client = getClient(peer_id);
1654 client->SetBlocksNotSent(modified_blocks2);
1660 /*// Don't send too many at a time
1662 if(count >= 1 && m_unsent_map_edit_queue.size() < 100)
1666 if(event_count >= 5){
1667 infostream<<"Server: MapEditEvents:"<<std::endl;
1668 prof.print(infostream);
1669 } else if(event_count != 0){
1670 verbosestream<<"Server: MapEditEvents:"<<std::endl;
1671 prof.print(verbosestream);
1677 Trigger emergethread (it somehow gets to a non-triggered but
1678 bysy state sometimes)
1681 float &counter = m_emergethread_trigger_timer;
1687 m_emerge->triggerAllThreads();
1689 // Update m_enable_rollback_recording here too
1690 m_enable_rollback_recording =
1691 g_settings->getBool("enable_rollback_recording");
1695 // Save map, players and auth stuff
1697 float &counter = m_savemap_timer;
1699 if(counter >= g_settings->getFloat("server_map_save_interval"))
1702 JMutexAutoLock lock(m_env_mutex);
1704 ScopeProfiler sp(g_profiler, "Server: saving stuff");
1707 if(m_banmanager->isModified())
1708 m_banmanager->save();
1710 // Save changed parts of map
1711 m_env->getMap().save(MOD_STATE_WRITE_NEEDED);
1714 m_env->serializePlayers(m_path_world);
1716 // Save environment metadata
1717 m_env->saveMeta(m_path_world);
1722 void Server::Receive()
1724 DSTACK(__FUNCTION_NAME);
1725 SharedBuffer<u8> data;
1730 JMutexAutoLock conlock(m_con_mutex);
1731 datasize = m_con.Receive(peer_id, data);
1734 // This has to be called so that the client list gets synced
1735 // with the peer list of the connection
1736 handlePeerChanges();
1738 ProcessData(*data, datasize, peer_id);
1740 catch(con::InvalidIncomingDataException &e)
1742 infostream<<"Server::Receive(): "
1743 "InvalidIncomingDataException: what()="
1744 <<e.what()<<std::endl;
1746 catch(con::PeerNotFoundException &e)
1748 //NOTE: This is not needed anymore
1750 // The peer has been disconnected.
1751 // Find the associated player and remove it.
1753 /*JMutexAutoLock envlock(m_env_mutex);
1755 infostream<<"ServerThread: peer_id="<<peer_id
1756 <<" has apparently closed connection. "
1757 <<"Removing player."<<std::endl;
1759 m_env->removePlayer(peer_id);*/
1763 void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
1765 DSTACK(__FUNCTION_NAME);
1766 // Environment is locked first.
1767 JMutexAutoLock envlock(m_env_mutex);
1768 JMutexAutoLock conlock(m_con_mutex);
1770 ScopeProfiler sp(g_profiler, "Server::ProcessData");
1774 Address address = m_con.GetPeerAddress(peer_id);
1775 addr_s = address.serializeString();
1777 // drop player if is ip is banned
1778 if(m_banmanager->isIpBanned(addr_s)){
1779 infostream<<"Server: A banned client tried to connect from "
1780 <<addr_s<<"; banned name was "
1781 <<m_banmanager->getBanName(addr_s)<<std::endl;
1782 // This actually doesn't seem to transfer to the client
1783 DenyAccess(peer_id, L"Your ip is banned. Banned name was "
1784 +narrow_to_wide(m_banmanager->getBanName(addr_s)));
1785 m_con.DeletePeer(peer_id);
1789 catch(con::PeerNotFoundException &e)
1791 infostream<<"Server::ProcessData(): Cancelling: peer "
1792 <<peer_id<<" not found"<<std::endl;
1796 u8 peer_ser_ver = getClient(peer_id)->serialization_version;
1804 ToServerCommand command = (ToServerCommand)readU16(&data[0]);
1806 if(command == TOSERVER_INIT)
1808 // [0] u16 TOSERVER_INIT
1809 // [2] u8 SER_FMT_VER_HIGHEST_READ
1810 // [3] u8[20] player_name
1811 // [23] u8[28] password <--- can be sent without this, from old versions
1813 if(datasize < 2+1+PLAYERNAME_SIZE)
1816 // If net_proto_version is set, this client has already been handled
1817 if(getClient(peer_id)->net_proto_version != 0){
1818 verbosestream<<"Server: Ignoring multiple TOSERVER_INITs from "
1819 <<addr_s<<" (peer_id="<<peer_id<<")"<<std::endl;
1823 verbosestream<<"Server: Got TOSERVER_INIT from "<<addr_s<<" (peer_id="
1824 <<peer_id<<")"<<std::endl;
1826 // Do not allow multiple players in simple singleplayer mode.
1827 // This isn't a perfect way to do it, but will suffice for now.
1828 if(m_simple_singleplayer_mode && m_clients.size() > 1){
1829 infostream<<"Server: Not allowing another client ("<<addr_s
1830 <<") to connect in simple singleplayer mode"<<std::endl;
1831 DenyAccess(peer_id, L"Running in simple singleplayer mode.");
1835 // First byte after command is maximum supported
1836 // serialization version
1837 u8 client_max = data[2];
1838 u8 our_max = SER_FMT_VER_HIGHEST_READ;
1839 // Use the highest version supported by both
1840 u8 deployed = std::min(client_max, our_max);
1841 // If it's lower than the lowest supported, give up.
1842 if(deployed < SER_FMT_VER_LOWEST)
1843 deployed = SER_FMT_VER_INVALID;
1845 //peer->serialization_version = deployed;
1846 getClient(peer_id)->pending_serialization_version = deployed;
1848 if(deployed == SER_FMT_VER_INVALID)
1850 actionstream<<"Server: A mismatched client tried to connect from "
1851 <<addr_s<<std::endl;
1852 infostream<<"Server: Cannot negotiate serialization version with "
1853 <<addr_s<<std::endl;
1854 DenyAccess(peer_id, std::wstring(
1855 L"Your client's version is not supported.\n"
1856 L"Server version is ")
1857 + narrow_to_wide(VERSION_STRING) + L"."
1863 Read and check network protocol version
1866 u16 min_net_proto_version = 0;
1867 if(datasize >= 2+1+PLAYERNAME_SIZE+PASSWORD_SIZE+2)
1868 min_net_proto_version = readU16(&data[2+1+PLAYERNAME_SIZE+PASSWORD_SIZE]);
1870 // Use same version as minimum and maximum if maximum version field
1871 // doesn't exist (backwards compatibility)
1872 u16 max_net_proto_version = min_net_proto_version;
1873 if(datasize >= 2+1+PLAYERNAME_SIZE+PASSWORD_SIZE+2+2)
1874 max_net_proto_version = readU16(&data[2+1+PLAYERNAME_SIZE+PASSWORD_SIZE+2]);
1876 // Start with client's maximum version
1877 u16 net_proto_version = max_net_proto_version;
1879 // Figure out a working version if it is possible at all
1880 if(max_net_proto_version >= SERVER_PROTOCOL_VERSION_MIN ||
1881 min_net_proto_version <= SERVER_PROTOCOL_VERSION_MAX)
1883 // If maximum is larger than our maximum, go with our maximum
1884 if(max_net_proto_version > SERVER_PROTOCOL_VERSION_MAX)
1885 net_proto_version = SERVER_PROTOCOL_VERSION_MAX;
1886 // Else go with client's maximum
1888 net_proto_version = max_net_proto_version;
1891 verbosestream<<"Server: "<<addr_s<<": Protocol version: min: "
1892 <<min_net_proto_version<<", max: "<<max_net_proto_version
1893 <<", chosen: "<<net_proto_version<<std::endl;
1895 getClient(peer_id)->net_proto_version = net_proto_version;
1897 if(net_proto_version < SERVER_PROTOCOL_VERSION_MIN ||
1898 net_proto_version > SERVER_PROTOCOL_VERSION_MAX)
1900 actionstream<<"Server: A mismatched client tried to connect from "
1901 <<addr_s<<std::endl;
1902 DenyAccess(peer_id, std::wstring(
1903 L"Your client's version is not supported.\n"
1904 L"Server version is ")
1905 + narrow_to_wide(VERSION_STRING) + L",\n"
1906 + L"server's PROTOCOL_VERSION is "
1907 + narrow_to_wide(itos(SERVER_PROTOCOL_VERSION_MIN))
1909 + narrow_to_wide(itos(SERVER_PROTOCOL_VERSION_MAX))
1910 + L", client's PROTOCOL_VERSION is "
1911 + narrow_to_wide(itos(min_net_proto_version))
1913 + narrow_to_wide(itos(max_net_proto_version))
1918 if(g_settings->getBool("strict_protocol_version_checking"))
1920 if(net_proto_version != LATEST_PROTOCOL_VERSION)
1922 actionstream<<"Server: A mismatched (strict) client tried to "
1923 <<"connect from "<<addr_s<<std::endl;
1924 DenyAccess(peer_id, std::wstring(
1925 L"Your client's version is not supported.\n"
1926 L"Server version is ")
1927 + narrow_to_wide(VERSION_STRING) + L",\n"
1928 + L"server's PROTOCOL_VERSION (strict) is "
1929 + narrow_to_wide(itos(LATEST_PROTOCOL_VERSION))
1930 + L", client's PROTOCOL_VERSION is "
1931 + narrow_to_wide(itos(min_net_proto_version))
1933 + narrow_to_wide(itos(max_net_proto_version))
1944 char playername[PLAYERNAME_SIZE];
1945 for(u32 i=0; i<PLAYERNAME_SIZE-1; i++)
1947 playername[i] = data[3+i];
1949 playername[PLAYERNAME_SIZE-1] = 0;
1951 if(playername[0]=='\0')
1953 actionstream<<"Server: Player with an empty name "
1954 <<"tried to connect from "<<addr_s<<std::endl;
1955 DenyAccess(peer_id, L"Empty name");
1959 if(string_allowed(playername, PLAYERNAME_ALLOWED_CHARS)==false)
1961 actionstream<<"Server: Player with an invalid name "
1962 <<"tried to connect from "<<addr_s<<std::endl;
1963 DenyAccess(peer_id, L"Name contains unallowed characters");
1967 if(!isSingleplayer() && strcasecmp(playername, "singleplayer") == 0)
1969 actionstream<<"Server: Player with the name \"singleplayer\" "
1970 <<"tried to connect from "<<addr_s<<std::endl;
1971 DenyAccess(peer_id, L"Name is not allowed");
1975 infostream<<"Server: New connection: \""<<playername<<"\" from "
1976 <<addr_s<<" (peer_id="<<peer_id<<")"<<std::endl;
1979 char given_password[PASSWORD_SIZE];
1980 if(datasize < 2+1+PLAYERNAME_SIZE+PASSWORD_SIZE)
1982 // old version - assume blank password
1983 given_password[0] = 0;
1987 for(u32 i=0; i<PASSWORD_SIZE-1; i++)
1989 given_password[i] = data[23+i];
1991 given_password[PASSWORD_SIZE-1] = 0;
1994 if(!base64_is_valid(given_password)){
1995 actionstream<<"Server: "<<playername
1996 <<" supplied invalid password hash"<<std::endl;
1997 DenyAccess(peer_id, L"Invalid password hash");
2001 // Enforce user limit.
2002 // Don't enforce for users that have some admin right
2003 if(m_clients.size() >= g_settings->getU16("max_users") &&
2004 !checkPriv(playername, "server") &&
2005 !checkPriv(playername, "ban") &&
2006 !checkPriv(playername, "privs") &&
2007 !checkPriv(playername, "password") &&
2008 playername != g_settings->get("name"))
2010 actionstream<<"Server: "<<playername<<" tried to join, but there"
2011 <<" are already max_users="
2012 <<g_settings->getU16("max_users")<<" players."<<std::endl;
2013 DenyAccess(peer_id, L"Too many users.");
2017 std::string checkpwd; // Password hash to check against
2018 bool has_auth = m_script->getAuth(playername, &checkpwd, NULL);
2020 // If no authentication info exists for user, create it
2022 if(!isSingleplayer() &&
2023 g_settings->getBool("disallow_empty_password") &&
2024 std::string(given_password) == ""){
2025 actionstream<<"Server: "<<playername
2026 <<" supplied empty password"<<std::endl;
2027 DenyAccess(peer_id, L"Empty passwords are "
2028 L"disallowed. Set a password and try again.");
2031 std::wstring raw_default_password =
2032 narrow_to_wide(g_settings->get("default_password"));
2033 std::string initial_password =
2034 translatePassword(playername, raw_default_password);
2036 // If default_password is empty, allow any initial password
2037 if (raw_default_password.length() == 0)
2038 initial_password = given_password;
2040 m_script->createAuth(playername, initial_password);
2043 has_auth = m_script->getAuth(playername, &checkpwd, NULL);
2046 actionstream<<"Server: "<<playername<<" cannot be authenticated"
2047 <<" (auth handler does not work?)"<<std::endl;
2048 DenyAccess(peer_id, L"Not allowed to login");
2052 if(given_password != checkpwd){
2053 actionstream<<"Server: "<<playername<<" supplied wrong password"
2055 DenyAccess(peer_id, L"Wrong password");
2060 PlayerSAO *playersao = emergePlayer(playername, peer_id);
2062 // If failed, cancel
2063 if(playersao == NULL)
2065 RemotePlayer *player =
2066 static_cast<RemotePlayer*>(m_env->getPlayer(playername));
2067 if(player && player->peer_id != 0){
2068 errorstream<<"Server: "<<playername<<": Failed to emerge player"
2069 <<" (player allocated to an another client)"<<std::endl;
2070 DenyAccess(peer_id, L"Another client is connected with this "
2071 L"name. If your client closed unexpectedly, try again in "
2074 errorstream<<"Server: "<<playername<<": Failed to emerge player"
2076 DenyAccess(peer_id, L"Could not allocate player.");
2082 Answer with a TOCLIENT_INIT
2085 SharedBuffer<u8> reply(2+1+6+8+4);
2086 writeU16(&reply[0], TOCLIENT_INIT);
2087 writeU8(&reply[2], deployed);
2088 writeV3S16(&reply[2+1], floatToInt(playersao->getPlayer()->getPosition()+v3f(0,BS/2,0), BS));
2089 writeU64(&reply[2+1+6], m_env->getServerMap().getSeed());
2090 writeF1000(&reply[2+1+6+8], g_settings->getFloat("dedicated_server_step"));
2093 m_con.Send(peer_id, 0, reply, true);
2097 Send complete position information
2099 SendMovePlayer(peer_id);
2104 if(command == TOSERVER_INIT2)
2106 verbosestream<<"Server: Got TOSERVER_INIT2 from "
2107 <<peer_id<<std::endl;
2109 Player *player = m_env->getPlayer(peer_id);
2111 verbosestream<<"Server: TOSERVER_INIT2: "
2112 <<"Player not found; ignoring."<<std::endl;
2116 RemoteClient *client = getClient(peer_id);
2117 client->serialization_version =
2118 getClient(peer_id)->pending_serialization_version;
2121 Send some initialization data
2124 infostream<<"Server: Sending content to "
2125 <<getPlayerName(peer_id)<<std::endl;
2127 // Send player movement settings
2128 SendMovement(m_con, peer_id);
2130 // Send item definitions
2131 SendItemDef(m_con, peer_id, m_itemdef, client->net_proto_version);
2133 // Send node definitions
2134 SendNodeDef(m_con, peer_id, m_nodedef, client->net_proto_version);
2136 // Send media announcement
2137 sendMediaAnnouncement(peer_id);
2140 SendPlayerPrivileges(peer_id);
2142 // Send inventory formspec
2143 SendPlayerInventoryFormspec(peer_id);
2146 UpdateCrafting(peer_id);
2147 SendInventory(peer_id);
2150 if(g_settings->getBool("enable_damage"))
2151 SendPlayerHP(peer_id);
2154 SendPlayerBreath(peer_id);
2156 // Send detached inventories
2157 sendDetachedInventories(peer_id);
2159 // Show death screen if necessary
2161 SendDeathscreen(m_con, peer_id, false, v3f(0,0,0));
2165 u16 time = m_env->getTimeOfDay();
2166 float time_speed = g_settings->getFloat("time_speed");
2167 SendTimeOfDay(peer_id, time, time_speed);
2170 // Note things in chat if not in simple singleplayer mode
2171 if(!m_simple_singleplayer_mode)
2173 // Send information about server to player in chat
2174 SendChatMessage(peer_id, getStatusString());
2176 // Send information about joining in chat
2178 std::wstring name = L"unknown";
2179 Player *player = m_env->getPlayer(peer_id);
2181 name = narrow_to_wide(player->getName());
2183 std::wstring message;
2186 message += L" joined the game.";
2187 BroadcastChatMessage(message);
2191 // Warnings about protocol version can be issued here
2192 if(getClient(peer_id)->net_proto_version < LATEST_PROTOCOL_VERSION)
2194 SendChatMessage(peer_id, L"# Server: WARNING: YOUR CLIENT'S "
2195 L"VERSION MAY NOT BE FULLY COMPATIBLE WITH THIS SERVER!");
2202 std::ostringstream os(std::ios_base::binary);
2203 for(std::map<u16, RemoteClient*>::iterator
2204 i = m_clients.begin();
2205 i != m_clients.end(); ++i)
2207 RemoteClient *client = i->second;
2208 assert(client->peer_id == i->first);
2209 if(client->serialization_version == SER_FMT_VER_INVALID)
2212 Player *player = m_env->getPlayer(client->peer_id);
2215 // Get name of player
2216 os<<player->getName()<<" ";
2219 actionstream<<player->getName()<<" ["<<addr_s<<"] "<<"joins game. List of players: "
2220 <<os.str()<<std::endl;
2226 if(peer_ser_ver == SER_FMT_VER_INVALID)
2228 infostream<<"Server::ProcessData(): Cancelling: Peer"
2229 " serialization format invalid or not initialized."
2230 " Skipping incoming command="<<command<<std::endl;
2234 Player *player = m_env->getPlayer(peer_id);
2236 infostream<<"Server::ProcessData(): Cancelling: "
2237 "No player for peer_id="<<peer_id
2242 PlayerSAO *playersao = player->getPlayerSAO();
2243 if(playersao == NULL){
2244 infostream<<"Server::ProcessData(): Cancelling: "
2245 "No player object for peer_id="<<peer_id
2250 if(command == TOSERVER_PLAYERPOS)
2252 if(datasize < 2+12+12+4+4)
2256 v3s32 ps = readV3S32(&data[start+2]);
2257 v3s32 ss = readV3S32(&data[start+2+12]);
2258 f32 pitch = (f32)readS32(&data[2+12+12]) / 100.0;
2259 f32 yaw = (f32)readS32(&data[2+12+12+4]) / 100.0;
2261 if(datasize >= 2+12+12+4+4+4)
2262 keyPressed = (u32)readU32(&data[2+12+12+4+4]);
2263 v3f position((f32)ps.X/100., (f32)ps.Y/100., (f32)ps.Z/100.);
2264 v3f speed((f32)ss.X/100., (f32)ss.Y/100., (f32)ss.Z/100.);
2265 pitch = wrapDegrees(pitch);
2266 yaw = wrapDegrees(yaw);
2268 player->setPosition(position);
2269 player->setSpeed(speed);
2270 player->setPitch(pitch);
2271 player->setYaw(yaw);
2272 player->keyPressed=keyPressed;
2273 player->control.up = (bool)(keyPressed&1);
2274 player->control.down = (bool)(keyPressed&2);
2275 player->control.left = (bool)(keyPressed&4);
2276 player->control.right = (bool)(keyPressed&8);
2277 player->control.jump = (bool)(keyPressed&16);
2278 player->control.aux1 = (bool)(keyPressed&32);
2279 player->control.sneak = (bool)(keyPressed&64);
2280 player->control.LMB = (bool)(keyPressed&128);
2281 player->control.RMB = (bool)(keyPressed&256);
2283 bool cheated = playersao->checkMovementCheat();
2286 m_script->on_cheat(playersao, "moved_too_fast");
2289 /*infostream<<"Server::ProcessData(): Moved player "<<peer_id<<" to "
2290 <<"("<<position.X<<","<<position.Y<<","<<position.Z<<")"
2291 <<" pitch="<<pitch<<" yaw="<<yaw<<std::endl;*/
2293 else if(command == TOSERVER_GOTBLOCKS)
2306 u16 count = data[2];
2307 for(u16 i=0; i<count; i++)
2309 if((s16)datasize < 2+1+(i+1)*6)
2310 throw con::InvalidIncomingDataException
2311 ("GOTBLOCKS length is too short");
2312 v3s16 p = readV3S16(&data[2+1+i*6]);
2313 /*infostream<<"Server: GOTBLOCKS ("
2314 <<p.X<<","<<p.Y<<","<<p.Z<<")"<<std::endl;*/
2315 RemoteClient *client = getClient(peer_id);
2316 client->GotBlock(p);
2319 else if(command == TOSERVER_DELETEDBLOCKS)
2332 u16 count = data[2];
2333 for(u16 i=0; i<count; i++)
2335 if((s16)datasize < 2+1+(i+1)*6)
2336 throw con::InvalidIncomingDataException
2337 ("DELETEDBLOCKS length is too short");
2338 v3s16 p = readV3S16(&data[2+1+i*6]);
2339 /*infostream<<"Server: DELETEDBLOCKS ("
2340 <<p.X<<","<<p.Y<<","<<p.Z<<")"<<std::endl;*/
2341 RemoteClient *client = getClient(peer_id);
2342 client->SetBlockNotSent(p);
2345 else if(command == TOSERVER_CLICK_OBJECT)
2347 infostream<<"Server: CLICK_OBJECT not supported anymore"<<std::endl;
2350 else if(command == TOSERVER_CLICK_ACTIVEOBJECT)
2352 infostream<<"Server: CLICK_ACTIVEOBJECT not supported anymore"<<std::endl;
2355 else if(command == TOSERVER_GROUND_ACTION)
2357 infostream<<"Server: GROUND_ACTION not supported anymore"<<std::endl;
2361 else if(command == TOSERVER_RELEASE)
2363 infostream<<"Server: RELEASE not supported anymore"<<std::endl;
2366 else if(command == TOSERVER_SIGNTEXT)
2368 infostream<<"Server: SIGNTEXT not supported anymore"
2372 else if(command == TOSERVER_SIGNNODETEXT)
2374 infostream<<"Server: SIGNNODETEXT not supported anymore"
2378 else if(command == TOSERVER_INVENTORY_ACTION)
2380 // Strip command and create a stream
2381 std::string datastring((char*)&data[2], datasize-2);
2382 verbosestream<<"TOSERVER_INVENTORY_ACTION: data="<<datastring<<std::endl;
2383 std::istringstream is(datastring, std::ios_base::binary);
2385 InventoryAction *a = InventoryAction::deSerialize(is);
2388 infostream<<"TOSERVER_INVENTORY_ACTION: "
2389 <<"InventoryAction::deSerialize() returned NULL"
2394 // If something goes wrong, this player is to blame
2395 RollbackScopeActor rollback_scope(m_rollback,
2396 std::string("player:")+player->getName());
2399 Note: Always set inventory not sent, to repair cases
2400 where the client made a bad prediction.
2404 Handle restrictions and special cases of the move action
2406 if(a->getType() == IACTION_MOVE)
2408 IMoveAction *ma = (IMoveAction*)a;
2410 ma->from_inv.applyCurrentPlayer(player->getName());
2411 ma->to_inv.applyCurrentPlayer(player->getName());
2413 setInventoryModified(ma->from_inv);
2414 setInventoryModified(ma->to_inv);
2416 bool from_inv_is_current_player =
2417 (ma->from_inv.type == InventoryLocation::PLAYER) &&
2418 (ma->from_inv.name == player->getName());
2420 bool to_inv_is_current_player =
2421 (ma->to_inv.type == InventoryLocation::PLAYER) &&
2422 (ma->to_inv.name == player->getName());
2425 Disable moving items out of craftpreview
2427 if(ma->from_list == "craftpreview")
2429 infostream<<"Ignoring IMoveAction from "
2430 <<(ma->from_inv.dump())<<":"<<ma->from_list
2431 <<" to "<<(ma->to_inv.dump())<<":"<<ma->to_list
2432 <<" because src is "<<ma->from_list<<std::endl;
2438 Disable moving items into craftresult and craftpreview
2440 if(ma->to_list == "craftpreview" || ma->to_list == "craftresult")
2442 infostream<<"Ignoring IMoveAction from "
2443 <<(ma->from_inv.dump())<<":"<<ma->from_list
2444 <<" to "<<(ma->to_inv.dump())<<":"<<ma->to_list
2445 <<" because dst is "<<ma->to_list<<std::endl;
2450 // Disallow moving items in elsewhere than player's inventory
2451 // if not allowed to interact
2452 if(!checkPriv(player->getName(), "interact") &&
2453 (!from_inv_is_current_player ||
2454 !to_inv_is_current_player))
2456 infostream<<"Cannot move outside of player's inventory: "
2457 <<"No interact privilege"<<std::endl;
2463 Handle restrictions and special cases of the drop action
2465 else if(a->getType() == IACTION_DROP)
2467 IDropAction *da = (IDropAction*)a;
2469 da->from_inv.applyCurrentPlayer(player->getName());
2471 setInventoryModified(da->from_inv);
2474 Disable dropping items out of craftpreview
2476 if(da->from_list == "craftpreview")
2478 infostream<<"Ignoring IDropAction from "
2479 <<(da->from_inv.dump())<<":"<<da->from_list
2480 <<" because src is "<<da->from_list<<std::endl;
2485 // Disallow dropping items if not allowed to interact
2486 if(!checkPriv(player->getName(), "interact"))
2493 Handle restrictions and special cases of the craft action
2495 else if(a->getType() == IACTION_CRAFT)
2497 ICraftAction *ca = (ICraftAction*)a;
2499 ca->craft_inv.applyCurrentPlayer(player->getName());
2501 setInventoryModified(ca->craft_inv);
2503 //bool craft_inv_is_current_player =
2504 // (ca->craft_inv.type == InventoryLocation::PLAYER) &&
2505 // (ca->craft_inv.name == player->getName());
2507 // Disallow crafting if not allowed to interact
2508 if(!checkPriv(player->getName(), "interact"))
2510 infostream<<"Cannot craft: "
2511 <<"No interact privilege"<<std::endl;
2518 a->apply(this, playersao, this);
2522 else if(command == TOSERVER_CHAT_MESSAGE)
2530 std::string datastring((char*)&data[2], datasize-2);
2531 std::istringstream is(datastring, std::ios_base::binary);
2534 is.read((char*)buf, 2);
2535 u16 len = readU16(buf);
2537 std::wstring message;
2538 for(u16 i=0; i<len; i++)
2540 is.read((char*)buf, 2);
2541 message += (wchar_t)readU16(buf);
2544 // If something goes wrong, this player is to blame
2545 RollbackScopeActor rollback_scope(m_rollback,
2546 std::string("player:")+player->getName());
2548 // Get player name of this client
2549 std::wstring name = narrow_to_wide(player->getName());
2552 bool ate = m_script->on_chat_message(player->getName(),
2553 wide_to_narrow(message));
2554 // If script ate the message, don't proceed
2558 // Line to send to players
2560 // Whether to send to the player that sent the line
2561 bool send_to_sender = false;
2562 // Whether to send to other players
2563 bool send_to_others = false;
2565 // Commands are implemented in Lua, so only catch invalid
2566 // commands that were not "eaten" and send an error back
2567 if(message[0] == L'/')
2569 message = message.substr(1);
2570 send_to_sender = true;
2571 if(message.length() == 0)
2572 line += L"-!- Empty command";
2574 line += L"-!- Invalid command: " + str_split(message, L' ')[0];
2578 if(checkPriv(player->getName(), "shout")){
2583 send_to_others = true;
2585 line += L"-!- You don't have permission to shout.";
2586 send_to_sender = true;
2593 actionstream<<"CHAT: "<<wide_to_narrow(line)<<std::endl;
2596 Send the message to clients
2598 for(std::map<u16, RemoteClient*>::iterator
2599 i = m_clients.begin();
2600 i != m_clients.end(); ++i)
2602 // Get client and check that it is valid
2603 RemoteClient *client = i->second;
2604 assert(client->peer_id == i->first);
2605 if(client->serialization_version == SER_FMT_VER_INVALID)
2609 bool sender_selected = (peer_id == client->peer_id);
2610 if(sender_selected == true && send_to_sender == false)
2612 if(sender_selected == false && send_to_others == false)
2615 SendChatMessage(client->peer_id, line);
2619 else if(command == TOSERVER_DAMAGE)
2621 std::string datastring((char*)&data[2], datasize-2);
2622 std::istringstream is(datastring, std::ios_base::binary);
2623 u8 damage = readU8(is);
2625 if(g_settings->getBool("enable_damage"))
2627 actionstream<<player->getName()<<" damaged by "
2628 <<(int)damage<<" hp at "<<PP(player->getPosition()/BS)
2631 playersao->setHP(playersao->getHP() - damage);
2633 if(playersao->getHP() == 0 && playersao->m_hp_not_sent)
2636 if(playersao->m_hp_not_sent)
2637 SendPlayerHP(peer_id);
2640 else if(command == TOSERVER_BREATH)
2642 std::string datastring((char*)&data[2], datasize-2);
2643 std::istringstream is(datastring, std::ios_base::binary);
2644 u16 breath = readU16(is);
2645 playersao->setBreath(breath);
2647 else if(command == TOSERVER_PASSWORD)
2650 [0] u16 TOSERVER_PASSWORD
2651 [2] u8[28] old password
2652 [30] u8[28] new password
2655 if(datasize != 2+PASSWORD_SIZE*2)
2657 /*char password[PASSWORD_SIZE];
2658 for(u32 i=0; i<PASSWORD_SIZE-1; i++)
2659 password[i] = data[2+i];
2660 password[PASSWORD_SIZE-1] = 0;*/
2662 for(u32 i=0; i<PASSWORD_SIZE-1; i++)
2670 for(u32 i=0; i<PASSWORD_SIZE-1; i++)
2672 char c = data[2+PASSWORD_SIZE+i];
2678 if(!base64_is_valid(newpwd)){
2679 infostream<<"Server: "<<player->getName()<<" supplied invalid password hash"<<std::endl;
2680 // Wrong old password supplied!!
2681 SendChatMessage(peer_id, L"Invalid new password hash supplied. Password NOT changed.");
2685 infostream<<"Server: Client requests a password change from "
2686 <<"'"<<oldpwd<<"' to '"<<newpwd<<"'"<<std::endl;
2688 std::string playername = player->getName();
2690 std::string checkpwd;
2691 m_script->getAuth(playername, &checkpwd, NULL);
2693 if(oldpwd != checkpwd)
2695 infostream<<"Server: invalid old password"<<std::endl;
2696 // Wrong old password supplied!!
2697 SendChatMessage(peer_id, L"Invalid old password supplied. Password NOT changed.");
2701 bool success = m_script->setPassword(playername, newpwd);
2703 actionstream<<player->getName()<<" changes password"<<std::endl;
2704 SendChatMessage(peer_id, L"Password change successful.");
2706 actionstream<<player->getName()<<" tries to change password but "
2707 <<"it fails"<<std::endl;
2708 SendChatMessage(peer_id, L"Password change failed or inavailable.");
2711 else if(command == TOSERVER_PLAYERITEM)
2716 u16 item = readU16(&data[2]);
2717 playersao->setWieldIndex(item);
2719 else if(command == TOSERVER_RESPAWN)
2721 if(player->hp != 0 || !g_settings->getBool("enable_damage"))
2724 RespawnPlayer(peer_id);
2726 actionstream<<player->getName()<<" respawns at "
2727 <<PP(player->getPosition()/BS)<<std::endl;
2729 // ActiveObject is added to environment in AsyncRunStep after
2730 // the previous addition has been succesfully removed
2732 else if(command == TOSERVER_REQUEST_MEDIA) {
2733 std::string datastring((char*)&data[2], datasize-2);
2734 std::istringstream is(datastring, std::ios_base::binary);
2736 std::list<MediaRequest> tosend;
2737 u16 numfiles = readU16(is);
2739 infostream<<"Sending "<<numfiles<<" files to "
2740 <<getPlayerName(peer_id)<<std::endl;
2741 verbosestream<<"TOSERVER_REQUEST_MEDIA: "<<std::endl;
2743 for(int i = 0; i < numfiles; i++) {
2744 std::string name = deSerializeString(is);
2745 tosend.push_back(MediaRequest(name));
2746 verbosestream<<"TOSERVER_REQUEST_MEDIA: requested file "
2750 sendRequestedMedia(peer_id, tosend);
2752 // Now the client should know about everything
2753 // (definitions and files)
2754 getClient(peer_id)->definitions_sent = true;
2756 else if(command == TOSERVER_RECEIVED_MEDIA) {
2757 getClient(peer_id)->definitions_sent = true;
2759 else if(command == TOSERVER_INTERACT)
2761 std::string datastring((char*)&data[2], datasize-2);
2762 std::istringstream is(datastring, std::ios_base::binary);
2768 [5] u32 length of the next item
2769 [9] serialized PointedThing
2771 0: start digging (from undersurface) or use
2772 1: stop digging (all parameters ignored)
2773 2: digging completed
2774 3: place block or item (to abovesurface)
2777 u8 action = readU8(is);
2778 u16 item_i = readU16(is);
2779 std::istringstream tmp_is(deSerializeLongString(is), std::ios::binary);
2780 PointedThing pointed;
2781 pointed.deSerialize(tmp_is);
2783 verbosestream<<"TOSERVER_INTERACT: action="<<(int)action<<", item="
2784 <<item_i<<", pointed="<<pointed.dump()<<std::endl;
2788 verbosestream<<"TOSERVER_INTERACT: "<<player->getName()
2789 <<" tried to interact, but is dead!"<<std::endl;
2793 v3f player_pos = playersao->getLastGoodPosition();
2795 // Update wielded item
2796 playersao->setWieldIndex(item_i);
2798 // Get pointed to node (undefined if not POINTEDTYPE_NODE)
2799 v3s16 p_under = pointed.node_undersurface;
2800 v3s16 p_above = pointed.node_abovesurface;
2802 // Get pointed to object (NULL if not POINTEDTYPE_OBJECT)
2803 ServerActiveObject *pointed_object = NULL;
2804 if(pointed.type == POINTEDTHING_OBJECT)
2806 pointed_object = m_env->getActiveObject(pointed.object_id);
2807 if(pointed_object == NULL)
2809 verbosestream<<"TOSERVER_INTERACT: "
2810 "pointed object is NULL"<<std::endl;
2816 v3f pointed_pos_under = player_pos;
2817 v3f pointed_pos_above = player_pos;
2818 if(pointed.type == POINTEDTHING_NODE)
2820 pointed_pos_under = intToFloat(p_under, BS);
2821 pointed_pos_above = intToFloat(p_above, BS);
2823 else if(pointed.type == POINTEDTHING_OBJECT)
2825 pointed_pos_under = pointed_object->getBasePosition();
2826 pointed_pos_above = pointed_pos_under;
2830 Check that target is reasonably close
2831 (only when digging or placing things)
2833 if(action == 0 || action == 2 || action == 3)
2835 float d = player_pos.getDistanceFrom(pointed_pos_under);
2836 float max_d = BS * 14; // Just some large enough value
2838 actionstream<<"Player "<<player->getName()
2839 <<" tried to access "<<pointed.dump()
2841 <<"d="<<d<<", max_d="<<max_d
2842 <<". ignoring."<<std::endl;
2843 // Re-send block to revert change on client-side
2844 RemoteClient *client = getClient(peer_id);
2845 v3s16 blockpos = getNodeBlockPos(floatToInt(pointed_pos_under, BS));
2846 client->SetBlockNotSent(blockpos);
2848 m_script->on_cheat(playersao, "interacted_too_far");
2855 Make sure the player is allowed to do it
2857 if(!checkPriv(player->getName(), "interact"))
2859 actionstream<<player->getName()<<" attempted to interact with "
2860 <<pointed.dump()<<" without 'interact' privilege"
2862 // Re-send block to revert change on client-side
2863 RemoteClient *client = getClient(peer_id);
2864 // Digging completed -> under
2866 v3s16 blockpos = getNodeBlockPos(floatToInt(pointed_pos_under, BS));
2867 client->SetBlockNotSent(blockpos);
2869 // Placement -> above
2871 v3s16 blockpos = getNodeBlockPos(floatToInt(pointed_pos_above, BS));
2872 client->SetBlockNotSent(blockpos);
2878 If something goes wrong, this player is to blame
2880 RollbackScopeActor rollback_scope(m_rollback,
2881 std::string("player:")+player->getName());
2884 0: start digging or punch object
2888 if(pointed.type == POINTEDTHING_NODE)
2891 NOTE: This can be used in the future to check if
2892 somebody is cheating, by checking the timing.
2894 MapNode n(CONTENT_IGNORE);
2897 n = m_env->getMap().getNode(p_under);
2899 catch(InvalidPositionException &e)
2901 infostream<<"Server: Not punching: Node not found."
2902 <<" Adding block to emerge queue."
2904 m_emerge->enqueueBlockEmerge(peer_id, getNodeBlockPos(p_above), false);
2906 if(n.getContent() != CONTENT_IGNORE)
2907 m_script->node_on_punch(p_under, n, playersao);
2909 playersao->noCheatDigStart(p_under);
2911 else if(pointed.type == POINTEDTHING_OBJECT)
2913 // Skip if object has been removed
2914 if(pointed_object->m_removed)
2917 actionstream<<player->getName()<<" punches object "
2918 <<pointed.object_id<<": "
2919 <<pointed_object->getDescription()<<std::endl;
2921 ItemStack punchitem = playersao->getWieldedItem();
2922 ToolCapabilities toolcap =
2923 punchitem.getToolCapabilities(m_itemdef);
2924 v3f dir = (pointed_object->getBasePosition() -
2925 (player->getPosition() + player->getEyeOffset())
2927 float time_from_last_punch =
2928 playersao->resetTimeFromLastPunch();
2929 pointed_object->punch(dir, &toolcap, playersao,
2930 time_from_last_punch);
2938 else if(action == 1)
2943 2: Digging completed
2945 else if(action == 2)
2947 // Only digging of nodes
2948 if(pointed.type == POINTEDTHING_NODE)
2950 MapNode n(CONTENT_IGNORE);
2953 n = m_env->getMap().getNode(p_under);
2955 catch(InvalidPositionException &e)
2957 infostream<<"Server: Not finishing digging: Node not found."
2958 <<" Adding block to emerge queue."
2960 m_emerge->enqueueBlockEmerge(peer_id, getNodeBlockPos(p_above), false);
2963 /* Cheat prevention */
2964 bool is_valid_dig = true;
2965 if(!isSingleplayer() && !g_settings->getBool("disable_anticheat"))
2967 v3s16 nocheat_p = playersao->getNoCheatDigPos();
2968 float nocheat_t = playersao->getNoCheatDigTime();
2969 playersao->noCheatDigEnd();
2970 // If player didn't start digging this, ignore dig
2971 if(nocheat_p != p_under){
2972 infostream<<"Server: NoCheat: "<<player->getName()
2973 <<" started digging "
2974 <<PP(nocheat_p)<<" and completed digging "
2975 <<PP(p_under)<<"; not digging."<<std::endl;
2976 is_valid_dig = false;
2978 m_script->on_cheat(playersao, "finished_unknown_dig");
2980 // Get player's wielded item
2981 ItemStack playeritem;
2982 InventoryList *mlist = playersao->getInventory()->getList("main");
2984 playeritem = mlist->getItem(playersao->getWieldIndex());
2985 ToolCapabilities playeritem_toolcap =
2986 playeritem.getToolCapabilities(m_itemdef);
2987 // Get diggability and expected digging time
2988 DigParams params = getDigParams(m_nodedef->get(n).groups,
2989 &playeritem_toolcap);
2990 // If can't dig, try hand
2991 if(!params.diggable){
2992 const ItemDefinition &hand = m_itemdef->get("");
2993 const ToolCapabilities *tp = hand.tool_capabilities;
2995 params = getDigParams(m_nodedef->get(n).groups, tp);
2997 // If can't dig, ignore dig
2998 if(!params.diggable){
2999 infostream<<"Server: NoCheat: "<<player->getName()
3000 <<" completed digging "<<PP(p_under)
3001 <<", which is not diggable with tool. not digging."
3003 is_valid_dig = false;
3005 m_script->on_cheat(playersao, "dug_unbreakable");
3007 // Check digging time
3008 // If already invalidated, we don't have to
3010 // Well not our problem then
3012 // Clean and long dig
3013 else if(params.time > 2.0 && nocheat_t * 1.2 > params.time){
3014 // All is good, but grab time from pool; don't care if
3015 // it's actually available
3016 playersao->getDigPool().grab(params.time);
3018 // Short or laggy dig
3019 // Try getting the time from pool
3020 else if(playersao->getDigPool().grab(params.time)){
3025 infostream<<"Server: NoCheat: "<<player->getName()
3026 <<" completed digging "<<PP(p_under)
3027 <<"too fast; not digging."<<std::endl;
3028 is_valid_dig = false;
3030 m_script->on_cheat(playersao, "dug_too_fast");
3034 /* Actually dig node */
3036 if(is_valid_dig && n.getContent() != CONTENT_IGNORE)
3037 m_script->node_on_dig(p_under, n, playersao);
3039 // Send unusual result (that is, node not being removed)
3040 if(m_env->getMap().getNodeNoEx(p_under).getContent() != CONTENT_AIR)
3042 // Re-send block to revert change on client-side
3043 RemoteClient *client = getClient(peer_id);
3044 v3s16 blockpos = getNodeBlockPos(floatToInt(pointed_pos_under, BS));
3045 client->SetBlockNotSent(blockpos);
3051 3: place block or right-click object
3053 else if(action == 3)
3055 ItemStack item = playersao->getWieldedItem();
3057 // Reset build time counter
3058 if(pointed.type == POINTEDTHING_NODE &&
3059 item.getDefinition(m_itemdef).type == ITEM_NODE)
3060 getClient(peer_id)->m_time_from_building = 0.0;
3062 if(pointed.type == POINTEDTHING_OBJECT)
3064 // Right click object
3066 // Skip if object has been removed
3067 if(pointed_object->m_removed)
3070 actionstream<<player->getName()<<" right-clicks object "
3071 <<pointed.object_id<<": "
3072 <<pointed_object->getDescription()<<std::endl;
3075 pointed_object->rightClick(playersao);
3077 else if(m_script->item_OnPlace(
3078 item, playersao, pointed))
3080 // Placement was handled in lua
3082 // Apply returned ItemStack
3083 playersao->setWieldedItem(item);
3086 // If item has node placement prediction, always send the
3087 // blocks to make sure the client knows what exactly happened
3088 if(item.getDefinition(m_itemdef).node_placement_prediction != ""){
3089 RemoteClient *client = getClient(peer_id);
3090 v3s16 blockpos = getNodeBlockPos(floatToInt(pointed_pos_above, BS));
3091 client->SetBlockNotSent(blockpos);
3092 v3s16 blockpos2 = getNodeBlockPos(floatToInt(pointed_pos_under, BS));
3093 if(blockpos2 != blockpos){
3094 client->SetBlockNotSent(blockpos2);
3102 else if(action == 4)
3104 ItemStack item = playersao->getWieldedItem();
3106 actionstream<<player->getName()<<" uses "<<item.name
3107 <<", pointing at "<<pointed.dump()<<std::endl;
3109 if(m_script->item_OnUse(
3110 item, playersao, pointed))
3112 // Apply returned ItemStack
3113 playersao->setWieldedItem(item);
3120 Catch invalid actions
3124 infostream<<"WARNING: Server: Invalid action "
3125 <<action<<std::endl;
3128 else if(command == TOSERVER_REMOVED_SOUNDS)
3130 std::string datastring((char*)&data[2], datasize-2);
3131 std::istringstream is(datastring, std::ios_base::binary);
3133 int num = readU16(is);
3134 for(int k=0; k<num; k++){
3135 s32 id = readS32(is);
3136 std::map<s32, ServerPlayingSound>::iterator i =
3137 m_playing_sounds.find(id);
3138 if(i == m_playing_sounds.end())
3140 ServerPlayingSound &psound = i->second;
3141 psound.clients.erase(peer_id);
3142 if(psound.clients.size() == 0)
3143 m_playing_sounds.erase(i++);
3146 else if(command == TOSERVER_NODEMETA_FIELDS)
3148 std::string datastring((char*)&data[2], datasize-2);
3149 std::istringstream is(datastring, std::ios_base::binary);
3151 v3s16 p = readV3S16(is);
3152 std::string formname = deSerializeString(is);
3153 int num = readU16(is);
3154 std::map<std::string, std::string> fields;
3155 for(int k=0; k<num; k++){
3156 std::string fieldname = deSerializeString(is);
3157 std::string fieldvalue = deSerializeLongString(is);
3158 fields[fieldname] = fieldvalue;
3161 // If something goes wrong, this player is to blame
3162 RollbackScopeActor rollback_scope(m_rollback,
3163 std::string("player:")+player->getName());
3165 // Check the target node for rollback data; leave others unnoticed
3166 RollbackNode rn_old(&m_env->getMap(), p, this);
3168 m_script->node_on_receive_fields(p, formname, fields,playersao);
3170 // Report rollback data
3171 RollbackNode rn_new(&m_env->getMap(), p, this);
3172 if(rollback() && rn_new != rn_old){
3173 RollbackAction action;
3174 action.setSetNode(p, rn_old, rn_new);
3175 rollback()->reportAction(action);
3178 else if(command == TOSERVER_INVENTORY_FIELDS)
3180 std::string datastring((char*)&data[2], datasize-2);
3181 std::istringstream is(datastring, std::ios_base::binary);
3183 std::string formname = deSerializeString(is);
3184 int num = readU16(is);
3185 std::map<std::string, std::string> fields;
3186 for(int k=0; k<num; k++){
3187 std::string fieldname = deSerializeString(is);
3188 std::string fieldvalue = deSerializeLongString(is);
3189 fields[fieldname] = fieldvalue;
3192 m_script->on_playerReceiveFields(playersao, formname, fields);
3196 infostream<<"Server::ProcessData(): Ignoring "
3197 "unknown command "<<command<<std::endl;
3201 catch(SendFailedException &e)
3203 errorstream<<"Server::ProcessData(): SendFailedException: "
3209 void Server::setTimeOfDay(u32 time)
3211 m_env->setTimeOfDay(time);
3212 m_time_of_day_send_timer = 0;
3215 void Server::onMapEditEvent(MapEditEvent *event)
3217 //infostream<<"Server::onMapEditEvent()"<<std::endl;
3218 if(m_ignore_map_edit_events)
3220 if(m_ignore_map_edit_events_area.contains(event->getArea()))
3222 MapEditEvent *e = event->clone();
3223 m_unsent_map_edit_queue.push_back(e);
3226 Inventory* Server::getInventory(const InventoryLocation &loc)
3229 case InventoryLocation::UNDEFINED:
3232 case InventoryLocation::CURRENT_PLAYER:
3235 case InventoryLocation::PLAYER:
3237 Player *player = m_env->getPlayer(loc.name.c_str());
3240 PlayerSAO *playersao = player->getPlayerSAO();
3243 return playersao->getInventory();
3246 case InventoryLocation::NODEMETA:
3248 NodeMetadata *meta = m_env->getMap().getNodeMetadata(loc.p);
3251 return meta->getInventory();
3254 case InventoryLocation::DETACHED:
3256 if(m_detached_inventories.count(loc.name) == 0)
3258 return m_detached_inventories[loc.name];
3266 void Server::setInventoryModified(const InventoryLocation &loc)
3269 case InventoryLocation::UNDEFINED:
3272 case InventoryLocation::PLAYER:
3274 Player *player = m_env->getPlayer(loc.name.c_str());
3277 PlayerSAO *playersao = player->getPlayerSAO();
3280 playersao->m_inventory_not_sent = true;
3281 playersao->m_wielded_item_not_sent = true;
3284 case InventoryLocation::NODEMETA:
3286 v3s16 blockpos = getNodeBlockPos(loc.p);
3288 MapBlock *block = m_env->getMap().getBlockNoCreateNoEx(blockpos);
3290 block->raiseModified(MOD_STATE_WRITE_NEEDED);
3292 setBlockNotSent(blockpos);
3295 case InventoryLocation::DETACHED:
3297 sendDetachedInventoryToAll(loc.name);
3305 void Server::peerAdded(con::Peer *peer)
3307 DSTACK(__FUNCTION_NAME);
3308 verbosestream<<"Server::peerAdded(): peer->id="
3309 <<peer->id<<std::endl;
3312 c.type = PEER_ADDED;
3313 c.peer_id = peer->id;
3315 m_peer_change_queue.push_back(c);
3318 void Server::deletingPeer(con::Peer *peer, bool timeout)
3320 DSTACK(__FUNCTION_NAME);
3321 verbosestream<<"Server::deletingPeer(): peer->id="
3322 <<peer->id<<", timeout="<<timeout<<std::endl;
3325 c.type = PEER_REMOVED;
3326 c.peer_id = peer->id;
3327 c.timeout = timeout;
3328 m_peer_change_queue.push_back(c);
3335 void Server::SendMovement(con::Connection &con, u16 peer_id)
3337 DSTACK(__FUNCTION_NAME);
3338 std::ostringstream os(std::ios_base::binary);
3340 writeU16(os, TOCLIENT_MOVEMENT);
3341 writeF1000(os, g_settings->getFloat("movement_acceleration_default"));
3342 writeF1000(os, g_settings->getFloat("movement_acceleration_air"));
3343 writeF1000(os, g_settings->getFloat("movement_acceleration_fast"));
3344 writeF1000(os, g_settings->getFloat("movement_speed_walk"));
3345 writeF1000(os, g_settings->getFloat("movement_speed_crouch"));
3346 writeF1000(os, g_settings->getFloat("movement_speed_fast"));
3347 writeF1000(os, g_settings->getFloat("movement_speed_climb"));
3348 writeF1000(os, g_settings->getFloat("movement_speed_jump"));
3349 writeF1000(os, g_settings->getFloat("movement_liquid_fluidity"));
3350 writeF1000(os, g_settings->getFloat("movement_liquid_fluidity_smooth"));
3351 writeF1000(os, g_settings->getFloat("movement_liquid_sink"));
3352 writeF1000(os, g_settings->getFloat("movement_gravity"));
3355 std::string s = os.str();
3356 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3358 con.Send(peer_id, 0, data, true);
3361 void Server::SendHP(con::Connection &con, u16 peer_id, u8 hp)
3363 DSTACK(__FUNCTION_NAME);
3364 std::ostringstream os(std::ios_base::binary);
3366 writeU16(os, TOCLIENT_HP);
3370 std::string s = os.str();
3371 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3373 con.Send(peer_id, 0, data, true);
3376 void Server::SendBreath(con::Connection &con, u16 peer_id, u16 breath)
3378 DSTACK(__FUNCTION_NAME);
3379 std::ostringstream os(std::ios_base::binary);
3381 writeU16(os, TOCLIENT_BREATH);
3382 writeU16(os, breath);
3385 std::string s = os.str();
3386 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3388 con.Send(peer_id, 0, data, true);
3391 void Server::SendAccessDenied(con::Connection &con, u16 peer_id,
3392 const std::wstring &reason)
3394 DSTACK(__FUNCTION_NAME);
3395 std::ostringstream os(std::ios_base::binary);
3397 writeU16(os, TOCLIENT_ACCESS_DENIED);
3398 os<<serializeWideString(reason);
3401 std::string s = os.str();
3402 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3404 con.Send(peer_id, 0, data, true);
3407 void Server::SendDeathscreen(con::Connection &con, u16 peer_id,
3408 bool set_camera_point_target, v3f camera_point_target)
3410 DSTACK(__FUNCTION_NAME);
3411 std::ostringstream os(std::ios_base::binary);
3413 writeU16(os, TOCLIENT_DEATHSCREEN);
3414 writeU8(os, set_camera_point_target);
3415 writeV3F1000(os, camera_point_target);
3418 std::string s = os.str();
3419 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3421 con.Send(peer_id, 0, data, true);
3424 void Server::SendItemDef(con::Connection &con, u16 peer_id,
3425 IItemDefManager *itemdef, u16 protocol_version)
3427 DSTACK(__FUNCTION_NAME);
3428 std::ostringstream os(std::ios_base::binary);
3432 u32 length of the next item
3433 zlib-compressed serialized ItemDefManager
3435 writeU16(os, TOCLIENT_ITEMDEF);
3436 std::ostringstream tmp_os(std::ios::binary);
3437 itemdef->serialize(tmp_os, protocol_version);
3438 std::ostringstream tmp_os2(std::ios::binary);
3439 compressZlib(tmp_os.str(), tmp_os2);
3440 os<<serializeLongString(tmp_os2.str());
3443 std::string s = os.str();
3444 verbosestream<<"Server: Sending item definitions to id("<<peer_id
3445 <<"): size="<<s.size()<<std::endl;
3446 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3448 con.Send(peer_id, 0, data, true);
3451 void Server::SendNodeDef(con::Connection &con, u16 peer_id,
3452 INodeDefManager *nodedef, u16 protocol_version)
3454 DSTACK(__FUNCTION_NAME);
3455 std::ostringstream os(std::ios_base::binary);
3459 u32 length of the next item
3460 zlib-compressed serialized NodeDefManager
3462 writeU16(os, TOCLIENT_NODEDEF);
3463 std::ostringstream tmp_os(std::ios::binary);
3464 nodedef->serialize(tmp_os, protocol_version);
3465 std::ostringstream tmp_os2(std::ios::binary);
3466 compressZlib(tmp_os.str(), tmp_os2);
3467 os<<serializeLongString(tmp_os2.str());
3470 std::string s = os.str();
3471 verbosestream<<"Server: Sending node definitions to id("<<peer_id
3472 <<"): size="<<s.size()<<std::endl;
3473 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3475 con.Send(peer_id, 0, data, true);
3479 Non-static send methods
3482 void Server::SendInventory(u16 peer_id)
3484 DSTACK(__FUNCTION_NAME);
3486 PlayerSAO *playersao = getPlayerSAO(peer_id);
3489 playersao->m_inventory_not_sent = false;
3495 std::ostringstream os;
3496 playersao->getInventory()->serialize(os);
3498 std::string s = os.str();
3500 SharedBuffer<u8> data(s.size()+2);
3501 writeU16(&data[0], TOCLIENT_INVENTORY);
3502 memcpy(&data[2], s.c_str(), s.size());
3505 m_con.Send(peer_id, 0, data, true);
3508 void Server::SendChatMessage(u16 peer_id, const std::wstring &message)
3510 DSTACK(__FUNCTION_NAME);
3512 std::ostringstream os(std::ios_base::binary);
3516 writeU16(buf, TOCLIENT_CHAT_MESSAGE);
3517 os.write((char*)buf, 2);
3520 writeU16(buf, message.size());
3521 os.write((char*)buf, 2);
3524 for(u32 i=0; i<message.size(); i++)
3528 os.write((char*)buf, 2);
3532 std::string s = os.str();
3533 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3535 m_con.Send(peer_id, 0, data, true);
3538 void Server::SendShowFormspecMessage(u16 peer_id, const std::string formspec,
3539 const std::string formname)
3541 DSTACK(__FUNCTION_NAME);
3543 std::ostringstream os(std::ios_base::binary);
3547 writeU16(buf, TOCLIENT_SHOW_FORMSPEC);
3548 os.write((char*)buf, 2);
3549 os<<serializeLongString(formspec);
3550 os<<serializeString(formname);
3553 std::string s = os.str();
3554 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3556 m_con.Send(peer_id, 0, data, true);
3559 // Spawns a particle on peer with peer_id
3560 void Server::SendSpawnParticle(u16 peer_id, v3f pos, v3f velocity, v3f acceleration,
3561 float expirationtime, float size, bool collisiondetection,
3562 std::string texture)
3564 DSTACK(__FUNCTION_NAME);
3566 std::ostringstream os(std::ios_base::binary);
3567 writeU16(os, TOCLIENT_SPAWN_PARTICLE);
3568 writeV3F1000(os, pos);
3569 writeV3F1000(os, velocity);
3570 writeV3F1000(os, acceleration);
3571 writeF1000(os, expirationtime);
3572 writeF1000(os, size);
3573 writeU8(os, collisiondetection);
3574 os<<serializeLongString(texture);
3577 std::string s = os.str();
3578 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3580 m_con.Send(peer_id, 0, data, true);
3583 // Spawns a particle on all peers
3584 void Server::SendSpawnParticleAll(v3f pos, v3f velocity, v3f acceleration,
3585 float expirationtime, float size, bool collisiondetection,
3586 std::string texture)
3588 for(std::map<u16, RemoteClient*>::iterator
3589 i = m_clients.begin();
3590 i != m_clients.end(); i++)
3592 // Get client and check that it is valid
3593 RemoteClient *client = i->second;
3594 assert(client->peer_id == i->first);
3595 if(client->serialization_version == SER_FMT_VER_INVALID)
3598 SendSpawnParticle(client->peer_id, pos, velocity, acceleration,
3599 expirationtime, size, collisiondetection, texture);
3603 // Adds a ParticleSpawner on peer with peer_id
3604 void Server::SendAddParticleSpawner(u16 peer_id, u16 amount, float spawntime, v3f minpos, v3f maxpos,
3605 v3f minvel, v3f maxvel, v3f minacc, v3f maxacc, float minexptime, float maxexptime,
3606 float minsize, float maxsize, bool collisiondetection, std::string texture, u32 id)
3608 DSTACK(__FUNCTION_NAME);
3610 std::ostringstream os(std::ios_base::binary);
3611 writeU16(os, TOCLIENT_ADD_PARTICLESPAWNER);
3613 writeU16(os, amount);
3614 writeF1000(os, spawntime);
3615 writeV3F1000(os, minpos);
3616 writeV3F1000(os, maxpos);
3617 writeV3F1000(os, minvel);
3618 writeV3F1000(os, maxvel);
3619 writeV3F1000(os, minacc);
3620 writeV3F1000(os, maxacc);
3621 writeF1000(os, minexptime);
3622 writeF1000(os, maxexptime);
3623 writeF1000(os, minsize);
3624 writeF1000(os, maxsize);
3625 writeU8(os, collisiondetection);
3626 os<<serializeLongString(texture);
3630 std::string s = os.str();
3631 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3633 m_con.Send(peer_id, 0, data, true);
3636 // Adds a ParticleSpawner on all peers
3637 void Server::SendAddParticleSpawnerAll(u16 amount, float spawntime, v3f minpos, v3f maxpos,
3638 v3f minvel, v3f maxvel, v3f minacc, v3f maxacc, float minexptime, float maxexptime,
3639 float minsize, float maxsize, bool collisiondetection, std::string texture, u32 id)
3641 for(std::map<u16, RemoteClient*>::iterator
3642 i = m_clients.begin();
3643 i != m_clients.end(); i++)
3645 // Get client and check that it is valid
3646 RemoteClient *client = i->second;
3647 assert(client->peer_id == i->first);
3648 if(client->serialization_version == SER_FMT_VER_INVALID)
3651 SendAddParticleSpawner(client->peer_id, amount, spawntime,
3652 minpos, maxpos, minvel, maxvel, minacc, maxacc,
3653 minexptime, maxexptime, minsize, maxsize, collisiondetection, texture, id);
3657 void Server::SendDeleteParticleSpawner(u16 peer_id, u32 id)
3659 DSTACK(__FUNCTION_NAME);
3661 std::ostringstream os(std::ios_base::binary);
3662 writeU16(os, TOCLIENT_DELETE_PARTICLESPAWNER);
3667 std::string s = os.str();
3668 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3670 m_con.Send(peer_id, 0, data, true);
3673 void Server::SendDeleteParticleSpawnerAll(u32 id)
3675 for(std::map<u16, RemoteClient*>::iterator
3676 i = m_clients.begin();
3677 i != m_clients.end(); i++)
3679 // Get client and check that it is valid
3680 RemoteClient *client = i->second;
3681 assert(client->peer_id == i->first);
3682 if(client->serialization_version == SER_FMT_VER_INVALID)
3685 SendDeleteParticleSpawner(client->peer_id, id);
3689 void Server::SendHUDAdd(u16 peer_id, u32 id, HudElement *form)
3691 std::ostringstream os(std::ios_base::binary);
3694 writeU16(os, TOCLIENT_HUDADD);
3696 writeU8(os, (u8)form->type);
3697 writeV2F1000(os, form->pos);
3698 os << serializeString(form->name);
3699 writeV2F1000(os, form->scale);
3700 os << serializeString(form->text);
3701 writeU32(os, form->number);
3702 writeU32(os, form->item);
3703 writeU32(os, form->dir);
3704 writeV2F1000(os, form->align);
3705 writeV2F1000(os, form->offset);
3708 std::string s = os.str();
3709 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3711 m_con.Send(peer_id, 0, data, true);
3714 void Server::SendHUDRemove(u16 peer_id, u32 id)
3716 std::ostringstream os(std::ios_base::binary);
3719 writeU16(os, TOCLIENT_HUDRM);
3723 std::string s = os.str();
3724 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3726 m_con.Send(peer_id, 0, data, true);
3729 void Server::SendHUDChange(u16 peer_id, u32 id, HudElementStat stat, void *value)
3731 std::ostringstream os(std::ios_base::binary);
3734 writeU16(os, TOCLIENT_HUDCHANGE);
3736 writeU8(os, (u8)stat);
3739 case HUD_STAT_SCALE:
3740 case HUD_STAT_ALIGN:
3741 case HUD_STAT_OFFSET:
3742 writeV2F1000(os, *(v2f *)value);
3746 os << serializeString(*(std::string *)value);
3748 case HUD_STAT_NUMBER:
3752 writeU32(os, *(u32 *)value);
3757 std::string s = os.str();
3758 SharedBuffer<u8> data((u8 *)s.c_str(), s.size());
3760 m_con.Send(peer_id, 0, data, true);
3763 void Server::SendHUDSetFlags(u16 peer_id, u32 flags, u32 mask)
3765 std::ostringstream os(std::ios_base::binary);
3768 writeU16(os, TOCLIENT_HUD_SET_FLAGS);
3769 writeU32(os, flags);
3773 std::string s = os.str();
3774 SharedBuffer<u8> data((u8 *)s.c_str(), s.size());
3776 m_con.Send(peer_id, 0, data, true);
3779 void Server::SendHUDSetParam(u16 peer_id, u16 param, const std::string &value)
3781 std::ostringstream os(std::ios_base::binary);
3784 writeU16(os, TOCLIENT_HUD_SET_PARAM);
3785 writeU16(os, param);
3786 os<<serializeString(value);
3789 std::string s = os.str();
3790 SharedBuffer<u8> data((u8 *)s.c_str(), s.size());
3792 m_con.Send(peer_id, 0, data, true);
3795 void Server::BroadcastChatMessage(const std::wstring &message)
3797 for(std::map<u16, RemoteClient*>::iterator
3798 i = m_clients.begin();
3799 i != m_clients.end(); ++i)
3801 // Get client and check that it is valid
3802 RemoteClient *client = i->second;
3803 assert(client->peer_id == i->first);
3804 if(client->serialization_version == SER_FMT_VER_INVALID)
3807 SendChatMessage(client->peer_id, message);
3811 void Server::SendTimeOfDay(u16 peer_id, u16 time, f32 time_speed)
3813 DSTACK(__FUNCTION_NAME);
3816 SharedBuffer<u8> data(2+2+4);
3817 writeU16(&data[0], TOCLIENT_TIME_OF_DAY);
3818 writeU16(&data[2], time);
3819 writeF1000(&data[4], time_speed);
3822 m_con.Send(peer_id, 0, data, true);
3825 void Server::SendPlayerHP(u16 peer_id)
3827 DSTACK(__FUNCTION_NAME);
3828 PlayerSAO *playersao = getPlayerSAO(peer_id);
3830 playersao->m_hp_not_sent = false;
3831 SendHP(m_con, peer_id, playersao->getHP());
3833 // Send to other clients
3834 std::string str = gob_cmd_punched(playersao->readDamage(), playersao->getHP());
3835 ActiveObjectMessage aom(playersao->getId(), true, str);
3836 playersao->m_messages_out.push_back(aom);
3839 void Server::SendPlayerBreath(u16 peer_id)
3841 DSTACK(__FUNCTION_NAME);
3842 PlayerSAO *playersao = getPlayerSAO(peer_id);
3844 playersao->m_breath_not_sent = false;
3845 SendBreath(m_con, peer_id, playersao->getBreath());
3848 void Server::SendMovePlayer(u16 peer_id)
3850 DSTACK(__FUNCTION_NAME);
3851 Player *player = m_env->getPlayer(peer_id);
3854 std::ostringstream os(std::ios_base::binary);
3855 writeU16(os, TOCLIENT_MOVE_PLAYER);
3856 writeV3F1000(os, player->getPosition());
3857 writeF1000(os, player->getPitch());
3858 writeF1000(os, player->getYaw());
3861 v3f pos = player->getPosition();
3862 f32 pitch = player->getPitch();
3863 f32 yaw = player->getYaw();
3864 verbosestream<<"Server: Sending TOCLIENT_MOVE_PLAYER"
3865 <<" pos=("<<pos.X<<","<<pos.Y<<","<<pos.Z<<")"
3872 std::string s = os.str();
3873 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3875 m_con.Send(peer_id, 0, data, true);
3878 void Server::SendPlayerPrivileges(u16 peer_id)
3880 Player *player = m_env->getPlayer(peer_id);
3882 if(player->peer_id == PEER_ID_INEXISTENT)
3885 std::set<std::string> privs;
3886 m_script->getAuth(player->getName(), NULL, &privs);
3888 std::ostringstream os(std::ios_base::binary);
3889 writeU16(os, TOCLIENT_PRIVILEGES);
3890 writeU16(os, privs.size());
3891 for(std::set<std::string>::const_iterator i = privs.begin();
3892 i != privs.end(); i++){
3893 os<<serializeString(*i);
3897 std::string s = os.str();
3898 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3900 m_con.Send(peer_id, 0, data, true);
3903 void Server::SendPlayerInventoryFormspec(u16 peer_id)
3905 Player *player = m_env->getPlayer(peer_id);
3907 if(player->peer_id == PEER_ID_INEXISTENT)
3910 std::ostringstream os(std::ios_base::binary);
3911 writeU16(os, TOCLIENT_INVENTORY_FORMSPEC);
3912 os<<serializeLongString(player->inventory_formspec);
3915 std::string s = os.str();
3916 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3918 m_con.Send(peer_id, 0, data, true);
3921 s32 Server::playSound(const SimpleSoundSpec &spec,
3922 const ServerSoundParams ¶ms)
3924 // Find out initial position of sound
3925 bool pos_exists = false;
3926 v3f pos = params.getPos(m_env, &pos_exists);
3927 // If position is not found while it should be, cancel sound
3928 if(pos_exists != (params.type != ServerSoundParams::SSP_LOCAL))
3930 // Filter destination clients
3931 std::set<RemoteClient*> dst_clients;
3932 if(params.to_player != "")
3934 Player *player = m_env->getPlayer(params.to_player.c_str());
3936 infostream<<"Server::playSound: Player \""<<params.to_player
3937 <<"\" not found"<<std::endl;
3940 if(player->peer_id == PEER_ID_INEXISTENT){
3941 infostream<<"Server::playSound: Player \""<<params.to_player
3942 <<"\" not connected"<<std::endl;
3945 RemoteClient *client = getClient(player->peer_id);
3946 dst_clients.insert(client);
3950 for(std::map<u16, RemoteClient*>::iterator
3951 i = m_clients.begin(); i != m_clients.end(); ++i)
3953 RemoteClient *client = i->second;
3954 Player *player = m_env->getPlayer(client->peer_id);
3958 if(player->getPosition().getDistanceFrom(pos) >
3959 params.max_hear_distance)
3962 dst_clients.insert(client);
3965 if(dst_clients.size() == 0)
3968 s32 id = m_next_sound_id++;
3969 // The sound will exist as a reference in m_playing_sounds
3970 m_playing_sounds[id] = ServerPlayingSound();
3971 ServerPlayingSound &psound = m_playing_sounds[id];
3972 psound.params = params;
3973 for(std::set<RemoteClient*>::iterator i = dst_clients.begin();
3974 i != dst_clients.end(); i++)
3975 psound.clients.insert((*i)->peer_id);
3977 std::ostringstream os(std::ios_base::binary);
3978 writeU16(os, TOCLIENT_PLAY_SOUND);
3980 os<<serializeString(spec.name);
3981 writeF1000(os, spec.gain * params.gain);
3982 writeU8(os, params.type);
3983 writeV3F1000(os, pos);
3984 writeU16(os, params.object);
3985 writeU8(os, params.loop);
3987 std::string s = os.str();
3988 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3990 for(std::set<RemoteClient*>::iterator i = dst_clients.begin();
3991 i != dst_clients.end(); i++){
3993 m_con.Send((*i)->peer_id, 0, data, true);
3997 void Server::stopSound(s32 handle)
3999 // Get sound reference
4000 std::map<s32, ServerPlayingSound>::iterator i =
4001 m_playing_sounds.find(handle);
4002 if(i == m_playing_sounds.end())
4004 ServerPlayingSound &psound = i->second;
4006 std::ostringstream os(std::ios_base::binary);
4007 writeU16(os, TOCLIENT_STOP_SOUND);
4008 writeS32(os, handle);
4010 std::string s = os.str();
4011 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
4013 for(std::set<u16>::iterator i = psound.clients.begin();
4014 i != psound.clients.end(); i++){
4016 m_con.Send(*i, 0, data, true);
4018 // Remove sound reference
4019 m_playing_sounds.erase(i);
4022 void Server::sendRemoveNode(v3s16 p, u16 ignore_id,
4023 std::list<u16> *far_players, float far_d_nodes)
4025 float maxd = far_d_nodes*BS;
4026 v3f p_f = intToFloat(p, BS);
4030 SharedBuffer<u8> reply(replysize);
4031 writeU16(&reply[0], TOCLIENT_REMOVENODE);
4032 writeS16(&reply[2], p.X);
4033 writeS16(&reply[4], p.Y);
4034 writeS16(&reply[6], p.Z);
4036 for(std::map<u16, RemoteClient*>::iterator
4037 i = m_clients.begin();
4038 i != m_clients.end(); ++i)
4040 // Get client and check that it is valid
4041 RemoteClient *client = i->second;
4042 assert(client->peer_id == i->first);
4043 if(client->serialization_version == SER_FMT_VER_INVALID)
4046 // Don't send if it's the same one
4047 if(client->peer_id == ignore_id)
4053 Player *player = m_env->getPlayer(client->peer_id);
4056 // If player is far away, only set modified blocks not sent
4057 v3f player_pos = player->getPosition();
4058 if(player_pos.getDistanceFrom(p_f) > maxd)
4060 far_players->push_back(client->peer_id);
4067 m_con.Send(client->peer_id, 0, reply, true);
4071 void Server::sendAddNode(v3s16 p, MapNode n, u16 ignore_id,
4072 std::list<u16> *far_players, float far_d_nodes)
4074 float maxd = far_d_nodes*BS;
4075 v3f p_f = intToFloat(p, BS);
4077 for(std::map<u16, RemoteClient*>::iterator
4078 i = m_clients.begin();
4079 i != m_clients.end(); ++i)
4081 // Get client and check that it is valid
4082 RemoteClient *client = i->second;
4083 assert(client->peer_id == i->first);
4084 if(client->serialization_version == SER_FMT_VER_INVALID)
4087 // Don't send if it's the same one
4088 if(client->peer_id == ignore_id)
4094 Player *player = m_env->getPlayer(client->peer_id);
4097 // If player is far away, only set modified blocks not sent
4098 v3f player_pos = player->getPosition();
4099 if(player_pos.getDistanceFrom(p_f) > maxd)
4101 far_players->push_back(client->peer_id);
4108 u32 replysize = 8 + MapNode::serializedLength(client->serialization_version);
4109 SharedBuffer<u8> reply(replysize);
4110 writeU16(&reply[0], TOCLIENT_ADDNODE);
4111 writeS16(&reply[2], p.X);
4112 writeS16(&reply[4], p.Y);
4113 writeS16(&reply[6], p.Z);
4114 n.serialize(&reply[8], client->serialization_version);
4117 m_con.Send(client->peer_id, 0, reply, true);
4121 void Server::setBlockNotSent(v3s16 p)
4123 for(std::map<u16, RemoteClient*>::iterator
4124 i = m_clients.begin();
4125 i != m_clients.end(); ++i)
4127 RemoteClient *client = i->second;
4128 client->SetBlockNotSent(p);
4132 void Server::SendBlockNoLock(u16 peer_id, MapBlock *block, u8 ver, u16 net_proto_version)
4134 DSTACK(__FUNCTION_NAME);
4136 v3s16 p = block->getPos();
4140 bool completely_air = true;
4141 for(s16 z0=0; z0<MAP_BLOCKSIZE; z0++)
4142 for(s16 x0=0; x0<MAP_BLOCKSIZE; x0++)
4143 for(s16 y0=0; y0<MAP_BLOCKSIZE; y0++)
4145 if(block->getNodeNoEx(v3s16(x0,y0,z0)).d != CONTENT_AIR)
4147 completely_air = false;
4148 x0 = y0 = z0 = MAP_BLOCKSIZE; // Break out
4153 infostream<<"Server: Sending block ("<<p.X<<","<<p.Y<<","<<p.Z<<"): ";
4155 infostream<<"[completely air] ";
4156 infostream<<std::endl;
4160 Create a packet with the block in the right format
4163 std::ostringstream os(std::ios_base::binary);
4164 block->serialize(os, ver, false);
4165 block->serializeNetworkSpecific(os, net_proto_version);
4166 std::string s = os.str();
4167 SharedBuffer<u8> blockdata((u8*)s.c_str(), s.size());
4169 u32 replysize = 8 + blockdata.getSize();
4170 SharedBuffer<u8> reply(replysize);
4171 writeU16(&reply[0], TOCLIENT_BLOCKDATA);
4172 writeS16(&reply[2], p.X);
4173 writeS16(&reply[4], p.Y);
4174 writeS16(&reply[6], p.Z);
4175 memcpy(&reply[8], *blockdata, blockdata.getSize());
4177 /*infostream<<"Server: Sending block ("<<p.X<<","<<p.Y<<","<<p.Z<<")"
4178 <<": \tpacket size: "<<replysize<<std::endl;*/
4183 m_con.Send(peer_id, 1, reply, true);
4186 void Server::SendBlocks(float dtime)
4188 DSTACK(__FUNCTION_NAME);
4190 JMutexAutoLock envlock(m_env_mutex);
4191 JMutexAutoLock conlock(m_con_mutex);
4193 ScopeProfiler sp(g_profiler, "Server: sel and send blocks to clients");
4195 std::vector<PrioritySortedBlockTransfer> queue;
4197 s32 total_sending = 0;
4200 ScopeProfiler sp(g_profiler, "Server: selecting blocks for sending");
4202 for(std::map<u16, RemoteClient*>::iterator
4203 i = m_clients.begin();
4204 i != m_clients.end(); ++i)
4206 RemoteClient *client = i->second;
4207 assert(client->peer_id == i->first);
4209 // If definitions and textures have not been sent, don't
4210 // send MapBlocks either
4211 if(!client->definitions_sent)
4214 total_sending += client->SendingCount();
4216 if(client->serialization_version == SER_FMT_VER_INVALID)
4219 client->GetNextBlocks(this, dtime, queue);
4224 // Lowest priority number comes first.
4225 // Lowest is most important.
4226 std::sort(queue.begin(), queue.end());
4228 for(u32 i=0; i<queue.size(); i++)
4230 //TODO: Calculate limit dynamically
4231 if(total_sending >= g_settings->getS32
4232 ("max_simultaneous_block_sends_server_total"))
4235 PrioritySortedBlockTransfer q = queue[i];
4237 MapBlock *block = NULL;
4240 block = m_env->getMap().getBlockNoCreate(q.pos);
4242 catch(InvalidPositionException &e)
4247 RemoteClient *client = getClientNoEx(q.peer_id);
4253 SendBlockNoLock(q.peer_id, block, client->serialization_version, client->net_proto_version);
4255 client->SentBlock(q.pos);
4261 void Server::fillMediaCache()
4263 DSTACK(__FUNCTION_NAME);
4265 infostream<<"Server: Calculating media file checksums"<<std::endl;
4267 // Collect all media file paths
4268 std::list<std::string> paths;
4269 for(std::vector<ModSpec>::iterator i = m_mods.begin();
4270 i != m_mods.end(); i++){
4271 const ModSpec &mod = *i;
4272 paths.push_back(mod.path + DIR_DELIM + "textures");
4273 paths.push_back(mod.path + DIR_DELIM + "sounds");
4274 paths.push_back(mod.path + DIR_DELIM + "media");
4275 paths.push_back(mod.path + DIR_DELIM + "models");
4277 paths.push_back(porting::path_user + DIR_DELIM + "textures" + DIR_DELIM + "server");
4279 // Collect media file information from paths into cache
4280 for(std::list<std::string>::iterator i = paths.begin();
4281 i != paths.end(); i++)
4283 std::string mediapath = *i;
4284 std::vector<fs::DirListNode> dirlist = fs::GetDirListing(mediapath);
4285 for(u32 j=0; j<dirlist.size(); j++){
4286 if(dirlist[j].dir) // Ignode dirs
4288 std::string filename = dirlist[j].name;
4289 // If name contains illegal characters, ignore the file
4290 if(!string_allowed(filename, TEXTURENAME_ALLOWED_CHARS)){
4291 infostream<<"Server: ignoring illegal file name: \""
4292 <<filename<<"\""<<std::endl;
4295 // If name is not in a supported format, ignore it
4296 const char *supported_ext[] = {
4297 ".png", ".jpg", ".bmp", ".tga",
4298 ".pcx", ".ppm", ".psd", ".wal", ".rgb",
4300 ".x", ".b3d", ".md2", ".obj",
4303 if(removeStringEnd(filename, supported_ext) == ""){
4304 infostream<<"Server: ignoring unsupported file extension: \""
4305 <<filename<<"\""<<std::endl;
4308 // Ok, attempt to load the file and add to cache
4309 std::string filepath = mediapath + DIR_DELIM + filename;
4311 std::ifstream fis(filepath.c_str(), std::ios_base::binary);
4312 if(fis.good() == false){
4313 errorstream<<"Server::fillMediaCache(): Could not open \""
4314 <<filename<<"\" for reading"<<std::endl;
4317 std::ostringstream tmp_os(std::ios_base::binary);
4321 fis.read(buf, 1024);
4322 std::streamsize len = fis.gcount();
4323 tmp_os.write(buf, len);
4332 errorstream<<"Server::fillMediaCache(): Failed to read \""
4333 <<filename<<"\""<<std::endl;
4336 if(tmp_os.str().length() == 0){
4337 errorstream<<"Server::fillMediaCache(): Empty file \""
4338 <<filepath<<"\""<<std::endl;
4343 sha1.addBytes(tmp_os.str().c_str(), tmp_os.str().length());
4345 unsigned char *digest = sha1.getDigest();
4346 std::string sha1_base64 = base64_encode(digest, 20);
4347 std::string sha1_hex = hex_encode((char*)digest, 20);
4351 this->m_media[filename] = MediaInfo(filepath, sha1_base64);
4352 verbosestream<<"Server: "<<sha1_hex<<" is "<<filename<<std::endl;
4357 struct SendableMediaAnnouncement
4360 std::string sha1_digest;
4362 SendableMediaAnnouncement(const std::string name_="",
4363 const std::string sha1_digest_=""):
4365 sha1_digest(sha1_digest_)
4369 void Server::sendMediaAnnouncement(u16 peer_id)
4371 DSTACK(__FUNCTION_NAME);
4373 verbosestream<<"Server: Announcing files to id("<<peer_id<<")"
4376 std::list<SendableMediaAnnouncement> file_announcements;
4378 for(std::map<std::string, MediaInfo>::iterator i = m_media.begin();
4379 i != m_media.end(); i++){
4381 file_announcements.push_back(
4382 SendableMediaAnnouncement(i->first, i->second.sha1_digest));
4386 std::ostringstream os(std::ios_base::binary);
4394 u16 length of sha1_digest
4399 writeU16(os, TOCLIENT_ANNOUNCE_MEDIA);
4400 writeU16(os, file_announcements.size());
4402 for(std::list<SendableMediaAnnouncement>::iterator
4403 j = file_announcements.begin();
4404 j != file_announcements.end(); ++j){
4405 os<<serializeString(j->name);
4406 os<<serializeString(j->sha1_digest);
4408 os<<serializeString(g_settings->get("remote_media"));
4411 std::string s = os.str();
4412 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
4415 m_con.Send(peer_id, 0, data, true);
4418 struct SendableMedia
4424 SendableMedia(const std::string &name_="", const std::string path_="",
4425 const std::string &data_=""):
4432 void Server::sendRequestedMedia(u16 peer_id,
4433 const std::list<MediaRequest> &tosend)
4435 DSTACK(__FUNCTION_NAME);
4437 verbosestream<<"Server::sendRequestedMedia(): "
4438 <<"Sending files to client"<<std::endl;
4442 // Put 5kB in one bunch (this is not accurate)
4443 u32 bytes_per_bunch = 5000;
4445 std::vector< std::list<SendableMedia> > file_bunches;
4446 file_bunches.push_back(std::list<SendableMedia>());
4448 u32 file_size_bunch_total = 0;
4450 for(std::list<MediaRequest>::const_iterator i = tosend.begin();
4451 i != tosend.end(); ++i)
4453 if(m_media.find(i->name) == m_media.end()){
4454 errorstream<<"Server::sendRequestedMedia(): Client asked for "
4455 <<"unknown file \""<<(i->name)<<"\""<<std::endl;
4459 //TODO get path + name
4460 std::string tpath = m_media[(*i).name].path;
4463 std::ifstream fis(tpath.c_str(), std::ios_base::binary);
4464 if(fis.good() == false){
4465 errorstream<<"Server::sendRequestedMedia(): Could not open \""
4466 <<tpath<<"\" for reading"<<std::endl;
4469 std::ostringstream tmp_os(std::ios_base::binary);
4473 fis.read(buf, 1024);
4474 std::streamsize len = fis.gcount();
4475 tmp_os.write(buf, len);
4476 file_size_bunch_total += len;
4485 errorstream<<"Server::sendRequestedMedia(): Failed to read \""
4486 <<(*i).name<<"\""<<std::endl;
4489 /*infostream<<"Server::sendRequestedMedia(): Loaded \""
4490 <<tname<<"\""<<std::endl;*/
4492 file_bunches[file_bunches.size()-1].push_back(
4493 SendableMedia((*i).name, tpath, tmp_os.str()));
4495 // Start next bunch if got enough data
4496 if(file_size_bunch_total >= bytes_per_bunch){
4497 file_bunches.push_back(std::list<SendableMedia>());
4498 file_size_bunch_total = 0;
4503 /* Create and send packets */
4505 u32 num_bunches = file_bunches.size();
4506 for(u32 i=0; i<num_bunches; i++)
4508 std::ostringstream os(std::ios_base::binary);
4512 u16 total number of texture bunches
4513 u16 index of this bunch
4514 u32 number of files in this bunch
4523 writeU16(os, TOCLIENT_MEDIA);
4524 writeU16(os, num_bunches);
4526 writeU32(os, file_bunches[i].size());
4528 for(std::list<SendableMedia>::iterator
4529 j = file_bunches[i].begin();
4530 j != file_bunches[i].end(); ++j){
4531 os<<serializeString(j->name);
4532 os<<serializeLongString(j->data);
4536 std::string s = os.str();
4537 verbosestream<<"Server::sendRequestedMedia(): bunch "
4538 <<i<<"/"<<num_bunches
4539 <<" files="<<file_bunches[i].size()
4540 <<" size=" <<s.size()<<std::endl;
4541 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
4543 m_con.Send(peer_id, 0, data, true);
4547 void Server::sendDetachedInventory(const std::string &name, u16 peer_id)
4549 if(m_detached_inventories.count(name) == 0){
4550 errorstream<<__FUNCTION_NAME<<": \""<<name<<"\" not found"<<std::endl;
4553 Inventory *inv = m_detached_inventories[name];
4555 std::ostringstream os(std::ios_base::binary);
4556 writeU16(os, TOCLIENT_DETACHED_INVENTORY);
4557 os<<serializeString(name);
4561 std::string s = os.str();
4562 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
4564 m_con.Send(peer_id, 0, data, true);
4567 void Server::sendDetachedInventoryToAll(const std::string &name)
4569 DSTACK(__FUNCTION_NAME);
4571 for(std::map<u16, RemoteClient*>::iterator
4572 i = m_clients.begin();
4573 i != m_clients.end(); ++i){
4574 RemoteClient *client = i->second;
4575 sendDetachedInventory(name, client->peer_id);
4579 void Server::sendDetachedInventories(u16 peer_id)
4581 DSTACK(__FUNCTION_NAME);
4583 for(std::map<std::string, Inventory*>::iterator
4584 i = m_detached_inventories.begin();
4585 i != m_detached_inventories.end(); i++){
4586 const std::string &name = i->first;
4587 //Inventory *inv = i->second;
4588 sendDetachedInventory(name, peer_id);
4596 void Server::DiePlayer(u16 peer_id)
4598 DSTACK(__FUNCTION_NAME);
4600 PlayerSAO *playersao = getPlayerSAO(peer_id);
4603 infostream<<"Server::DiePlayer(): Player "
4604 <<playersao->getPlayer()->getName()
4605 <<" dies"<<std::endl;
4607 playersao->setHP(0);
4609 // Trigger scripted stuff
4610 m_script->on_dieplayer(playersao);
4612 SendPlayerHP(peer_id);
4613 SendDeathscreen(m_con, peer_id, false, v3f(0,0,0));
4616 void Server::RespawnPlayer(u16 peer_id)
4618 DSTACK(__FUNCTION_NAME);
4620 PlayerSAO *playersao = getPlayerSAO(peer_id);
4623 infostream<<"Server::RespawnPlayer(): Player "
4624 <<playersao->getPlayer()->getName()
4625 <<" respawns"<<std::endl;
4627 playersao->setHP(PLAYER_MAX_HP);
4629 bool repositioned = m_script->on_respawnplayer(playersao);
4631 v3f pos = findSpawnPos(m_env->getServerMap());
4632 playersao->setPos(pos);
4636 void Server::DenyAccess(u16 peer_id, const std::wstring &reason)
4638 DSTACK(__FUNCTION_NAME);
4640 SendAccessDenied(m_con, peer_id, reason);
4642 RemoteClient *client = getClientNoEx(peer_id);
4644 client->denied = true;
4646 // If there are way too many clients, get rid of denied new ones immediately
4647 if(m_clients.size() > 2 * g_settings->getU16("max_users")){
4648 verbosestream<<"Server: DenyAccess: Too many clients; getting rid of "
4649 <<"peer_id="<<peer_id<<" immediately"<<std::endl;
4650 // Delete peer to stop sending it data
4651 m_con.DeletePeer(peer_id);
4652 // Delete client also to stop block sends and other stuff
4653 DeleteClient(peer_id, CDR_DENY);
4657 void Server::DeleteClient(u16 peer_id, ClientDeletionReason reason)
4659 DSTACK(__FUNCTION_NAME);
4662 std::map<u16, RemoteClient*>::iterator n;
4663 n = m_clients.find(peer_id);
4664 // The client may not exist; clients are immediately removed if their
4665 // access is denied, and this event occurs later then.
4666 if(n == m_clients.end())
4670 Mark objects to be not known by the client
4672 RemoteClient *client = n->second;
4674 for(std::set<u16>::iterator
4675 i = client->m_known_objects.begin();
4676 i != client->m_known_objects.end(); ++i)
4680 ServerActiveObject* obj = m_env->getActiveObject(id);
4682 if(obj && obj->m_known_by_count > 0)
4683 obj->m_known_by_count--;
4687 Clear references to playing sounds
4689 for(std::map<s32, ServerPlayingSound>::iterator
4690 i = m_playing_sounds.begin();
4691 i != m_playing_sounds.end();)
4693 ServerPlayingSound &psound = i->second;
4694 psound.clients.erase(peer_id);
4695 if(psound.clients.size() == 0)
4696 m_playing_sounds.erase(i++);
4701 Player *player = m_env->getPlayer(peer_id);
4703 // Collect information about leaving in chat
4704 std::wstring message;
4706 if(player != NULL && reason != CDR_DENY)
4708 std::wstring name = narrow_to_wide(player->getName());
4711 message += L" left the game.";
4712 if(reason == CDR_TIMEOUT)
4713 message += L" (timed out)";
4717 /* Run scripts and remove from environment */
4721 PlayerSAO *playersao = player->getPlayerSAO();
4724 m_script->on_leaveplayer(playersao);
4726 playersao->disconnected();
4734 if(player != NULL && reason != CDR_DENY)
4736 std::ostringstream os(std::ios_base::binary);
4737 for(std::map<u16, RemoteClient*>::iterator
4738 i = m_clients.begin();
4739 i != m_clients.end(); ++i)
4741 RemoteClient *client = i->second;
4742 assert(client->peer_id == i->first);
4743 if(client->serialization_version == SER_FMT_VER_INVALID)
4746 Player *player = m_env->getPlayer(client->peer_id);
4749 // Get name of player
4750 os<<player->getName()<<" ";
4753 actionstream<<player->getName()<<" "
4754 <<(reason==CDR_TIMEOUT?"times out.":"leaves game.")
4755 <<" List of players: "<<os.str()<<std::endl;
4760 delete m_clients[peer_id];
4761 m_clients.erase(peer_id);
4763 // Send leave chat message to all remaining clients
4764 if(message.length() != 0)
4765 BroadcastChatMessage(message);
4768 void Server::UpdateCrafting(u16 peer_id)
4770 DSTACK(__FUNCTION_NAME);
4772 Player* player = m_env->getPlayer(peer_id);
4775 // Get a preview for crafting
4777 getCraftingResult(&player->inventory, preview, false, this);
4779 // Put the new preview in
4780 InventoryList *plist = player->inventory.getList("craftpreview");
4782 assert(plist->getSize() >= 1);
4783 plist->changeItem(0, preview);
4786 RemoteClient* Server::getClient(u16 peer_id)
4788 RemoteClient *client = getClientNoEx(peer_id);
4790 throw ClientNotFoundException("Client not found");
4793 RemoteClient* Server::getClientNoEx(u16 peer_id)
4795 std::map<u16, RemoteClient*>::iterator n;
4796 n = m_clients.find(peer_id);
4797 // The client may not exist; clients are immediately removed if their
4798 // access is denied, and this event occurs later then.
4799 if(n == m_clients.end())
4804 std::string Server::getPlayerName(u16 peer_id)
4806 Player *player = m_env->getPlayer(peer_id);
4808 return "[id="+itos(peer_id)+"]";
4809 return player->getName();
4812 PlayerSAO* Server::getPlayerSAO(u16 peer_id)
4814 Player *player = m_env->getPlayer(peer_id);
4817 return player->getPlayerSAO();
4820 std::wstring Server::getStatusString()
4822 std::wostringstream os(std::ios_base::binary);
4825 os<<L"version="<<narrow_to_wide(VERSION_STRING);
4827 os<<L", uptime="<<m_uptime.get();
4829 os<<L", max_lag="<<m_env->getMaxLagEstimate();
4830 // Information about clients
4831 std::map<u16, RemoteClient*>::iterator i;
4834 for(i = m_clients.begin(), first = true;
4835 i != m_clients.end(); ++i)
4837 // Get client and check that it is valid
4838 RemoteClient *client = i->second;
4839 assert(client->peer_id == i->first);
4840 if(client->serialization_version == SER_FMT_VER_INVALID)
4843 Player *player = m_env->getPlayer(client->peer_id);
4844 // Get name of player
4845 std::wstring name = L"unknown";
4847 name = narrow_to_wide(player->getName());
4848 // Add name to information string
4856 if(((ServerMap*)(&m_env->getMap()))->isSavingEnabled() == false)
4857 os<<std::endl<<L"# Server: "<<" WARNING: Map saving is disabled.";
4858 if(g_settings->get("motd") != "")
4859 os<<std::endl<<L"# Server: "<<narrow_to_wide(g_settings->get("motd"));
4863 std::set<std::string> Server::getPlayerEffectivePrivs(const std::string &name)
4865 std::set<std::string> privs;
4866 m_script->getAuth(name, NULL, &privs);
4870 bool Server::checkPriv(const std::string &name, const std::string &priv)
4872 std::set<std::string> privs = getPlayerEffectivePrivs(name);
4873 return (privs.count(priv) != 0);
4876 void Server::reportPrivsModified(const std::string &name)
4879 for(std::map<u16, RemoteClient*>::iterator
4880 i = m_clients.begin();
4881 i != m_clients.end(); ++i){
4882 RemoteClient *client = i->second;
4883 Player *player = m_env->getPlayer(client->peer_id);
4884 reportPrivsModified(player->getName());
4887 Player *player = m_env->getPlayer(name.c_str());
4890 SendPlayerPrivileges(player->peer_id);
4891 PlayerSAO *sao = player->getPlayerSAO();
4894 sao->updatePrivileges(
4895 getPlayerEffectivePrivs(name),
4900 void Server::reportInventoryFormspecModified(const std::string &name)
4902 Player *player = m_env->getPlayer(name.c_str());
4905 SendPlayerInventoryFormspec(player->peer_id);
4908 void Server::setIpBanned(const std::string &ip, const std::string &name)
4910 m_banmanager->add(ip, name);
4913 void Server::unsetIpBanned(const std::string &ip_or_name)
4915 m_banmanager->remove(ip_or_name);
4918 std::string Server::getBanDescription(const std::string &ip_or_name)
4920 return m_banmanager->getBanDescription(ip_or_name);
4923 void Server::notifyPlayer(const char *name, const std::wstring msg, const bool prepend = true)
4925 Player *player = m_env->getPlayer(name);
4929 SendChatMessage(player->peer_id, std::wstring(L"Server -!- ")+msg);
4931 SendChatMessage(player->peer_id, msg);
4934 bool Server::showFormspec(const char *playername, const std::string &formspec, const std::string &formname)
4936 Player *player = m_env->getPlayer(playername);
4940 infostream<<"showFormspec: couldn't find player:"<<playername<<std::endl;
4944 SendShowFormspecMessage(player->peer_id, formspec, formname);
4948 u32 Server::hudAdd(Player *player, HudElement *form) {
4952 u32 id = player->getFreeHudID();
4953 if (id < player->hud.size())
4954 player->hud[id] = form;
4956 player->hud.push_back(form);
4958 SendHUDAdd(player->peer_id, id, form);
4962 bool Server::hudRemove(Player *player, u32 id) {
4963 if (!player || id >= player->hud.size() || !player->hud[id])
4966 delete player->hud[id];
4967 player->hud[id] = NULL;
4969 SendHUDRemove(player->peer_id, id);
4973 bool Server::hudChange(Player *player, u32 id, HudElementStat stat, void *data) {
4977 SendHUDChange(player->peer_id, id, stat, data);
4981 bool Server::hudSetFlags(Player *player, u32 flags, u32 mask) {
4985 SendHUDSetFlags(player->peer_id, flags, mask);
4989 bool Server::hudSetHotbarItemcount(Player *player, s32 hotbar_itemcount) {
4992 if (hotbar_itemcount <= 0 || hotbar_itemcount > HUD_HOTBAR_ITEMCOUNT_MAX)
4995 std::ostringstream os(std::ios::binary);
4996 writeS32(os, hotbar_itemcount);
4997 SendHUDSetParam(player->peer_id, HUD_PARAM_HOTBAR_ITEMCOUNT, os.str());
5001 void Server::notifyPlayers(const std::wstring msg)
5003 BroadcastChatMessage(msg);
5006 void Server::spawnParticle(const char *playername, v3f pos,
5007 v3f velocity, v3f acceleration,
5008 float expirationtime, float size, bool
5009 collisiondetection, std::string texture)
5011 Player *player = m_env->getPlayer(playername);
5014 SendSpawnParticle(player->peer_id, pos, velocity, acceleration,
5015 expirationtime, size, collisiondetection, texture);
5018 void Server::spawnParticleAll(v3f pos, v3f velocity, v3f acceleration,
5019 float expirationtime, float size,
5020 bool collisiondetection, std::string texture)
5022 SendSpawnParticleAll(pos, velocity, acceleration,
5023 expirationtime, size, collisiondetection, texture);
5026 u32 Server::addParticleSpawner(const char *playername,
5027 u16 amount, float spawntime,
5028 v3f minpos, v3f maxpos,
5029 v3f minvel, v3f maxvel,
5030 v3f minacc, v3f maxacc,
5031 float minexptime, float maxexptime,
5032 float minsize, float maxsize,
5033 bool collisiondetection, std::string texture)
5035 Player *player = m_env->getPlayer(playername);
5040 for(;;) // look for unused particlespawner id
5043 if (std::find(m_particlespawner_ids.begin(),
5044 m_particlespawner_ids.end(), id)
5045 == m_particlespawner_ids.end())
5047 m_particlespawner_ids.push_back(id);
5052 SendAddParticleSpawner(player->peer_id, amount, spawntime,
5053 minpos, maxpos, minvel, maxvel, minacc, maxacc,
5054 minexptime, maxexptime, minsize, maxsize,
5055 collisiondetection, texture, id);
5060 u32 Server::addParticleSpawnerAll(u16 amount, float spawntime,
5061 v3f minpos, v3f maxpos,
5062 v3f minvel, v3f maxvel,
5063 v3f minacc, v3f maxacc,
5064 float minexptime, float maxexptime,
5065 float minsize, float maxsize,
5066 bool collisiondetection, std::string texture)
5069 for(;;) // look for unused particlespawner id
5072 if (std::find(m_particlespawner_ids.begin(),
5073 m_particlespawner_ids.end(), id)
5074 == m_particlespawner_ids.end())
5076 m_particlespawner_ids.push_back(id);
5081 SendAddParticleSpawnerAll(amount, spawntime,
5082 minpos, maxpos, minvel, maxvel, minacc, maxacc,
5083 minexptime, maxexptime, minsize, maxsize,
5084 collisiondetection, texture, id);
5089 void Server::deleteParticleSpawner(const char *playername, u32 id)
5091 Player *player = m_env->getPlayer(playername);
5095 m_particlespawner_ids.erase(
5096 std::remove(m_particlespawner_ids.begin(),
5097 m_particlespawner_ids.end(), id),
5098 m_particlespawner_ids.end());
5099 SendDeleteParticleSpawner(player->peer_id, id);
5102 void Server::deleteParticleSpawnerAll(u32 id)
5104 m_particlespawner_ids.erase(
5105 std::remove(m_particlespawner_ids.begin(),
5106 m_particlespawner_ids.end(), id),
5107 m_particlespawner_ids.end());
5108 SendDeleteParticleSpawnerAll(id);
5111 Inventory* Server::createDetachedInventory(const std::string &name)
5113 if(m_detached_inventories.count(name) > 0){
5114 infostream<<"Server clearing detached inventory \""<<name<<"\""<<std::endl;
5115 delete m_detached_inventories[name];
5117 infostream<<"Server creating detached inventory \""<<name<<"\""<<std::endl;
5119 Inventory *inv = new Inventory(m_itemdef);
5121 m_detached_inventories[name] = inv;
5122 sendDetachedInventoryToAll(name);
5129 BoolScopeSet(bool *dst, bool val):
5132 m_orig_state = *m_dst;
5137 *m_dst = m_orig_state;
5144 // actions: time-reversed list
5145 // Return value: success/failure
5146 bool Server::rollbackRevertActions(const std::list<RollbackAction> &actions,
5147 std::list<std::string> *log)
5149 infostream<<"Server::rollbackRevertActions(len="<<actions.size()<<")"<<std::endl;
5150 ServerMap *map = (ServerMap*)(&m_env->getMap());
5151 // Disable rollback report sink while reverting
5152 BoolScopeSet rollback_scope_disable(&m_rollback_sink_enabled, false);
5154 // Fail if no actions to handle
5155 if(actions.empty()){
5156 log->push_back("Nothing to do.");
5163 for(std::list<RollbackAction>::const_iterator
5164 i = actions.begin();
5165 i != actions.end(); i++)
5167 const RollbackAction &action = *i;
5169 bool success = action.applyRevert(map, this, this);
5172 std::ostringstream os;
5173 os<<"Revert of step ("<<num_tried<<") "<<action.toString()<<" failed";
5174 infostream<<"Map::rollbackRevertActions(): "<<os.str()<<std::endl;
5176 log->push_back(os.str());
5178 std::ostringstream os;
5179 os<<"Successfully reverted step ("<<num_tried<<") "<<action.toString();
5180 infostream<<"Map::rollbackRevertActions(): "<<os.str()<<std::endl;
5182 log->push_back(os.str());
5186 infostream<<"Map::rollbackRevertActions(): "<<num_failed<<"/"<<num_tried
5187 <<" failed"<<std::endl;
5189 // Call it done if less than half failed
5190 return num_failed <= num_tried/2;
5193 // IGameDef interface
5195 IItemDefManager* Server::getItemDefManager()
5199 INodeDefManager* Server::getNodeDefManager()
5203 ICraftDefManager* Server::getCraftDefManager()
5207 ITextureSource* Server::getTextureSource()
5211 IShaderSource* Server::getShaderSource()
5215 u16 Server::allocateUnknownNodeId(const std::string &name)
5217 return m_nodedef->allocateDummy(name);
5219 ISoundManager* Server::getSoundManager()
5221 return &dummySoundManager;
5223 MtEventManager* Server::getEventManager()
5227 IRollbackReportSink* Server::getRollbackReportSink()
5229 if(!m_enable_rollback_recording)
5231 if(!m_rollback_sink_enabled)
5236 IWritableItemDefManager* Server::getWritableItemDefManager()
5240 IWritableNodeDefManager* Server::getWritableNodeDefManager()
5244 IWritableCraftDefManager* Server::getWritableCraftDefManager()
5249 const ModSpec* Server::getModSpec(const std::string &modname)
5251 for(std::vector<ModSpec>::iterator i = m_mods.begin();
5252 i != m_mods.end(); i++){
5253 const ModSpec &mod = *i;
5254 if(mod.name == modname)
5259 void Server::getModNames(std::list<std::string> &modlist)
5261 for(std::vector<ModSpec>::iterator i = m_mods.begin(); i != m_mods.end(); i++)
5263 modlist.push_back(i->name);
5266 std::string Server::getBuiltinLuaPath()
5268 return porting::path_share + DIR_DELIM + "builtin";
5271 v3f findSpawnPos(ServerMap &map)
5273 //return v3f(50,50,50)*BS;
5278 nodepos = v2s16(0,0);
5283 s16 water_level = map.m_mgparams->water_level;
5285 // Try to find a good place a few times
5286 for(s32 i=0; i<1000; i++)
5289 // We're going to try to throw the player to this position
5290 v2s16 nodepos2d = v2s16(
5291 -range + (myrand() % (range * 2)),
5292 -range + (myrand() % (range * 2)));
5294 // Get ground height at point
5295 s16 groundheight = map.findGroundLevel(nodepos2d);
5296 if (groundheight <= water_level) // Don't go underwater
5298 if (groundheight > water_level + 6) // Don't go to high places
5301 nodepos = v3s16(nodepos2d.X, groundheight, nodepos2d.Y);
5302 bool is_good = false;
5304 for (s32 i = 0; i < 10; i++) {
5305 v3s16 blockpos = getNodeBlockPos(nodepos);
5306 map.emergeBlock(blockpos, true);
5307 content_t c = map.getNodeNoEx(nodepos).getContent();
5308 if (c == CONTENT_AIR || c == CONTENT_IGNORE) {
5310 if (air_count >= 2){
5318 // Found a good place
5319 //infostream<<"Searched through "<<i<<" places."<<std::endl;
5325 return intToFloat(nodepos, BS);
5328 PlayerSAO* Server::emergePlayer(const char *name, u16 peer_id)
5330 RemotePlayer *player = NULL;
5331 bool newplayer = false;
5334 Try to get an existing player
5336 player = static_cast<RemotePlayer*>(m_env->getPlayer(name));
5338 // If player is already connected, cancel
5339 if(player != NULL && player->peer_id != 0)
5341 infostream<<"emergePlayer(): Player already connected"<<std::endl;
5346 If player with the wanted peer_id already exists, cancel.
5348 if(m_env->getPlayer(peer_id) != NULL)
5350 infostream<<"emergePlayer(): Player with wrong name but same"
5351 " peer_id already exists"<<std::endl;
5356 Create a new player if it doesn't exist yet
5361 player = new RemotePlayer(this);
5362 player->updateName(name);
5364 /* Set player position */
5365 infostream<<"Server: Finding spawn place for player \""
5366 <<name<<"\""<<std::endl;
5367 v3f pos = findSpawnPos(m_env->getServerMap());
5368 player->setPosition(pos);
5370 /* Add player to environment */
5371 m_env->addPlayer(player);
5375 Create a new player active object
5377 PlayerSAO *playersao = new PlayerSAO(m_env, player, peer_id,
5378 getPlayerEffectivePrivs(player->getName()),
5381 /* Clean up old HUD elements from previous sessions */
5382 player->hud.clear();
5384 /* Add object to environment */
5385 m_env->addActiveObject(playersao);
5389 m_script->on_newplayer(playersao);
5391 m_script->on_joinplayer(playersao);
5396 void Server::handlePeerChange(PeerChange &c)
5398 JMutexAutoLock envlock(m_env_mutex);
5399 JMutexAutoLock conlock(m_con_mutex);
5401 if(c.type == PEER_ADDED)
5408 std::map<u16, RemoteClient*>::iterator n;
5409 n = m_clients.find(c.peer_id);
5410 // The client shouldn't already exist
5411 assert(n == m_clients.end());
5414 RemoteClient *client = new RemoteClient();
5415 client->peer_id = c.peer_id;
5416 m_clients[client->peer_id] = client;
5419 else if(c.type == PEER_REMOVED)
5425 DeleteClient(c.peer_id, c.timeout?CDR_TIMEOUT:CDR_LEAVE);
5434 void Server::handlePeerChanges()
5436 while(m_peer_change_queue.size() > 0)
5438 PeerChange c = m_peer_change_queue.pop_front();
5440 verbosestream<<"Server: Handling peer change: "
5441 <<"id="<<c.peer_id<<", timeout="<<c.timeout
5444 handlePeerChange(c);
5448 void dedicated_server_loop(Server &server, bool &kill)
5450 DSTACK(__FUNCTION_NAME);
5452 verbosestream<<"dedicated_server_loop()"<<std::endl;
5454 IntervalLimiter m_profiler_interval;
5458 float steplen = g_settings->getFloat("dedicated_server_step");
5459 // This is kind of a hack but can be done like this
5460 // because server.step() is very light
5462 ScopeProfiler sp(g_profiler, "dedicated server sleep");
5463 sleep_ms((int)(steplen*1000.0));
5465 server.step(steplen);
5467 if(server.getShutdownRequested() || kill)
5469 infostream<<"Dedicated server quitting"<<std::endl;
5471 if(g_settings->getBool("server_announce") == true)
5472 ServerList::sendAnnounce("delete");
5480 float profiler_print_interval =
5481 g_settings->getFloat("profiler_print_interval");
5482 if(profiler_print_interval != 0)
5484 if(m_profiler_interval.step(steplen, profiler_print_interval))
5486 infostream<<"Profiler:"<<std::endl;
5487 g_profiler->print(infostream);
5488 g_profiler->clear();