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 "jthread/jmutexautolock.h"
30 #include "constants.h"
36 #include "serverobject.h"
37 #include "genericobject.h"
41 #include "scripting_game.h"
48 #include "content_mapnode.h"
49 #include "content_nodemeta.h"
50 #include "content_abm.h"
51 #include "content_sao.h"
56 #include "sound.h" // dummySoundManager
57 #include "event_manager.h"
59 #include "serverlist.h"
60 #include "util/string.h"
61 #include "util/pointedthing.h"
62 #include "util/mathconstants.h"
64 #include "util/serialize.h"
65 #include "util/thread.h"
66 #include "defaultsettings.h"
68 class ClientNotFoundException : public BaseException
71 ClientNotFoundException(const char *s):
76 class ServerThread : public SimpleThread
82 ServerThread(Server *server):
91 void * ServerThread::Thread()
95 log_register_thread("ServerThread");
97 DSTACK(__FUNCTION_NAME);
99 BEGIN_DEBUG_EXCEPTION_HANDLER
104 //TimeTaker timer("AsyncRunStep() + Receive()");
107 //TimeTaker timer("AsyncRunStep()");
108 m_server->AsyncRunStep();
111 //infostream<<"Running m_server->Receive()"<<std::endl;
114 catch(con::NoIncomingDataException &e)
117 catch(con::PeerNotFoundException &e)
119 infostream<<"Server: PeerNotFoundException"<<std::endl;
121 catch(ClientNotFoundException &e)
124 catch(con::ConnectionBindFailed &e)
126 m_server->setAsyncFatalError(e.what());
130 m_server->setAsyncFatalError(e.what());
134 END_DEBUG_EXCEPTION_HANDLER(errorstream)
139 v3f ServerSoundParams::getPos(ServerEnvironment *env, bool *pos_exists) const
141 if(pos_exists) *pos_exists = false;
146 if(pos_exists) *pos_exists = true;
151 ServerActiveObject *sao = env->getActiveObject(object);
154 if(pos_exists) *pos_exists = true;
155 return sao->getBasePosition(); }
160 void RemoteClient::GetNextBlocks(Server *server, float dtime,
161 std::vector<PrioritySortedBlockTransfer> &dest)
163 DSTACK(__FUNCTION_NAME);
166 TimeTaker timer("RemoteClient::GetNextBlocks", &timer_result);*/
169 m_nothing_to_send_pause_timer -= dtime;
170 m_nearest_unsent_reset_timer += dtime;
172 if(m_nothing_to_send_pause_timer >= 0)
175 Player *player = server->m_env->getPlayer(peer_id);
176 // This can happen sometimes; clients and players are not in perfect sync.
180 // Won't send anything if already sending
181 if(m_blocks_sending.size() >= g_settings->getU16
182 ("max_simultaneous_block_sends_per_client"))
184 //infostream<<"Not sending any blocks, Queue full."<<std::endl;
188 //TimeTaker timer("RemoteClient::GetNextBlocks");
190 v3f playerpos = player->getPosition();
191 v3f playerspeed = player->getSpeed();
192 v3f playerspeeddir(0,0,0);
193 if(playerspeed.getLength() > 1.0*BS)
194 playerspeeddir = playerspeed / playerspeed.getLength();
195 // Predict to next block
196 v3f playerpos_predicted = playerpos + playerspeeddir*MAP_BLOCKSIZE*BS;
198 v3s16 center_nodepos = floatToInt(playerpos_predicted, BS);
200 v3s16 center = getNodeBlockPos(center_nodepos);
202 // Camera position and direction
203 v3f camera_pos = player->getEyePosition();
204 v3f camera_dir = v3f(0,0,1);
205 camera_dir.rotateYZBy(player->getPitch());
206 camera_dir.rotateXZBy(player->getYaw());
208 /*infostream<<"camera_dir=("<<camera_dir.X<<","<<camera_dir.Y<<","
209 <<camera_dir.Z<<")"<<std::endl;*/
212 Get the starting value of the block finder radius.
215 if(m_last_center != center)
217 m_nearest_unsent_d = 0;
218 m_last_center = center;
221 /*infostream<<"m_nearest_unsent_reset_timer="
222 <<m_nearest_unsent_reset_timer<<std::endl;*/
224 // Reset periodically to workaround for some bugs or stuff
225 if(m_nearest_unsent_reset_timer > 20.0)
227 m_nearest_unsent_reset_timer = 0;
228 m_nearest_unsent_d = 0;
229 //infostream<<"Resetting m_nearest_unsent_d for "
230 // <<server->getPlayerName(peer_id)<<std::endl;
233 //s16 last_nearest_unsent_d = m_nearest_unsent_d;
234 s16 d_start = m_nearest_unsent_d;
236 //infostream<<"d_start="<<d_start<<std::endl;
238 u16 max_simul_sends_setting = g_settings->getU16
239 ("max_simultaneous_block_sends_per_client");
240 u16 max_simul_sends_usually = max_simul_sends_setting;
243 Check the time from last addNode/removeNode.
245 Decrease send rate if player is building stuff.
247 m_time_from_building += dtime;
248 if(m_time_from_building < g_settings->getFloat(
249 "full_block_send_enable_min_time_from_building"))
251 max_simul_sends_usually
252 = LIMITED_MAX_SIMULTANEOUS_BLOCK_SENDS;
256 Number of blocks sending + number of blocks selected for sending
258 u32 num_blocks_selected = m_blocks_sending.size();
261 next time d will be continued from the d from which the nearest
262 unsent block was found this time.
264 This is because not necessarily any of the blocks found this
265 time are actually sent.
267 s32 new_nearest_unsent_d = -1;
269 s16 d_max = g_settings->getS16("max_block_send_distance");
270 s16 d_max_gen = g_settings->getS16("max_block_generate_distance");
272 // Don't loop very much at a time
273 s16 max_d_increment_at_time = 2;
274 if(d_max > d_start + max_d_increment_at_time)
275 d_max = d_start + max_d_increment_at_time;
276 /*if(d_max_gen > d_start+2)
277 d_max_gen = d_start+2;*/
279 //infostream<<"Starting from "<<d_start<<std::endl;
281 s32 nearest_emerged_d = -1;
282 s32 nearest_emergefull_d = -1;
283 s32 nearest_sent_d = -1;
284 bool queue_is_full = false;
287 for(d = d_start; d <= d_max; d++)
289 /*errorstream<<"checking d="<<d<<" for "
290 <<server->getPlayerName(peer_id)<<std::endl;*/
291 //infostream<<"RemoteClient::SendBlocks(): d="<<d<<std::endl;
294 If m_nearest_unsent_d was changed by the EmergeThread
295 (it can change it to 0 through SetBlockNotSent),
297 Else update m_nearest_unsent_d
299 /*if(m_nearest_unsent_d != last_nearest_unsent_d)
301 d = m_nearest_unsent_d;
302 last_nearest_unsent_d = m_nearest_unsent_d;
306 Get the border/face dot coordinates of a "d-radiused"
309 std::list<v3s16> list;
310 getFacePositions(list, d);
312 std::list<v3s16>::iterator li;
313 for(li=list.begin(); li!=list.end(); ++li)
315 v3s16 p = *li + center;
319 - Don't allow too many simultaneous transfers
320 - EXCEPT when the blocks are very close
322 Also, don't send blocks that are already flying.
325 // Start with the usual maximum
326 u16 max_simul_dynamic = max_simul_sends_usually;
328 // If block is very close, allow full maximum
329 if(d <= BLOCK_SEND_DISABLE_LIMITS_MAX_D)
330 max_simul_dynamic = max_simul_sends_setting;
332 // Don't select too many blocks for sending
333 if(num_blocks_selected >= max_simul_dynamic)
335 queue_is_full = true;
336 goto queue_full_break;
339 // Don't send blocks that are currently being transferred
340 if(m_blocks_sending.find(p) != m_blocks_sending.end())
346 if(p.X < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
347 || p.X > MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
348 || p.Y < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
349 || p.Y > MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
350 || p.Z < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
351 || p.Z > MAP_GENERATION_LIMIT / MAP_BLOCKSIZE)
354 // If this is true, inexistent block will be made from scratch
355 bool generate = d <= d_max_gen;
358 /*// Limit the generating area vertically to 2/3
359 if(abs(p.Y - center.Y) > d_max_gen - d_max_gen / 3)
362 // Limit the send area vertically to 1/2
363 if(abs(p.Y - center.Y) > d_max / 2)
369 If block is far away, don't generate it unless it is
375 // Block center y in nodes
376 f32 y = (f32)(p.Y * MAP_BLOCKSIZE + MAP_BLOCKSIZE/2);
377 // Don't generate if it's very high or very low
378 if(y < -64 || y > 64)
382 v2s16 p2d_nodes_center(
386 // Get ground height in nodes
387 s16 gh = server->m_env->getServerMap().findGroundLevel(
390 // If differs a lot, don't generate
391 if(fabs(gh - y) > MAP_BLOCKSIZE*2)
393 // Actually, don't even send it
399 //infostream<<"d="<<d<<std::endl;
402 Don't generate or send if not in sight
403 FIXME This only works if the client uses a small enough
404 FOV setting. The default of 72 degrees is fine.
407 float camera_fov = (72.0*M_PI/180) * 4./3.;
408 if(isBlockInSight(p, camera_pos, camera_dir, camera_fov, 10000*BS) == false)
414 Don't send already sent blocks
417 if(m_blocks_sent.find(p) != m_blocks_sent.end())
424 Check if map has this block
426 MapBlock *block = server->m_env->getMap().getBlockNoCreateNoEx(p);
428 bool surely_not_found_on_disk = false;
429 bool block_is_invalid = false;
432 // Reset usage timer, this block will be of use in the future.
433 block->resetUsageTimer();
435 // Block is dummy if data doesn't exist.
436 // It means it has been not found from disk and not generated
439 surely_not_found_on_disk = true;
442 // Block is valid if lighting is up-to-date and data exists
443 if(block->isValid() == false)
445 block_is_invalid = true;
448 /*if(block->isFullyGenerated() == false)
450 block_is_invalid = true;
455 ServerMap *map = (ServerMap*)(&server->m_env->getMap());
456 v2s16 chunkpos = map->sector_to_chunk(p2d);
457 if(map->chunkNonVolatile(chunkpos) == false)
458 block_is_invalid = true;
460 if(block->isGenerated() == false)
461 block_is_invalid = true;
464 If block is not close, don't send it unless it is near
467 Block is near ground level if night-time mesh
468 differs from day-time mesh.
472 if(block->getDayNightDiff() == false)
479 If block has been marked to not exist on disk (dummy)
480 and generating new ones is not wanted, skip block.
482 if(generate == false && surely_not_found_on_disk == true)
489 Add inexistent block to emerge queue.
491 if(block == NULL || surely_not_found_on_disk || block_is_invalid)
493 /* //TODO: Get value from somewhere
494 // Allow only one block in emerge queue
495 //if(server->m_emerge_queue.peerItemCount(peer_id) < 1)
496 // Allow two blocks in queue per client
497 //if(server->m_emerge_queue.peerItemCount(peer_id) < 2)
499 // Make it more responsive when needing to generate stuff
500 if(surely_not_found_on_disk)
502 if(server->m_emerge_queue.peerItemCount(peer_id) < max_emerge)
504 //infostream<<"Adding block to emerge queue"<<std::endl;
506 // Add it to the emerge queue and trigger the thread
509 if(generate == false)
510 flags |= BLOCK_EMERGE_FLAG_FROMDISK;
512 server->m_emerge_queue.addBlock(peer_id, p, flags);
513 server->m_emergethread.trigger();
515 if(nearest_emerged_d == -1)
516 nearest_emerged_d = d;
518 if(nearest_emergefull_d == -1)
519 nearest_emergefull_d = d;
520 goto queue_full_break;
524 if (server->m_emerge->enqueueBlockEmerge(peer_id, p, generate)) {
525 if (nearest_emerged_d == -1)
526 nearest_emerged_d = d;
528 if (nearest_emergefull_d == -1)
529 nearest_emergefull_d = d;
530 goto queue_full_break;
537 if(nearest_sent_d == -1)
541 Add block to send queue
544 /*errorstream<<"sending from d="<<d<<" to "
545 <<server->getPlayerName(peer_id)<<std::endl;*/
547 PrioritySortedBlockTransfer q((float)d, p, peer_id);
551 num_blocks_selected += 1;
556 //infostream<<"Stopped at "<<d<<std::endl;
558 // If nothing was found for sending and nothing was queued for
559 // emerging, continue next time browsing from here
560 if(nearest_emerged_d != -1){
561 new_nearest_unsent_d = nearest_emerged_d;
562 } else if(nearest_emergefull_d != -1){
563 new_nearest_unsent_d = nearest_emergefull_d;
565 if(d > g_settings->getS16("max_block_send_distance")){
566 new_nearest_unsent_d = 0;
567 m_nothing_to_send_pause_timer = 2.0;
568 /*infostream<<"GetNextBlocks(): d wrapped around for "
569 <<server->getPlayerName(peer_id)
570 <<"; setting to 0 and pausing"<<std::endl;*/
572 if(nearest_sent_d != -1)
573 new_nearest_unsent_d = nearest_sent_d;
575 new_nearest_unsent_d = d;
579 if(new_nearest_unsent_d != -1)
580 m_nearest_unsent_d = new_nearest_unsent_d;
582 /*timer_result = timer.stop(true);
583 if(timer_result != 0)
584 infostream<<"GetNextBlocks timeout: "<<timer_result<<" (!=0)"<<std::endl;*/
587 void RemoteClient::GotBlock(v3s16 p)
589 if(m_blocks_sending.find(p) != m_blocks_sending.end())
590 m_blocks_sending.erase(p);
593 /*infostream<<"RemoteClient::GotBlock(): Didn't find in"
594 " m_blocks_sending"<<std::endl;*/
595 m_excess_gotblocks++;
597 m_blocks_sent.insert(p);
600 void RemoteClient::SentBlock(v3s16 p)
602 if(m_blocks_sending.find(p) == m_blocks_sending.end())
603 m_blocks_sending[p] = 0.0;
605 infostream<<"RemoteClient::SentBlock(): Sent block"
606 " already in m_blocks_sending"<<std::endl;
609 void RemoteClient::SetBlockNotSent(v3s16 p)
611 m_nearest_unsent_d = 0;
613 if(m_blocks_sending.find(p) != m_blocks_sending.end())
614 m_blocks_sending.erase(p);
615 if(m_blocks_sent.find(p) != m_blocks_sent.end())
616 m_blocks_sent.erase(p);
619 void RemoteClient::SetBlocksNotSent(std::map<v3s16, MapBlock*> &blocks)
621 m_nearest_unsent_d = 0;
623 for(std::map<v3s16, MapBlock*>::iterator
625 i != blocks.end(); ++i)
629 if(m_blocks_sending.find(p) != m_blocks_sending.end())
630 m_blocks_sending.erase(p);
631 if(m_blocks_sent.find(p) != m_blocks_sent.end())
632 m_blocks_sent.erase(p);
641 const std::string &path_world,
642 const SubgameSpec &gamespec,
643 bool simple_singleplayer_mode
645 m_path_world(path_world),
646 m_gamespec(gamespec),
647 m_simple_singleplayer_mode(simple_singleplayer_mode),
648 m_async_fatal_error(""),
650 m_con(PROTOCOL_ID, 512, CONNECTION_TIMEOUT,
651 g_settings->getBool("enable_ipv6") && g_settings->getBool("ipv6_server"), this),
654 m_rollback_sink_enabled(true),
655 m_enable_rollback_recording(false),
658 m_itemdef(createItemDefManager()),
659 m_nodedef(createNodeDefManager()),
660 m_craftdef(createCraftDefManager()),
661 m_event(new EventManager()),
663 m_time_of_day_send_timer(0),
665 m_shutdown_requested(false),
666 m_ignore_map_edit_events(false),
667 m_ignore_map_edit_events_peer_id(0)
669 m_liquid_transform_timer = 0.0;
670 m_liquid_transform_every = 1.0;
671 m_print_info_timer = 0.0;
672 m_masterserver_timer = 0.0;
673 m_objectdata_timer = 0.0;
674 m_emergethread_trigger_timer = 0.0;
675 m_savemap_timer = 0.0;
676 m_clients_number = 0;
680 m_step_dtime_mutex.Init();
684 throw ServerError("Supplied empty world path");
686 if(!gamespec.isValid())
687 throw ServerError("Supplied invalid gamespec");
689 infostream<<"Server created for gameid \""<<m_gamespec.id<<"\"";
690 if(m_simple_singleplayer_mode)
691 infostream<<" in simple singleplayer mode"<<std::endl;
693 infostream<<std::endl;
694 infostream<<"- world: "<<m_path_world<<std::endl;
695 infostream<<"- game: "<<m_gamespec.path<<std::endl;
697 // Initialize default settings and override defaults with those provided
699 set_default_settings(g_settings);
700 Settings gamedefaults;
701 getGameMinetestConfig(gamespec.path, gamedefaults);
702 override_default_settings(g_settings, &gamedefaults);
704 // Create server thread
705 m_thread = new ServerThread(this);
707 // Create emerge manager
708 m_emerge = new EmergeManager(this);
710 // Create ban manager
711 std::string ban_path = m_path_world+DIR_DELIM+"ipban.txt";
712 m_banmanager = new BanManager(ban_path);
714 // Create rollback manager
715 std::string rollback_path = m_path_world+DIR_DELIM+"rollback.txt";
716 m_rollback = createRollbackManager(rollback_path, this);
718 // Create world if it doesn't exist
719 if(!initializeWorld(m_path_world, m_gamespec.id))
720 throw ServerError("Failed to initialize world");
722 ModConfiguration modconf(m_path_world);
723 m_mods = modconf.getMods();
724 std::vector<ModSpec> unsatisfied_mods = modconf.getUnsatisfiedMods();
725 // complain about mods with unsatisfied dependencies
726 if(!modconf.isConsistent())
728 for(std::vector<ModSpec>::iterator it = unsatisfied_mods.begin();
729 it != unsatisfied_mods.end(); ++it)
732 errorstream << "mod \"" << mod.name << "\" has unsatisfied dependencies: ";
733 for(std::set<std::string>::iterator dep_it = mod.unsatisfied_depends.begin();
734 dep_it != mod.unsatisfied_depends.end(); ++dep_it)
735 errorstream << " \"" << *dep_it << "\"";
736 errorstream << std::endl;
740 Settings worldmt_settings;
741 std::string worldmt = m_path_world + DIR_DELIM + "world.mt";
742 worldmt_settings.readConfigFile(worldmt.c_str());
743 std::vector<std::string> names = worldmt_settings.getNames();
744 std::set<std::string> load_mod_names;
745 for(std::vector<std::string>::iterator it = names.begin();
746 it != names.end(); ++it)
748 std::string name = *it;
749 if(name.compare(0,9,"load_mod_")==0 && worldmt_settings.getBool(name))
750 load_mod_names.insert(name.substr(9));
752 // complain about mods declared to be loaded, but not found
753 for(std::vector<ModSpec>::iterator it = m_mods.begin();
754 it != m_mods.end(); ++it)
755 load_mod_names.erase((*it).name);
756 for(std::vector<ModSpec>::iterator it = unsatisfied_mods.begin();
757 it != unsatisfied_mods.end(); ++it)
758 load_mod_names.erase((*it).name);
759 if(!load_mod_names.empty())
761 errorstream << "The following mods could not be found:";
762 for(std::set<std::string>::iterator it = load_mod_names.begin();
763 it != load_mod_names.end(); ++it)
764 errorstream << " \"" << (*it) << "\"";
765 errorstream << std::endl;
768 // Path to builtin.lua
769 std::string builtinpath = getBuiltinLuaPath() + DIR_DELIM + "builtin.lua";
772 JMutexAutoLock envlock(m_env_mutex);
773 JMutexAutoLock conlock(m_con_mutex);
775 // Initialize scripting
777 infostream<<"Server: Initializing Lua"<<std::endl;
779 m_script = new GameScripting(this);
782 // Load and run builtin.lua
783 infostream<<"Server: Loading builtin.lua [\""
784 <<builtinpath<<"\"]"<<std::endl;
785 bool success = m_script->loadMod(builtinpath, "__builtin");
787 errorstream<<"Server: Failed to load and run "
788 <<builtinpath<<std::endl;
789 throw ModError("Failed to load and run "+builtinpath);
792 infostream<<"Server: Loading mods: ";
793 for(std::vector<ModSpec>::iterator i = m_mods.begin();
794 i != m_mods.end(); i++){
795 const ModSpec &mod = *i;
796 infostream<<mod.name<<" ";
798 infostream<<std::endl;
799 // Load and run "mod" scripts
800 for(std::vector<ModSpec>::iterator i = m_mods.begin();
801 i != m_mods.end(); i++){
802 const ModSpec &mod = *i;
803 std::string scriptpath = mod.path + DIR_DELIM + "init.lua";
804 infostream<<" ["<<padStringRight(mod.name, 12)<<"] [\""
805 <<scriptpath<<"\"]"<<std::endl;
806 bool success = m_script->loadMod(scriptpath, mod.name);
808 errorstream<<"Server: Failed to load and run "
809 <<scriptpath<<std::endl;
810 throw ModError("Failed to load and run "+scriptpath);
814 // Read Textures and calculate sha1 sums
817 // Apply item aliases in the node definition manager
818 m_nodedef->updateAliases(m_itemdef);
820 // Initialize Environment
821 ServerMap *servermap = new ServerMap(path_world, this, m_emerge);
822 m_env = new ServerEnvironment(servermap, m_script, this, m_emerge);
824 // Run some callbacks after the MG params have been set up but before activation
825 MapgenParams *mgparams = servermap->getMapgenParams();
826 m_script->environment_OnMapgenInit(mgparams);
828 // Initialize mapgens
829 m_emerge->initMapgens(mgparams);
831 // Give environment reference to scripting api
832 m_script->initializeEnvironment(m_env);
834 // Register us to receive map edit events
835 servermap->addEventReceiver(this);
837 // If file exists, load environment metadata
838 if(fs::PathExists(m_path_world+DIR_DELIM+"env_meta.txt"))
840 infostream<<"Server: Loading environment metadata"<<std::endl;
841 m_env->loadMeta(m_path_world);
845 infostream<<"Server: Loading players"<<std::endl;
846 m_env->deSerializePlayers(m_path_world);
849 Add some test ActiveBlockModifiers to environment
851 add_legacy_abms(m_env, m_nodedef);
853 m_liquid_transform_every = g_settings->getFloat("liquid_update");
858 infostream<<"Server destructing"<<std::endl;
861 Send shutdown message
864 JMutexAutoLock conlock(m_con_mutex);
866 std::wstring line = L"*** Server shutting down";
869 Send the message to clients
871 for(std::map<u16, RemoteClient*>::iterator
872 i = m_clients.begin();
873 i != m_clients.end(); ++i)
875 // Get client and check that it is valid
876 RemoteClient *client = i->second;
877 assert(client->peer_id == i->first);
878 if(client->serialization_version == SER_FMT_VER_INVALID)
882 SendChatMessage(client->peer_id, line);
884 catch(con::PeerNotFoundException &e)
890 JMutexAutoLock envlock(m_env_mutex);
891 JMutexAutoLock conlock(m_con_mutex);
894 Execute script shutdown hooks
896 m_script->on_shutdown();
900 JMutexAutoLock envlock(m_env_mutex);
905 infostream<<"Server: Saving players"<<std::endl;
906 m_env->serializePlayers(m_path_world);
909 Save environment metadata
911 infostream<<"Server: Saving environment metadata"<<std::endl;
912 m_env->saveMeta(m_path_world);
921 //shutdown all emerge threads first!
928 JMutexAutoLock clientslock(m_con_mutex);
930 for(std::map<u16, RemoteClient*>::iterator
931 i = m_clients.begin();
932 i != m_clients.end(); ++i)
940 // Delete things in the reverse order of creation
949 // Deinitialize scripting
950 infostream<<"Server: Deinitializing scripting"<<std::endl;
953 // Delete detached inventories
955 for(std::map<std::string, Inventory*>::iterator
956 i = m_detached_inventories.begin();
957 i != m_detached_inventories.end(); i++){
963 void Server::start(unsigned short port)
965 DSTACK(__FUNCTION_NAME);
966 infostream<<"Starting server on port "<<port<<"..."<<std::endl;
968 // Stop thread if already running
971 // Initialize connection
972 m_con.SetTimeoutMs(30);
976 m_thread->setRun(true);
979 // ASCII art for the win!
981 <<" .__ __ __ "<<std::endl
982 <<" _____ |__| ____ _____/ |_ ____ _______/ |_ "<<std::endl
983 <<" / \\| |/ \\_/ __ \\ __\\/ __ \\ / ___/\\ __\\"<<std::endl
984 <<"| Y Y \\ | | \\ ___/| | \\ ___/ \\___ \\ | | "<<std::endl
985 <<"|__|_| /__|___| /\\___ >__| \\___ >____ > |__| "<<std::endl
986 <<" \\/ \\/ \\/ \\/ \\/ "<<std::endl;
987 actionstream<<"World at ["<<m_path_world<<"]"<<std::endl;
988 actionstream<<"Server for gameid=\""<<m_gamespec.id
989 <<"\" listening on port "<<port<<"."<<std::endl;
994 DSTACK(__FUNCTION_NAME);
996 infostream<<"Server: Stopping and waiting threads"<<std::endl;
998 // Stop threads (set run=false first so both start stopping)
999 m_thread->setRun(false);
1000 //m_emergethread.setRun(false);
1002 //m_emergethread.stop();
1004 infostream<<"Server: Threads stopped"<<std::endl;
1007 void Server::step(float dtime)
1009 DSTACK(__FUNCTION_NAME);
1014 JMutexAutoLock lock(m_step_dtime_mutex);
1015 m_step_dtime += dtime;
1017 // Throw if fatal error occurred in thread
1018 std::string async_err = m_async_fatal_error.get();
1019 if(async_err != ""){
1020 throw ServerError(async_err);
1024 void Server::AsyncRunStep()
1026 DSTACK(__FUNCTION_NAME);
1028 g_profiler->add("Server::AsyncRunStep (num)", 1);
1032 JMutexAutoLock lock1(m_step_dtime_mutex);
1033 dtime = m_step_dtime;
1037 // Send blocks to clients
1044 g_profiler->add("Server::AsyncRunStep with dtime (num)", 1);
1046 //infostream<<"Server steps "<<dtime<<std::endl;
1047 //infostream<<"Server::AsyncRunStep(): dtime="<<dtime<<std::endl;
1050 JMutexAutoLock lock1(m_step_dtime_mutex);
1051 m_step_dtime -= dtime;
1058 m_uptime.set(m_uptime.get() + dtime);
1062 // Process connection's timeouts
1063 JMutexAutoLock lock2(m_con_mutex);
1064 ScopeProfiler sp(g_profiler, "Server: connection timeout processing");
1065 m_con.RunTimeouts(dtime);
1069 // This has to be called so that the client list gets synced
1070 // with the peer list of the connection
1071 handlePeerChanges();
1075 Update time of day and overall game time
1078 JMutexAutoLock envlock(m_env_mutex);
1080 m_env->setTimeOfDaySpeed(g_settings->getFloat("time_speed"));
1083 Send to clients at constant intervals
1086 m_time_of_day_send_timer -= dtime;
1087 if(m_time_of_day_send_timer < 0.0)
1089 m_time_of_day_send_timer = g_settings->getFloat("time_send_interval");
1091 //JMutexAutoLock envlock(m_env_mutex);
1092 JMutexAutoLock conlock(m_con_mutex);
1094 u16 time = m_env->getTimeOfDay();
1095 float time_speed = g_settings->getFloat("time_speed");
1097 for(std::map<u16, RemoteClient*>::iterator
1098 i = m_clients.begin();
1099 i != m_clients.end(); ++i)
1101 RemoteClient *client = i->second;
1102 SendTimeOfDay(client->peer_id, time, time_speed);
1108 JMutexAutoLock lock(m_env_mutex);
1109 // Figure out and report maximum lag to environment
1110 float max_lag = m_env->getMaxLagEstimate();
1111 max_lag *= 0.9998; // Decrease slowly (about half per 5 minutes)
1112 if(dtime > max_lag){
1113 if(dtime > 0.1 && dtime > max_lag * 2.0)
1114 infostream<<"Server: Maximum lag peaked to "<<dtime
1118 m_env->reportMaxLagEstimate(max_lag);
1120 ScopeProfiler sp(g_profiler, "SEnv step");
1121 ScopeProfiler sp2(g_profiler, "SEnv step avg", SPT_AVG);
1125 const float map_timer_and_unload_dtime = 2.92;
1126 if(m_map_timer_and_unload_interval.step(dtime, map_timer_and_unload_dtime))
1128 JMutexAutoLock lock(m_env_mutex);
1129 // Run Map's timers and unload unused data
1130 ScopeProfiler sp(g_profiler, "Server: map timer and unload");
1131 m_env->getMap().timerUpdate(map_timer_and_unload_dtime,
1132 g_settings->getFloat("server_unload_unused_data_timeout"));
1143 JMutexAutoLock lock(m_env_mutex);
1144 JMutexAutoLock lock2(m_con_mutex);
1146 ScopeProfiler sp(g_profiler, "Server: handle players");
1148 for(std::map<u16, RemoteClient*>::iterator
1149 i = m_clients.begin();
1150 i != m_clients.end(); ++i)
1152 RemoteClient *client = i->second;
1153 PlayerSAO *playersao = getPlayerSAO(client->peer_id);
1154 if(playersao == NULL)
1158 Handle player HPs (die if hp=0)
1160 if(playersao->m_hp_not_sent && g_settings->getBool("enable_damage"))
1162 if(playersao->getHP() == 0)
1163 DiePlayer(client->peer_id);
1165 SendPlayerHP(client->peer_id);
1169 Send player breath if changed
1171 if(playersao->m_breath_not_sent){
1172 SendPlayerBreath(client->peer_id);
1176 Send player inventories if necessary
1178 if(playersao->m_moved){
1179 SendMovePlayer(client->peer_id);
1180 playersao->m_moved = false;
1182 if(playersao->m_inventory_not_sent){
1183 UpdateCrafting(client->peer_id);
1184 SendInventory(client->peer_id);
1189 /* Transform liquids */
1190 m_liquid_transform_timer += dtime;
1191 if(m_liquid_transform_timer >= m_liquid_transform_every)
1193 m_liquid_transform_timer -= m_liquid_transform_every;
1195 JMutexAutoLock lock(m_env_mutex);
1197 ScopeProfiler sp(g_profiler, "Server: liquid transform");
1199 std::map<v3s16, MapBlock*> modified_blocks;
1200 m_env->getMap().transformLiquids(modified_blocks);
1205 core::map<v3s16, MapBlock*> lighting_modified_blocks;
1206 ServerMap &map = ((ServerMap&)m_env->getMap());
1207 map.updateLighting(modified_blocks, lighting_modified_blocks);
1209 // Add blocks modified by lighting to modified_blocks
1210 for(core::map<v3s16, MapBlock*>::Iterator
1211 i = lighting_modified_blocks.getIterator();
1212 i.atEnd() == false; i++)
1214 MapBlock *block = i.getNode()->getValue();
1215 modified_blocks.insert(block->getPos(), block);
1219 Set the modified blocks unsent for all the clients
1222 JMutexAutoLock lock2(m_con_mutex);
1224 for(std::map<u16, RemoteClient*>::iterator
1225 i = m_clients.begin();
1226 i != m_clients.end(); ++i)
1228 RemoteClient *client = i->second;
1230 if(modified_blocks.size() > 0)
1232 // Remove block from sent history
1233 client->SetBlocksNotSent(modified_blocks);
1238 // Periodically print some info
1240 float &counter = m_print_info_timer;
1246 JMutexAutoLock lock2(m_con_mutex);
1247 m_clients_number = 0;
1248 if(m_clients.size() != 0)
1249 infostream<<"Players:"<<std::endl;
1250 for(std::map<u16, RemoteClient*>::iterator
1251 i = m_clients.begin();
1252 i != m_clients.end(); ++i)
1254 //u16 peer_id = i.getNode()->getKey();
1255 RemoteClient *client = i->second;
1256 Player *player = m_env->getPlayer(client->peer_id);
1259 infostream<<"* "<<player->getName()<<"\t";
1260 client->PrintInfo(infostream);
1268 // send masterserver announce
1270 float &counter = m_masterserver_timer;
1271 if(!isSingleplayer() && (!counter || counter >= 300.0) && g_settings->getBool("server_announce") == true)
1273 ServerList::sendAnnounce(!counter ? "start" : "update", m_clients_number, m_uptime.get(), m_gamespec.id, m_mods);
1280 //if(g_settings->getBool("enable_experimental"))
1284 Check added and deleted active objects
1287 //infostream<<"Server: Checking added and deleted active objects"<<std::endl;
1288 JMutexAutoLock envlock(m_env_mutex);
1289 JMutexAutoLock conlock(m_con_mutex);
1291 ScopeProfiler sp(g_profiler, "Server: checking added and deleted objs");
1293 // Radius inside which objects are active
1294 s16 radius = g_settings->getS16("active_object_send_range_blocks");
1295 radius *= MAP_BLOCKSIZE;
1297 for(std::map<u16, RemoteClient*>::iterator
1298 i = m_clients.begin();
1299 i != m_clients.end(); ++i)
1301 RemoteClient *client = i->second;
1303 // If definitions and textures have not been sent, don't
1304 // send objects either
1305 if(!client->definitions_sent)
1308 Player *player = m_env->getPlayer(client->peer_id);
1311 // This can happen if the client timeouts somehow
1312 /*infostream<<"WARNING: "<<__FUNCTION_NAME<<": Client "
1314 <<" has no associated player"<<std::endl;*/
1317 v3s16 pos = floatToInt(player->getPosition(), BS);
1319 std::set<u16> removed_objects;
1320 std::set<u16> added_objects;
1321 m_env->getRemovedActiveObjects(pos, radius,
1322 client->m_known_objects, removed_objects);
1323 m_env->getAddedActiveObjects(pos, radius,
1324 client->m_known_objects, added_objects);
1326 // Ignore if nothing happened
1327 if(removed_objects.size() == 0 && added_objects.size() == 0)
1329 //infostream<<"active objects: none changed"<<std::endl;
1333 std::string data_buffer;
1337 // Handle removed objects
1338 writeU16((u8*)buf, removed_objects.size());
1339 data_buffer.append(buf, 2);
1340 for(std::set<u16>::iterator
1341 i = removed_objects.begin();
1342 i != removed_objects.end(); ++i)
1346 ServerActiveObject* obj = m_env->getActiveObject(id);
1348 // Add to data buffer for sending
1349 writeU16((u8*)buf, id);
1350 data_buffer.append(buf, 2);
1352 // Remove from known objects
1353 client->m_known_objects.erase(id);
1355 if(obj && obj->m_known_by_count > 0)
1356 obj->m_known_by_count--;
1359 // Handle added objects
1360 writeU16((u8*)buf, added_objects.size());
1361 data_buffer.append(buf, 2);
1362 for(std::set<u16>::iterator
1363 i = added_objects.begin();
1364 i != added_objects.end(); ++i)
1368 ServerActiveObject* obj = m_env->getActiveObject(id);
1371 u8 type = ACTIVEOBJECT_TYPE_INVALID;
1373 infostream<<"WARNING: "<<__FUNCTION_NAME
1374 <<": NULL object"<<std::endl;
1376 type = obj->getSendType();
1378 // Add to data buffer for sending
1379 writeU16((u8*)buf, id);
1380 data_buffer.append(buf, 2);
1381 writeU8((u8*)buf, type);
1382 data_buffer.append(buf, 1);
1385 data_buffer.append(serializeLongString(
1386 obj->getClientInitializationData(client->net_proto_version)));
1388 data_buffer.append(serializeLongString(""));
1390 // Add to known objects
1391 client->m_known_objects.insert(id);
1394 obj->m_known_by_count++;
1398 SharedBuffer<u8> reply(2 + data_buffer.size());
1399 writeU16(&reply[0], TOCLIENT_ACTIVE_OBJECT_REMOVE_ADD);
1400 memcpy((char*)&reply[2], data_buffer.c_str(),
1401 data_buffer.size());
1403 m_con.Send(client->peer_id, 0, reply, true);
1405 verbosestream<<"Server: Sent object remove/add: "
1406 <<removed_objects.size()<<" removed, "
1407 <<added_objects.size()<<" added, "
1408 <<"packet size is "<<reply.getSize()<<std::endl;
1413 Collect a list of all the objects known by the clients
1414 and report it back to the environment.
1417 core::map<u16, bool> all_known_objects;
1419 for(core::map<u16, RemoteClient*>::Iterator
1420 i = m_clients.getIterator();
1421 i.atEnd() == false; i++)
1423 RemoteClient *client = i.getNode()->getValue();
1424 // Go through all known objects of client
1425 for(core::map<u16, bool>::Iterator
1426 i = client->m_known_objects.getIterator();
1427 i.atEnd()==false; i++)
1429 u16 id = i.getNode()->getKey();
1430 all_known_objects[id] = true;
1434 m_env->setKnownActiveObjects(whatever);
1440 Send object messages
1443 JMutexAutoLock envlock(m_env_mutex);
1444 JMutexAutoLock conlock(m_con_mutex);
1446 ScopeProfiler sp(g_profiler, "Server: sending object messages");
1449 // Value = data sent by object
1450 std::map<u16, std::list<ActiveObjectMessage>* > buffered_messages;
1452 // Get active object messages from environment
1455 ActiveObjectMessage aom = m_env->getActiveObjectMessage();
1459 std::list<ActiveObjectMessage>* message_list = NULL;
1460 std::map<u16, std::list<ActiveObjectMessage>* >::iterator n;
1461 n = buffered_messages.find(aom.id);
1462 if(n == buffered_messages.end())
1464 message_list = new std::list<ActiveObjectMessage>;
1465 buffered_messages[aom.id] = message_list;
1469 message_list = n->second;
1471 message_list->push_back(aom);
1474 // Route data to every client
1475 for(std::map<u16, RemoteClient*>::iterator
1476 i = m_clients.begin();
1477 i != m_clients.end(); ++i)
1479 RemoteClient *client = i->second;
1480 std::string reliable_data;
1481 std::string unreliable_data;
1482 // Go through all objects in message buffer
1483 for(std::map<u16, std::list<ActiveObjectMessage>* >::iterator
1484 j = buffered_messages.begin();
1485 j != buffered_messages.end(); ++j)
1487 // If object is not known by client, skip it
1489 if(client->m_known_objects.find(id) == client->m_known_objects.end())
1491 // Get message list of object
1492 std::list<ActiveObjectMessage>* list = j->second;
1493 // Go through every message
1494 for(std::list<ActiveObjectMessage>::iterator
1495 k = list->begin(); k != list->end(); ++k)
1497 // Compose the full new data with header
1498 ActiveObjectMessage aom = *k;
1499 std::string new_data;
1502 writeU16((u8*)&buf[0], aom.id);
1503 new_data.append(buf, 2);
1505 new_data += serializeString(aom.datastring);
1506 // Add data to buffer
1508 reliable_data += new_data;
1510 unreliable_data += new_data;
1514 reliable_data and unreliable_data are now ready.
1517 if(reliable_data.size() > 0)
1519 SharedBuffer<u8> reply(2 + reliable_data.size());
1520 writeU16(&reply[0], TOCLIENT_ACTIVE_OBJECT_MESSAGES);
1521 memcpy((char*)&reply[2], reliable_data.c_str(),
1522 reliable_data.size());
1524 m_con.Send(client->peer_id, 0, reply, true);
1526 if(unreliable_data.size() > 0)
1528 SharedBuffer<u8> reply(2 + unreliable_data.size());
1529 writeU16(&reply[0], TOCLIENT_ACTIVE_OBJECT_MESSAGES);
1530 memcpy((char*)&reply[2], unreliable_data.c_str(),
1531 unreliable_data.size());
1532 // Send as unreliable
1533 m_con.Send(client->peer_id, 0, reply, false);
1536 /*if(reliable_data.size() > 0 || unreliable_data.size() > 0)
1538 infostream<<"Server: Size of object message data: "
1539 <<"reliable: "<<reliable_data.size()
1540 <<", unreliable: "<<unreliable_data.size()
1545 // Clear buffered_messages
1546 for(std::map<u16, std::list<ActiveObjectMessage>* >::iterator
1547 i = buffered_messages.begin();
1548 i != buffered_messages.end(); ++i)
1554 } // enable_experimental
1557 Send queued-for-sending map edit events.
1560 // We will be accessing the environment and the connection
1561 JMutexAutoLock lock(m_env_mutex);
1562 JMutexAutoLock conlock(m_con_mutex);
1564 // Don't send too many at a time
1567 // Single change sending is disabled if queue size is not small
1568 bool disable_single_change_sending = false;
1569 if(m_unsent_map_edit_queue.size() >= 4)
1570 disable_single_change_sending = true;
1572 int event_count = m_unsent_map_edit_queue.size();
1574 // We'll log the amount of each
1577 while(m_unsent_map_edit_queue.size() != 0)
1579 MapEditEvent* event = m_unsent_map_edit_queue.pop_front();
1581 // Players far away from the change are stored here.
1582 // Instead of sending the changes, MapBlocks are set not sent
1584 std::list<u16> far_players;
1586 if(event->type == MEET_ADDNODE)
1588 //infostream<<"Server: MEET_ADDNODE"<<std::endl;
1589 prof.add("MEET_ADDNODE", 1);
1590 if(disable_single_change_sending)
1591 sendAddNode(event->p, event->n, event->already_known_by_peer,
1594 sendAddNode(event->p, event->n, event->already_known_by_peer,
1597 else if(event->type == MEET_REMOVENODE)
1599 //infostream<<"Server: MEET_REMOVENODE"<<std::endl;
1600 prof.add("MEET_REMOVENODE", 1);
1601 if(disable_single_change_sending)
1602 sendRemoveNode(event->p, event->already_known_by_peer,
1605 sendRemoveNode(event->p, event->already_known_by_peer,
1608 else if(event->type == MEET_BLOCK_NODE_METADATA_CHANGED)
1610 infostream<<"Server: MEET_BLOCK_NODE_METADATA_CHANGED"<<std::endl;
1611 prof.add("MEET_BLOCK_NODE_METADATA_CHANGED", 1);
1612 setBlockNotSent(event->p);
1614 else if(event->type == MEET_OTHER)
1616 infostream<<"Server: MEET_OTHER"<<std::endl;
1617 prof.add("MEET_OTHER", 1);
1618 for(std::set<v3s16>::iterator
1619 i = event->modified_blocks.begin();
1620 i != event->modified_blocks.end(); ++i)
1622 setBlockNotSent(*i);
1627 prof.add("unknown", 1);
1628 infostream<<"WARNING: Server: Unknown MapEditEvent "
1629 <<((u32)event->type)<<std::endl;
1633 Set blocks not sent to far players
1635 if(far_players.size() > 0)
1637 // Convert list format to that wanted by SetBlocksNotSent
1638 std::map<v3s16, MapBlock*> modified_blocks2;
1639 for(std::set<v3s16>::iterator
1640 i = event->modified_blocks.begin();
1641 i != event->modified_blocks.end(); ++i)
1643 modified_blocks2[*i] =
1644 m_env->getMap().getBlockNoCreateNoEx(*i);
1646 // Set blocks not sent
1647 for(std::list<u16>::iterator
1648 i = far_players.begin();
1649 i != far_players.end(); ++i)
1652 RemoteClient *client = getClient(peer_id);
1655 client->SetBlocksNotSent(modified_blocks2);
1661 /*// Don't send too many at a time
1663 if(count >= 1 && m_unsent_map_edit_queue.size() < 100)
1667 if(event_count >= 5){
1668 infostream<<"Server: MapEditEvents:"<<std::endl;
1669 prof.print(infostream);
1670 } else if(event_count != 0){
1671 verbosestream<<"Server: MapEditEvents:"<<std::endl;
1672 prof.print(verbosestream);
1678 Trigger emergethread (it somehow gets to a non-triggered but
1679 bysy state sometimes)
1682 float &counter = m_emergethread_trigger_timer;
1688 m_emerge->triggerAllThreads();
1690 // Update m_enable_rollback_recording here too
1691 m_enable_rollback_recording =
1692 g_settings->getBool("enable_rollback_recording");
1696 // Save map, players and auth stuff
1698 float &counter = m_savemap_timer;
1700 if(counter >= g_settings->getFloat("server_map_save_interval"))
1703 JMutexAutoLock lock(m_env_mutex);
1705 ScopeProfiler sp(g_profiler, "Server: saving stuff");
1708 if(m_banmanager->isModified())
1709 m_banmanager->save();
1711 // Save changed parts of map
1712 m_env->getMap().save(MOD_STATE_WRITE_NEEDED);
1715 m_env->serializePlayers(m_path_world);
1717 // Save environment metadata
1718 m_env->saveMeta(m_path_world);
1723 void Server::Receive()
1725 DSTACK(__FUNCTION_NAME);
1726 SharedBuffer<u8> data;
1731 JMutexAutoLock conlock(m_con_mutex);
1732 datasize = m_con.Receive(peer_id, data);
1735 // This has to be called so that the client list gets synced
1736 // with the peer list of the connection
1737 handlePeerChanges();
1739 ProcessData(*data, datasize, peer_id);
1741 catch(con::InvalidIncomingDataException &e)
1743 infostream<<"Server::Receive(): "
1744 "InvalidIncomingDataException: what()="
1745 <<e.what()<<std::endl;
1747 catch(con::PeerNotFoundException &e)
1749 //NOTE: This is not needed anymore
1751 // The peer has been disconnected.
1752 // Find the associated player and remove it.
1754 /*JMutexAutoLock envlock(m_env_mutex);
1756 infostream<<"ServerThread: peer_id="<<peer_id
1757 <<" has apparently closed connection. "
1758 <<"Removing player."<<std::endl;
1760 m_env->removePlayer(peer_id);*/
1764 void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
1766 DSTACK(__FUNCTION_NAME);
1767 // Environment is locked first.
1768 JMutexAutoLock envlock(m_env_mutex);
1769 JMutexAutoLock conlock(m_con_mutex);
1771 ScopeProfiler sp(g_profiler, "Server::ProcessData");
1775 Address address = m_con.GetPeerAddress(peer_id);
1776 addr_s = address.serializeString();
1778 // drop player if is ip is banned
1779 if(m_banmanager->isIpBanned(addr_s)){
1780 std::string ban_name = m_banmanager->getBanName(addr_s);
1781 infostream<<"Server: A banned client tried to connect from "
1782 <<addr_s<<"; banned name was "
1783 <<ban_name<<std::endl;
1784 // This actually doesn't seem to transfer to the client
1785 DenyAccess(peer_id, L"Your ip is banned. Banned name was "
1786 +narrow_to_wide(ban_name));
1787 m_con.DeletePeer(peer_id);
1791 catch(con::PeerNotFoundException &e)
1793 infostream<<"Server::ProcessData(): Cancelling: peer "
1794 <<peer_id<<" not found"<<std::endl;
1798 u8 peer_ser_ver = getClient(peer_id)->serialization_version;
1806 ToServerCommand command = (ToServerCommand)readU16(&data[0]);
1808 if(command == TOSERVER_INIT)
1810 // [0] u16 TOSERVER_INIT
1811 // [2] u8 SER_FMT_VER_HIGHEST_READ
1812 // [3] u8[20] player_name
1813 // [23] u8[28] password <--- can be sent without this, from old versions
1815 if(datasize < 2+1+PLAYERNAME_SIZE)
1818 // If net_proto_version is set, this client has already been handled
1819 if(getClient(peer_id)->net_proto_version != 0){
1820 verbosestream<<"Server: Ignoring multiple TOSERVER_INITs from "
1821 <<addr_s<<" (peer_id="<<peer_id<<")"<<std::endl;
1825 verbosestream<<"Server: Got TOSERVER_INIT from "<<addr_s<<" (peer_id="
1826 <<peer_id<<")"<<std::endl;
1828 // Do not allow multiple players in simple singleplayer mode.
1829 // This isn't a perfect way to do it, but will suffice for now.
1830 if(m_simple_singleplayer_mode && m_clients.size() > 1){
1831 infostream<<"Server: Not allowing another client ("<<addr_s
1832 <<") to connect in simple singleplayer mode"<<std::endl;
1833 DenyAccess(peer_id, L"Running in simple singleplayer mode.");
1837 // First byte after command is maximum supported
1838 // serialization version
1839 u8 client_max = data[2];
1840 u8 our_max = SER_FMT_VER_HIGHEST_READ;
1841 // Use the highest version supported by both
1842 u8 deployed = std::min(client_max, our_max);
1843 // If it's lower than the lowest supported, give up.
1844 if(deployed < SER_FMT_VER_LOWEST)
1845 deployed = SER_FMT_VER_INVALID;
1847 //peer->serialization_version = deployed;
1848 getClient(peer_id)->pending_serialization_version = deployed;
1850 if(deployed == SER_FMT_VER_INVALID)
1852 actionstream<<"Server: A mismatched client tried to connect from "
1853 <<addr_s<<std::endl;
1854 infostream<<"Server: Cannot negotiate serialization version with "
1855 <<addr_s<<std::endl;
1856 DenyAccess(peer_id, std::wstring(
1857 L"Your client's version is not supported.\n"
1858 L"Server version is ")
1859 + narrow_to_wide(minetest_version_simple) + L"."
1865 Read and check network protocol version
1868 u16 min_net_proto_version = 0;
1869 if(datasize >= 2+1+PLAYERNAME_SIZE+PASSWORD_SIZE+2)
1870 min_net_proto_version = readU16(&data[2+1+PLAYERNAME_SIZE+PASSWORD_SIZE]);
1872 // Use same version as minimum and maximum if maximum version field
1873 // doesn't exist (backwards compatibility)
1874 u16 max_net_proto_version = min_net_proto_version;
1875 if(datasize >= 2+1+PLAYERNAME_SIZE+PASSWORD_SIZE+2+2)
1876 max_net_proto_version = readU16(&data[2+1+PLAYERNAME_SIZE+PASSWORD_SIZE+2]);
1878 // Start with client's maximum version
1879 u16 net_proto_version = max_net_proto_version;
1881 // Figure out a working version if it is possible at all
1882 if(max_net_proto_version >= SERVER_PROTOCOL_VERSION_MIN ||
1883 min_net_proto_version <= SERVER_PROTOCOL_VERSION_MAX)
1885 // If maximum is larger than our maximum, go with our maximum
1886 if(max_net_proto_version > SERVER_PROTOCOL_VERSION_MAX)
1887 net_proto_version = SERVER_PROTOCOL_VERSION_MAX;
1888 // Else go with client's maximum
1890 net_proto_version = max_net_proto_version;
1893 verbosestream<<"Server: "<<addr_s<<": Protocol version: min: "
1894 <<min_net_proto_version<<", max: "<<max_net_proto_version
1895 <<", chosen: "<<net_proto_version<<std::endl;
1897 getClient(peer_id)->net_proto_version = net_proto_version;
1899 if(net_proto_version < SERVER_PROTOCOL_VERSION_MIN ||
1900 net_proto_version > SERVER_PROTOCOL_VERSION_MAX)
1902 actionstream<<"Server: A mismatched client tried to connect from "
1903 <<addr_s<<std::endl;
1904 DenyAccess(peer_id, std::wstring(
1905 L"Your client's version is not supported.\n"
1906 L"Server version is ")
1907 + narrow_to_wide(minetest_version_simple) + L",\n"
1908 + L"server's PROTOCOL_VERSION is "
1909 + narrow_to_wide(itos(SERVER_PROTOCOL_VERSION_MIN))
1911 + narrow_to_wide(itos(SERVER_PROTOCOL_VERSION_MAX))
1912 + L", client's PROTOCOL_VERSION is "
1913 + narrow_to_wide(itos(min_net_proto_version))
1915 + narrow_to_wide(itos(max_net_proto_version))
1920 if(g_settings->getBool("strict_protocol_version_checking"))
1922 if(net_proto_version != LATEST_PROTOCOL_VERSION)
1924 actionstream<<"Server: A mismatched (strict) client tried to "
1925 <<"connect from "<<addr_s<<std::endl;
1926 DenyAccess(peer_id, std::wstring(
1927 L"Your client's version is not supported.\n"
1928 L"Server version is ")
1929 + narrow_to_wide(minetest_version_simple) + L",\n"
1930 + L"server's PROTOCOL_VERSION (strict) is "
1931 + narrow_to_wide(itos(LATEST_PROTOCOL_VERSION))
1932 + L", client's PROTOCOL_VERSION is "
1933 + narrow_to_wide(itos(min_net_proto_version))
1935 + narrow_to_wide(itos(max_net_proto_version))
1946 char playername[PLAYERNAME_SIZE];
1947 for(u32 i=0; i<PLAYERNAME_SIZE-1; i++)
1949 playername[i] = data[3+i];
1951 playername[PLAYERNAME_SIZE-1] = 0;
1953 if(playername[0]=='\0')
1955 actionstream<<"Server: Player with an empty name "
1956 <<"tried to connect from "<<addr_s<<std::endl;
1957 DenyAccess(peer_id, L"Empty name");
1961 if(string_allowed(playername, PLAYERNAME_ALLOWED_CHARS)==false)
1963 actionstream<<"Server: Player with an invalid name "
1964 <<"tried to connect from "<<addr_s<<std::endl;
1965 DenyAccess(peer_id, L"Name contains unallowed characters");
1969 if(!isSingleplayer() && strcasecmp(playername, "singleplayer") == 0)
1971 actionstream<<"Server: Player with the name \"singleplayer\" "
1972 <<"tried to connect from "<<addr_s<<std::endl;
1973 DenyAccess(peer_id, L"Name is not allowed");
1977 infostream<<"Server: New connection: \""<<playername<<"\" from "
1978 <<addr_s<<" (peer_id="<<peer_id<<")"<<std::endl;
1981 char given_password[PASSWORD_SIZE];
1982 if(datasize < 2+1+PLAYERNAME_SIZE+PASSWORD_SIZE)
1984 // old version - assume blank password
1985 given_password[0] = 0;
1989 for(u32 i=0; i<PASSWORD_SIZE-1; i++)
1991 given_password[i] = data[23+i];
1993 given_password[PASSWORD_SIZE-1] = 0;
1996 if(!base64_is_valid(given_password)){
1997 actionstream<<"Server: "<<playername
1998 <<" supplied invalid password hash"<<std::endl;
1999 DenyAccess(peer_id, L"Invalid password hash");
2003 // Enforce user limit.
2004 // Don't enforce for users that have some admin right
2005 if(m_clients.size() >= g_settings->getU16("max_users") &&
2006 !checkPriv(playername, "server") &&
2007 !checkPriv(playername, "ban") &&
2008 !checkPriv(playername, "privs") &&
2009 !checkPriv(playername, "password") &&
2010 playername != g_settings->get("name"))
2012 actionstream<<"Server: "<<playername<<" tried to join, but there"
2013 <<" are already max_users="
2014 <<g_settings->getU16("max_users")<<" players."<<std::endl;
2015 DenyAccess(peer_id, L"Too many users.");
2019 std::string checkpwd; // Password hash to check against
2020 bool has_auth = m_script->getAuth(playername, &checkpwd, NULL);
2022 // If no authentication info exists for user, create it
2024 if(!isSingleplayer() &&
2025 g_settings->getBool("disallow_empty_password") &&
2026 std::string(given_password) == ""){
2027 actionstream<<"Server: "<<playername
2028 <<" supplied empty password"<<std::endl;
2029 DenyAccess(peer_id, L"Empty passwords are "
2030 L"disallowed. Set a password and try again.");
2033 std::wstring raw_default_password =
2034 narrow_to_wide(g_settings->get("default_password"));
2035 std::string initial_password =
2036 translatePassword(playername, raw_default_password);
2038 // If default_password is empty, allow any initial password
2039 if (raw_default_password.length() == 0)
2040 initial_password = given_password;
2042 m_script->createAuth(playername, initial_password);
2045 has_auth = m_script->getAuth(playername, &checkpwd, NULL);
2048 actionstream<<"Server: "<<playername<<" cannot be authenticated"
2049 <<" (auth handler does not work?)"<<std::endl;
2050 DenyAccess(peer_id, L"Not allowed to login");
2054 if(given_password != checkpwd){
2055 actionstream<<"Server: "<<playername<<" supplied wrong password"
2057 DenyAccess(peer_id, L"Wrong password");
2062 PlayerSAO *playersao = emergePlayer(playername, peer_id);
2064 // If failed, cancel
2065 if(playersao == NULL)
2067 RemotePlayer *player =
2068 static_cast<RemotePlayer*>(m_env->getPlayer(playername));
2069 if(player && player->peer_id != 0){
2070 errorstream<<"Server: "<<playername<<": Failed to emerge player"
2071 <<" (player allocated to an another client)"<<std::endl;
2072 DenyAccess(peer_id, L"Another client is connected with this "
2073 L"name. If your client closed unexpectedly, try again in "
2076 errorstream<<"Server: "<<playername<<": Failed to emerge player"
2078 DenyAccess(peer_id, L"Could not allocate player.");
2084 Answer with a TOCLIENT_INIT
2087 SharedBuffer<u8> reply(2+1+6+8+4);
2088 writeU16(&reply[0], TOCLIENT_INIT);
2089 writeU8(&reply[2], deployed);
2090 writeV3S16(&reply[2+1], floatToInt(playersao->getPlayer()->getPosition()+v3f(0,BS/2,0), BS));
2091 writeU64(&reply[2+1+6], m_env->getServerMap().getSeed());
2092 writeF1000(&reply[2+1+6+8], g_settings->getFloat("dedicated_server_step"));
2095 m_con.Send(peer_id, 0, reply, true);
2099 Send complete position information
2101 SendMovePlayer(peer_id);
2106 if(command == TOSERVER_INIT2)
2108 verbosestream<<"Server: Got TOSERVER_INIT2 from "
2109 <<peer_id<<std::endl;
2111 Player *player = m_env->getPlayer(peer_id);
2113 verbosestream<<"Server: TOSERVER_INIT2: "
2114 <<"Player not found; ignoring."<<std::endl;
2118 RemoteClient *client = getClient(peer_id);
2119 client->serialization_version =
2120 getClient(peer_id)->pending_serialization_version;
2123 Send some initialization data
2126 infostream<<"Server: Sending content to "
2127 <<getPlayerName(peer_id)<<std::endl;
2129 // Send player movement settings
2130 SendMovement(m_con, peer_id);
2132 // Send item definitions
2133 SendItemDef(m_con, peer_id, m_itemdef, client->net_proto_version);
2135 // Send node definitions
2136 SendNodeDef(m_con, peer_id, m_nodedef, client->net_proto_version);
2138 // Send media announcement
2139 sendMediaAnnouncement(peer_id);
2142 SendPlayerPrivileges(peer_id);
2144 // Send inventory formspec
2145 SendPlayerInventoryFormspec(peer_id);
2148 UpdateCrafting(peer_id);
2149 SendInventory(peer_id);
2152 if(g_settings->getBool("enable_damage"))
2153 SendPlayerHP(peer_id);
2156 SendPlayerBreath(peer_id);
2158 // Send detached inventories
2159 sendDetachedInventories(peer_id);
2161 // Show death screen if necessary
2163 SendDeathscreen(m_con, peer_id, false, v3f(0,0,0));
2167 u16 time = m_env->getTimeOfDay();
2168 float time_speed = g_settings->getFloat("time_speed");
2169 SendTimeOfDay(peer_id, time, time_speed);
2172 // Note things in chat if not in simple singleplayer mode
2173 if(!m_simple_singleplayer_mode)
2175 // Send information about server to player in chat
2176 SendChatMessage(peer_id, getStatusString());
2178 // Send information about joining in chat
2180 std::wstring name = L"unknown";
2181 Player *player = m_env->getPlayer(peer_id);
2183 name = narrow_to_wide(player->getName());
2185 std::wstring message;
2188 message += L" joined the game.";
2189 BroadcastChatMessage(message);
2193 // Warnings about protocol version can be issued here
2194 if(getClient(peer_id)->net_proto_version < LATEST_PROTOCOL_VERSION)
2196 SendChatMessage(peer_id, L"# Server: WARNING: YOUR CLIENT'S "
2197 L"VERSION MAY NOT BE FULLY COMPATIBLE WITH THIS SERVER!");
2204 std::ostringstream os(std::ios_base::binary);
2205 for(std::map<u16, RemoteClient*>::iterator
2206 i = m_clients.begin();
2207 i != m_clients.end(); ++i)
2209 RemoteClient *client = i->second;
2210 assert(client->peer_id == i->first);
2211 if(client->serialization_version == SER_FMT_VER_INVALID)
2214 Player *player = m_env->getPlayer(client->peer_id);
2217 // Get name of player
2218 os<<player->getName()<<" ";
2221 actionstream<<player->getName()<<" ["<<addr_s<<"] "<<"joins game. List of players: "
2222 <<os.str()<<std::endl;
2228 if(peer_ser_ver == SER_FMT_VER_INVALID)
2230 infostream<<"Server::ProcessData(): Cancelling: Peer"
2231 " serialization format invalid or not initialized."
2232 " Skipping incoming command="<<command<<std::endl;
2236 Player *player = m_env->getPlayer(peer_id);
2238 infostream<<"Server::ProcessData(): Cancelling: "
2239 "No player for peer_id="<<peer_id
2244 PlayerSAO *playersao = player->getPlayerSAO();
2245 if(playersao == NULL){
2246 infostream<<"Server::ProcessData(): Cancelling: "
2247 "No player object for peer_id="<<peer_id
2252 if(command == TOSERVER_PLAYERPOS)
2254 if(datasize < 2+12+12+4+4)
2258 v3s32 ps = readV3S32(&data[start+2]);
2259 v3s32 ss = readV3S32(&data[start+2+12]);
2260 f32 pitch = (f32)readS32(&data[2+12+12]) / 100.0;
2261 f32 yaw = (f32)readS32(&data[2+12+12+4]) / 100.0;
2263 if(datasize >= 2+12+12+4+4+4)
2264 keyPressed = (u32)readU32(&data[2+12+12+4+4]);
2265 v3f position((f32)ps.X/100., (f32)ps.Y/100., (f32)ps.Z/100.);
2266 v3f speed((f32)ss.X/100., (f32)ss.Y/100., (f32)ss.Z/100.);
2267 pitch = wrapDegrees(pitch);
2268 yaw = wrapDegrees(yaw);
2270 player->setPosition(position);
2271 player->setSpeed(speed);
2272 player->setPitch(pitch);
2273 player->setYaw(yaw);
2274 player->keyPressed=keyPressed;
2275 player->control.up = (bool)(keyPressed&1);
2276 player->control.down = (bool)(keyPressed&2);
2277 player->control.left = (bool)(keyPressed&4);
2278 player->control.right = (bool)(keyPressed&8);
2279 player->control.jump = (bool)(keyPressed&16);
2280 player->control.aux1 = (bool)(keyPressed&32);
2281 player->control.sneak = (bool)(keyPressed&64);
2282 player->control.LMB = (bool)(keyPressed&128);
2283 player->control.RMB = (bool)(keyPressed&256);
2285 bool cheated = playersao->checkMovementCheat();
2288 m_script->on_cheat(playersao, "moved_too_fast");
2291 /*infostream<<"Server::ProcessData(): Moved player "<<peer_id<<" to "
2292 <<"("<<position.X<<","<<position.Y<<","<<position.Z<<")"
2293 <<" pitch="<<pitch<<" yaw="<<yaw<<std::endl;*/
2295 else if(command == TOSERVER_GOTBLOCKS)
2308 u16 count = data[2];
2309 for(u16 i=0; i<count; i++)
2311 if((s16)datasize < 2+1+(i+1)*6)
2312 throw con::InvalidIncomingDataException
2313 ("GOTBLOCKS length is too short");
2314 v3s16 p = readV3S16(&data[2+1+i*6]);
2315 /*infostream<<"Server: GOTBLOCKS ("
2316 <<p.X<<","<<p.Y<<","<<p.Z<<")"<<std::endl;*/
2317 RemoteClient *client = getClient(peer_id);
2318 client->GotBlock(p);
2321 else if(command == TOSERVER_DELETEDBLOCKS)
2334 u16 count = data[2];
2335 for(u16 i=0; i<count; i++)
2337 if((s16)datasize < 2+1+(i+1)*6)
2338 throw con::InvalidIncomingDataException
2339 ("DELETEDBLOCKS length is too short");
2340 v3s16 p = readV3S16(&data[2+1+i*6]);
2341 /*infostream<<"Server: DELETEDBLOCKS ("
2342 <<p.X<<","<<p.Y<<","<<p.Z<<")"<<std::endl;*/
2343 RemoteClient *client = getClient(peer_id);
2344 client->SetBlockNotSent(p);
2347 else if(command == TOSERVER_CLICK_OBJECT)
2349 infostream<<"Server: CLICK_OBJECT not supported anymore"<<std::endl;
2352 else if(command == TOSERVER_CLICK_ACTIVEOBJECT)
2354 infostream<<"Server: CLICK_ACTIVEOBJECT not supported anymore"<<std::endl;
2357 else if(command == TOSERVER_GROUND_ACTION)
2359 infostream<<"Server: GROUND_ACTION not supported anymore"<<std::endl;
2363 else if(command == TOSERVER_RELEASE)
2365 infostream<<"Server: RELEASE not supported anymore"<<std::endl;
2368 else if(command == TOSERVER_SIGNTEXT)
2370 infostream<<"Server: SIGNTEXT not supported anymore"
2374 else if(command == TOSERVER_SIGNNODETEXT)
2376 infostream<<"Server: SIGNNODETEXT not supported anymore"
2380 else if(command == TOSERVER_INVENTORY_ACTION)
2382 // Strip command and create a stream
2383 std::string datastring((char*)&data[2], datasize-2);
2384 verbosestream<<"TOSERVER_INVENTORY_ACTION: data="<<datastring<<std::endl;
2385 std::istringstream is(datastring, std::ios_base::binary);
2387 InventoryAction *a = InventoryAction::deSerialize(is);
2390 infostream<<"TOSERVER_INVENTORY_ACTION: "
2391 <<"InventoryAction::deSerialize() returned NULL"
2396 // If something goes wrong, this player is to blame
2397 RollbackScopeActor rollback_scope(m_rollback,
2398 std::string("player:")+player->getName());
2401 Note: Always set inventory not sent, to repair cases
2402 where the client made a bad prediction.
2406 Handle restrictions and special cases of the move action
2408 if(a->getType() == IACTION_MOVE)
2410 IMoveAction *ma = (IMoveAction*)a;
2412 ma->from_inv.applyCurrentPlayer(player->getName());
2413 ma->to_inv.applyCurrentPlayer(player->getName());
2415 setInventoryModified(ma->from_inv);
2416 setInventoryModified(ma->to_inv);
2418 bool from_inv_is_current_player =
2419 (ma->from_inv.type == InventoryLocation::PLAYER) &&
2420 (ma->from_inv.name == player->getName());
2422 bool to_inv_is_current_player =
2423 (ma->to_inv.type == InventoryLocation::PLAYER) &&
2424 (ma->to_inv.name == player->getName());
2427 Disable moving items out of craftpreview
2429 if(ma->from_list == "craftpreview")
2431 infostream<<"Ignoring IMoveAction from "
2432 <<(ma->from_inv.dump())<<":"<<ma->from_list
2433 <<" to "<<(ma->to_inv.dump())<<":"<<ma->to_list
2434 <<" because src is "<<ma->from_list<<std::endl;
2440 Disable moving items into craftresult and craftpreview
2442 if(ma->to_list == "craftpreview" || ma->to_list == "craftresult")
2444 infostream<<"Ignoring IMoveAction from "
2445 <<(ma->from_inv.dump())<<":"<<ma->from_list
2446 <<" to "<<(ma->to_inv.dump())<<":"<<ma->to_list
2447 <<" because dst is "<<ma->to_list<<std::endl;
2452 // Disallow moving items in elsewhere than player's inventory
2453 // if not allowed to interact
2454 if(!checkPriv(player->getName(), "interact") &&
2455 (!from_inv_is_current_player ||
2456 !to_inv_is_current_player))
2458 infostream<<"Cannot move outside of player's inventory: "
2459 <<"No interact privilege"<<std::endl;
2465 Handle restrictions and special cases of the drop action
2467 else if(a->getType() == IACTION_DROP)
2469 IDropAction *da = (IDropAction*)a;
2471 da->from_inv.applyCurrentPlayer(player->getName());
2473 setInventoryModified(da->from_inv);
2476 Disable dropping items out of craftpreview
2478 if(da->from_list == "craftpreview")
2480 infostream<<"Ignoring IDropAction from "
2481 <<(da->from_inv.dump())<<":"<<da->from_list
2482 <<" because src is "<<da->from_list<<std::endl;
2487 // Disallow dropping items if not allowed to interact
2488 if(!checkPriv(player->getName(), "interact"))
2495 Handle restrictions and special cases of the craft action
2497 else if(a->getType() == IACTION_CRAFT)
2499 ICraftAction *ca = (ICraftAction*)a;
2501 ca->craft_inv.applyCurrentPlayer(player->getName());
2503 setInventoryModified(ca->craft_inv);
2505 //bool craft_inv_is_current_player =
2506 // (ca->craft_inv.type == InventoryLocation::PLAYER) &&
2507 // (ca->craft_inv.name == player->getName());
2509 // Disallow crafting if not allowed to interact
2510 if(!checkPriv(player->getName(), "interact"))
2512 infostream<<"Cannot craft: "
2513 <<"No interact privilege"<<std::endl;
2520 a->apply(this, playersao, this);
2524 else if(command == TOSERVER_CHAT_MESSAGE)
2532 std::string datastring((char*)&data[2], datasize-2);
2533 std::istringstream is(datastring, std::ios_base::binary);
2536 is.read((char*)buf, 2);
2537 u16 len = readU16(buf);
2539 std::wstring message;
2540 for(u16 i=0; i<len; i++)
2542 is.read((char*)buf, 2);
2543 message += (wchar_t)readU16(buf);
2546 // If something goes wrong, this player is to blame
2547 RollbackScopeActor rollback_scope(m_rollback,
2548 std::string("player:")+player->getName());
2550 // Get player name of this client
2551 std::wstring name = narrow_to_wide(player->getName());
2554 bool ate = m_script->on_chat_message(player->getName(),
2555 wide_to_narrow(message));
2556 // If script ate the message, don't proceed
2560 // Line to send to players
2562 // Whether to send to the player that sent the line
2563 bool send_to_sender = false;
2564 // Whether to send to other players
2565 bool send_to_others = false;
2567 // Commands are implemented in Lua, so only catch invalid
2568 // commands that were not "eaten" and send an error back
2569 if(message[0] == L'/')
2571 message = message.substr(1);
2572 send_to_sender = true;
2573 if(message.length() == 0)
2574 line += L"-!- Empty command";
2576 line += L"-!- Invalid command: " + str_split(message, L' ')[0];
2580 if(checkPriv(player->getName(), "shout")){
2585 send_to_others = true;
2587 line += L"-!- You don't have permission to shout.";
2588 send_to_sender = true;
2595 actionstream<<"CHAT: "<<wide_to_narrow(line)<<std::endl;
2598 Send the message to clients
2600 for(std::map<u16, RemoteClient*>::iterator
2601 i = m_clients.begin();
2602 i != m_clients.end(); ++i)
2604 // Get client and check that it is valid
2605 RemoteClient *client = i->second;
2606 assert(client->peer_id == i->first);
2607 if(client->serialization_version == SER_FMT_VER_INVALID)
2611 bool sender_selected = (peer_id == client->peer_id);
2612 if(sender_selected == true && send_to_sender == false)
2614 if(sender_selected == false && send_to_others == false)
2617 SendChatMessage(client->peer_id, line);
2621 else if(command == TOSERVER_DAMAGE)
2623 std::string datastring((char*)&data[2], datasize-2);
2624 std::istringstream is(datastring, std::ios_base::binary);
2625 u8 damage = readU8(is);
2627 if(g_settings->getBool("enable_damage"))
2629 actionstream<<player->getName()<<" damaged by "
2630 <<(int)damage<<" hp at "<<PP(player->getPosition()/BS)
2633 playersao->setHP(playersao->getHP() - damage);
2635 if(playersao->getHP() == 0 && playersao->m_hp_not_sent)
2638 if(playersao->m_hp_not_sent)
2639 SendPlayerHP(peer_id);
2642 else if(command == TOSERVER_BREATH)
2644 std::string datastring((char*)&data[2], datasize-2);
2645 std::istringstream is(datastring, std::ios_base::binary);
2646 u16 breath = readU16(is);
2647 playersao->setBreath(breath);
2649 else if(command == TOSERVER_PASSWORD)
2652 [0] u16 TOSERVER_PASSWORD
2653 [2] u8[28] old password
2654 [30] u8[28] new password
2657 if(datasize != 2+PASSWORD_SIZE*2)
2659 /*char password[PASSWORD_SIZE];
2660 for(u32 i=0; i<PASSWORD_SIZE-1; i++)
2661 password[i] = data[2+i];
2662 password[PASSWORD_SIZE-1] = 0;*/
2664 for(u32 i=0; i<PASSWORD_SIZE-1; i++)
2672 for(u32 i=0; i<PASSWORD_SIZE-1; i++)
2674 char c = data[2+PASSWORD_SIZE+i];
2680 if(!base64_is_valid(newpwd)){
2681 infostream<<"Server: "<<player->getName()<<" supplied invalid password hash"<<std::endl;
2682 // Wrong old password supplied!!
2683 SendChatMessage(peer_id, L"Invalid new password hash supplied. Password NOT changed.");
2687 infostream<<"Server: Client requests a password change from "
2688 <<"'"<<oldpwd<<"' to '"<<newpwd<<"'"<<std::endl;
2690 std::string playername = player->getName();
2692 std::string checkpwd;
2693 m_script->getAuth(playername, &checkpwd, NULL);
2695 if(oldpwd != checkpwd)
2697 infostream<<"Server: invalid old password"<<std::endl;
2698 // Wrong old password supplied!!
2699 SendChatMessage(peer_id, L"Invalid old password supplied. Password NOT changed.");
2703 bool success = m_script->setPassword(playername, newpwd);
2705 actionstream<<player->getName()<<" changes password"<<std::endl;
2706 SendChatMessage(peer_id, L"Password change successful.");
2708 actionstream<<player->getName()<<" tries to change password but "
2709 <<"it fails"<<std::endl;
2710 SendChatMessage(peer_id, L"Password change failed or inavailable.");
2713 else if(command == TOSERVER_PLAYERITEM)
2718 u16 item = readU16(&data[2]);
2719 playersao->setWieldIndex(item);
2721 else if(command == TOSERVER_RESPAWN)
2723 if(player->hp != 0 || !g_settings->getBool("enable_damage"))
2726 RespawnPlayer(peer_id);
2728 actionstream<<player->getName()<<" respawns at "
2729 <<PP(player->getPosition()/BS)<<std::endl;
2731 // ActiveObject is added to environment in AsyncRunStep after
2732 // the previous addition has been succesfully removed
2734 else if(command == TOSERVER_REQUEST_MEDIA) {
2735 std::string datastring((char*)&data[2], datasize-2);
2736 std::istringstream is(datastring, std::ios_base::binary);
2738 std::list<MediaRequest> tosend;
2739 u16 numfiles = readU16(is);
2741 infostream<<"Sending "<<numfiles<<" files to "
2742 <<getPlayerName(peer_id)<<std::endl;
2743 verbosestream<<"TOSERVER_REQUEST_MEDIA: "<<std::endl;
2745 for(int i = 0; i < numfiles; i++) {
2746 std::string name = deSerializeString(is);
2747 tosend.push_back(MediaRequest(name));
2748 verbosestream<<"TOSERVER_REQUEST_MEDIA: requested file "
2752 sendRequestedMedia(peer_id, tosend);
2754 // Now the client should know about everything
2755 // (definitions and files)
2756 getClient(peer_id)->definitions_sent = true;
2758 else if(command == TOSERVER_RECEIVED_MEDIA) {
2759 getClient(peer_id)->definitions_sent = true;
2761 else if(command == TOSERVER_INTERACT)
2763 std::string datastring((char*)&data[2], datasize-2);
2764 std::istringstream is(datastring, std::ios_base::binary);
2770 [5] u32 length of the next item
2771 [9] serialized PointedThing
2773 0: start digging (from undersurface) or use
2774 1: stop digging (all parameters ignored)
2775 2: digging completed
2776 3: place block or item (to abovesurface)
2779 u8 action = readU8(is);
2780 u16 item_i = readU16(is);
2781 std::istringstream tmp_is(deSerializeLongString(is), std::ios::binary);
2782 PointedThing pointed;
2783 pointed.deSerialize(tmp_is);
2785 verbosestream<<"TOSERVER_INTERACT: action="<<(int)action<<", item="
2786 <<item_i<<", pointed="<<pointed.dump()<<std::endl;
2790 verbosestream<<"TOSERVER_INTERACT: "<<player->getName()
2791 <<" tried to interact, but is dead!"<<std::endl;
2795 v3f player_pos = playersao->getLastGoodPosition();
2797 // Update wielded item
2798 playersao->setWieldIndex(item_i);
2800 // Get pointed to node (undefined if not POINTEDTYPE_NODE)
2801 v3s16 p_under = pointed.node_undersurface;
2802 v3s16 p_above = pointed.node_abovesurface;
2804 // Get pointed to object (NULL if not POINTEDTYPE_OBJECT)
2805 ServerActiveObject *pointed_object = NULL;
2806 if(pointed.type == POINTEDTHING_OBJECT)
2808 pointed_object = m_env->getActiveObject(pointed.object_id);
2809 if(pointed_object == NULL)
2811 verbosestream<<"TOSERVER_INTERACT: "
2812 "pointed object is NULL"<<std::endl;
2818 v3f pointed_pos_under = player_pos;
2819 v3f pointed_pos_above = player_pos;
2820 if(pointed.type == POINTEDTHING_NODE)
2822 pointed_pos_under = intToFloat(p_under, BS);
2823 pointed_pos_above = intToFloat(p_above, BS);
2825 else if(pointed.type == POINTEDTHING_OBJECT)
2827 pointed_pos_under = pointed_object->getBasePosition();
2828 pointed_pos_above = pointed_pos_under;
2832 Check that target is reasonably close
2833 (only when digging or placing things)
2835 if(action == 0 || action == 2 || action == 3)
2837 float d = player_pos.getDistanceFrom(pointed_pos_under);
2838 float max_d = BS * 14; // Just some large enough value
2840 actionstream<<"Player "<<player->getName()
2841 <<" tried to access "<<pointed.dump()
2843 <<"d="<<d<<", max_d="<<max_d
2844 <<". ignoring."<<std::endl;
2845 // Re-send block to revert change on client-side
2846 RemoteClient *client = getClient(peer_id);
2847 v3s16 blockpos = getNodeBlockPos(floatToInt(pointed_pos_under, BS));
2848 client->SetBlockNotSent(blockpos);
2850 m_script->on_cheat(playersao, "interacted_too_far");
2857 Make sure the player is allowed to do it
2859 if(!checkPriv(player->getName(), "interact"))
2861 actionstream<<player->getName()<<" attempted to interact with "
2862 <<pointed.dump()<<" without 'interact' privilege"
2864 // Re-send block to revert change on client-side
2865 RemoteClient *client = getClient(peer_id);
2866 // Digging completed -> under
2868 v3s16 blockpos = getNodeBlockPos(floatToInt(pointed_pos_under, BS));
2869 client->SetBlockNotSent(blockpos);
2871 // Placement -> above
2873 v3s16 blockpos = getNodeBlockPos(floatToInt(pointed_pos_above, BS));
2874 client->SetBlockNotSent(blockpos);
2880 If something goes wrong, this player is to blame
2882 RollbackScopeActor rollback_scope(m_rollback,
2883 std::string("player:")+player->getName());
2886 0: start digging or punch object
2890 if(pointed.type == POINTEDTHING_NODE)
2893 NOTE: This can be used in the future to check if
2894 somebody is cheating, by checking the timing.
2896 MapNode n(CONTENT_IGNORE);
2899 n = m_env->getMap().getNode(p_under);
2901 catch(InvalidPositionException &e)
2903 infostream<<"Server: Not punching: Node not found."
2904 <<" Adding block to emerge queue."
2906 m_emerge->enqueueBlockEmerge(peer_id, getNodeBlockPos(p_above), false);
2908 if(n.getContent() != CONTENT_IGNORE)
2909 m_script->node_on_punch(p_under, n, playersao);
2911 playersao->noCheatDigStart(p_under);
2913 else if(pointed.type == POINTEDTHING_OBJECT)
2915 // Skip if object has been removed
2916 if(pointed_object->m_removed)
2919 actionstream<<player->getName()<<" punches object "
2920 <<pointed.object_id<<": "
2921 <<pointed_object->getDescription()<<std::endl;
2923 ItemStack punchitem = playersao->getWieldedItem();
2924 ToolCapabilities toolcap =
2925 punchitem.getToolCapabilities(m_itemdef);
2926 v3f dir = (pointed_object->getBasePosition() -
2927 (player->getPosition() + player->getEyeOffset())
2929 float time_from_last_punch =
2930 playersao->resetTimeFromLastPunch();
2931 pointed_object->punch(dir, &toolcap, playersao,
2932 time_from_last_punch);
2940 else if(action == 1)
2945 2: Digging completed
2947 else if(action == 2)
2949 // Only digging of nodes
2950 if(pointed.type == POINTEDTHING_NODE)
2952 MapNode n(CONTENT_IGNORE);
2955 n = m_env->getMap().getNode(p_under);
2957 catch(InvalidPositionException &e)
2959 infostream<<"Server: Not finishing digging: Node not found."
2960 <<" Adding block to emerge queue."
2962 m_emerge->enqueueBlockEmerge(peer_id, getNodeBlockPos(p_above), false);
2965 /* Cheat prevention */
2966 bool is_valid_dig = true;
2967 if(!isSingleplayer() && !g_settings->getBool("disable_anticheat"))
2969 v3s16 nocheat_p = playersao->getNoCheatDigPos();
2970 float nocheat_t = playersao->getNoCheatDigTime();
2971 playersao->noCheatDigEnd();
2972 // If player didn't start digging this, ignore dig
2973 if(nocheat_p != p_under){
2974 infostream<<"Server: NoCheat: "<<player->getName()
2975 <<" started digging "
2976 <<PP(nocheat_p)<<" and completed digging "
2977 <<PP(p_under)<<"; not digging."<<std::endl;
2978 is_valid_dig = false;
2980 m_script->on_cheat(playersao, "finished_unknown_dig");
2982 // Get player's wielded item
2983 ItemStack playeritem;
2984 InventoryList *mlist = playersao->getInventory()->getList("main");
2986 playeritem = mlist->getItem(playersao->getWieldIndex());
2987 ToolCapabilities playeritem_toolcap =
2988 playeritem.getToolCapabilities(m_itemdef);
2989 // Get diggability and expected digging time
2990 DigParams params = getDigParams(m_nodedef->get(n).groups,
2991 &playeritem_toolcap);
2992 // If can't dig, try hand
2993 if(!params.diggable){
2994 const ItemDefinition &hand = m_itemdef->get("");
2995 const ToolCapabilities *tp = hand.tool_capabilities;
2997 params = getDigParams(m_nodedef->get(n).groups, tp);
2999 // If can't dig, ignore dig
3000 if(!params.diggable){
3001 infostream<<"Server: NoCheat: "<<player->getName()
3002 <<" completed digging "<<PP(p_under)
3003 <<", which is not diggable with tool. not digging."
3005 is_valid_dig = false;
3007 m_script->on_cheat(playersao, "dug_unbreakable");
3009 // Check digging time
3010 // If already invalidated, we don't have to
3012 // Well not our problem then
3014 // Clean and long dig
3015 else if(params.time > 2.0 && nocheat_t * 1.2 > params.time){
3016 // All is good, but grab time from pool; don't care if
3017 // it's actually available
3018 playersao->getDigPool().grab(params.time);
3020 // Short or laggy dig
3021 // Try getting the time from pool
3022 else if(playersao->getDigPool().grab(params.time)){
3027 infostream<<"Server: NoCheat: "<<player->getName()
3028 <<" completed digging "<<PP(p_under)
3029 <<"too fast; not digging."<<std::endl;
3030 is_valid_dig = false;
3032 m_script->on_cheat(playersao, "dug_too_fast");
3036 /* Actually dig node */
3038 if(is_valid_dig && n.getContent() != CONTENT_IGNORE)
3039 m_script->node_on_dig(p_under, n, playersao);
3041 // Send unusual result (that is, node not being removed)
3042 if(m_env->getMap().getNodeNoEx(p_under).getContent() != CONTENT_AIR)
3044 // Re-send block to revert change on client-side
3045 RemoteClient *client = getClient(peer_id);
3046 v3s16 blockpos = getNodeBlockPos(floatToInt(pointed_pos_under, BS));
3047 client->SetBlockNotSent(blockpos);
3053 3: place block or right-click object
3055 else if(action == 3)
3057 ItemStack item = playersao->getWieldedItem();
3059 // Reset build time counter
3060 if(pointed.type == POINTEDTHING_NODE &&
3061 item.getDefinition(m_itemdef).type == ITEM_NODE)
3062 getClient(peer_id)->m_time_from_building = 0.0;
3064 if(pointed.type == POINTEDTHING_OBJECT)
3066 // Right click object
3068 // Skip if object has been removed
3069 if(pointed_object->m_removed)
3072 actionstream<<player->getName()<<" right-clicks object "
3073 <<pointed.object_id<<": "
3074 <<pointed_object->getDescription()<<std::endl;
3077 pointed_object->rightClick(playersao);
3079 else if(m_script->item_OnPlace(
3080 item, playersao, pointed))
3082 // Placement was handled in lua
3084 // Apply returned ItemStack
3085 playersao->setWieldedItem(item);
3088 // If item has node placement prediction, always send the
3089 // blocks to make sure the client knows what exactly happened
3090 if(item.getDefinition(m_itemdef).node_placement_prediction != ""){
3091 RemoteClient *client = getClient(peer_id);
3092 v3s16 blockpos = getNodeBlockPos(floatToInt(pointed_pos_above, BS));
3093 client->SetBlockNotSent(blockpos);
3094 v3s16 blockpos2 = getNodeBlockPos(floatToInt(pointed_pos_under, BS));
3095 if(blockpos2 != blockpos){
3096 client->SetBlockNotSent(blockpos2);
3104 else if(action == 4)
3106 ItemStack item = playersao->getWieldedItem();
3108 actionstream<<player->getName()<<" uses "<<item.name
3109 <<", pointing at "<<pointed.dump()<<std::endl;
3111 if(m_script->item_OnUse(
3112 item, playersao, pointed))
3114 // Apply returned ItemStack
3115 playersao->setWieldedItem(item);
3122 Catch invalid actions
3126 infostream<<"WARNING: Server: Invalid action "
3127 <<action<<std::endl;
3130 else if(command == TOSERVER_REMOVED_SOUNDS)
3132 std::string datastring((char*)&data[2], datasize-2);
3133 std::istringstream is(datastring, std::ios_base::binary);
3135 int num = readU16(is);
3136 for(int k=0; k<num; k++){
3137 s32 id = readS32(is);
3138 std::map<s32, ServerPlayingSound>::iterator i =
3139 m_playing_sounds.find(id);
3140 if(i == m_playing_sounds.end())
3142 ServerPlayingSound &psound = i->second;
3143 psound.clients.erase(peer_id);
3144 if(psound.clients.size() == 0)
3145 m_playing_sounds.erase(i++);
3148 else if(command == TOSERVER_NODEMETA_FIELDS)
3150 std::string datastring((char*)&data[2], datasize-2);
3151 std::istringstream is(datastring, std::ios_base::binary);
3153 v3s16 p = readV3S16(is);
3154 std::string formname = deSerializeString(is);
3155 int num = readU16(is);
3156 std::map<std::string, std::string> fields;
3157 for(int k=0; k<num; k++){
3158 std::string fieldname = deSerializeString(is);
3159 std::string fieldvalue = deSerializeLongString(is);
3160 fields[fieldname] = fieldvalue;
3163 // If something goes wrong, this player is to blame
3164 RollbackScopeActor rollback_scope(m_rollback,
3165 std::string("player:")+player->getName());
3167 // Check the target node for rollback data; leave others unnoticed
3168 RollbackNode rn_old(&m_env->getMap(), p, this);
3170 m_script->node_on_receive_fields(p, formname, fields,playersao);
3172 // Report rollback data
3173 RollbackNode rn_new(&m_env->getMap(), p, this);
3174 if(rollback() && rn_new != rn_old){
3175 RollbackAction action;
3176 action.setSetNode(p, rn_old, rn_new);
3177 rollback()->reportAction(action);
3180 else if(command == TOSERVER_INVENTORY_FIELDS)
3182 std::string datastring((char*)&data[2], datasize-2);
3183 std::istringstream is(datastring, std::ios_base::binary);
3185 std::string formname = deSerializeString(is);
3186 int num = readU16(is);
3187 std::map<std::string, std::string> fields;
3188 for(int k=0; k<num; k++){
3189 std::string fieldname = deSerializeString(is);
3190 std::string fieldvalue = deSerializeLongString(is);
3191 fields[fieldname] = fieldvalue;
3194 m_script->on_playerReceiveFields(playersao, formname, fields);
3198 infostream<<"Server::ProcessData(): Ignoring "
3199 "unknown command "<<command<<std::endl;
3203 catch(SendFailedException &e)
3205 errorstream<<"Server::ProcessData(): SendFailedException: "
3211 void Server::setTimeOfDay(u32 time)
3213 m_env->setTimeOfDay(time);
3214 m_time_of_day_send_timer = 0;
3217 void Server::onMapEditEvent(MapEditEvent *event)
3219 //infostream<<"Server::onMapEditEvent()"<<std::endl;
3220 if(m_ignore_map_edit_events)
3222 if(m_ignore_map_edit_events_area.contains(event->getArea()))
3224 MapEditEvent *e = event->clone();
3225 m_unsent_map_edit_queue.push_back(e);
3228 Inventory* Server::getInventory(const InventoryLocation &loc)
3231 case InventoryLocation::UNDEFINED:
3234 case InventoryLocation::CURRENT_PLAYER:
3237 case InventoryLocation::PLAYER:
3239 Player *player = m_env->getPlayer(loc.name.c_str());
3242 PlayerSAO *playersao = player->getPlayerSAO();
3245 return playersao->getInventory();
3248 case InventoryLocation::NODEMETA:
3250 NodeMetadata *meta = m_env->getMap().getNodeMetadata(loc.p);
3253 return meta->getInventory();
3256 case InventoryLocation::DETACHED:
3258 if(m_detached_inventories.count(loc.name) == 0)
3260 return m_detached_inventories[loc.name];
3268 void Server::setInventoryModified(const InventoryLocation &loc)
3271 case InventoryLocation::UNDEFINED:
3274 case InventoryLocation::PLAYER:
3276 Player *player = m_env->getPlayer(loc.name.c_str());
3279 PlayerSAO *playersao = player->getPlayerSAO();
3282 playersao->m_inventory_not_sent = true;
3283 playersao->m_wielded_item_not_sent = true;
3286 case InventoryLocation::NODEMETA:
3288 v3s16 blockpos = getNodeBlockPos(loc.p);
3290 MapBlock *block = m_env->getMap().getBlockNoCreateNoEx(blockpos);
3292 block->raiseModified(MOD_STATE_WRITE_NEEDED);
3294 setBlockNotSent(blockpos);
3297 case InventoryLocation::DETACHED:
3299 sendDetachedInventoryToAll(loc.name);
3307 void Server::peerAdded(con::Peer *peer)
3309 DSTACK(__FUNCTION_NAME);
3310 verbosestream<<"Server::peerAdded(): peer->id="
3311 <<peer->id<<std::endl;
3314 c.type = PEER_ADDED;
3315 c.peer_id = peer->id;
3317 m_peer_change_queue.push_back(c);
3320 void Server::deletingPeer(con::Peer *peer, bool timeout)
3322 DSTACK(__FUNCTION_NAME);
3323 verbosestream<<"Server::deletingPeer(): peer->id="
3324 <<peer->id<<", timeout="<<timeout<<std::endl;
3327 c.type = PEER_REMOVED;
3328 c.peer_id = peer->id;
3329 c.timeout = timeout;
3330 m_peer_change_queue.push_back(c);
3337 void Server::SendMovement(con::Connection &con, u16 peer_id)
3339 DSTACK(__FUNCTION_NAME);
3340 std::ostringstream os(std::ios_base::binary);
3342 writeU16(os, TOCLIENT_MOVEMENT);
3343 writeF1000(os, g_settings->getFloat("movement_acceleration_default"));
3344 writeF1000(os, g_settings->getFloat("movement_acceleration_air"));
3345 writeF1000(os, g_settings->getFloat("movement_acceleration_fast"));
3346 writeF1000(os, g_settings->getFloat("movement_speed_walk"));
3347 writeF1000(os, g_settings->getFloat("movement_speed_crouch"));
3348 writeF1000(os, g_settings->getFloat("movement_speed_fast"));
3349 writeF1000(os, g_settings->getFloat("movement_speed_climb"));
3350 writeF1000(os, g_settings->getFloat("movement_speed_jump"));
3351 writeF1000(os, g_settings->getFloat("movement_liquid_fluidity"));
3352 writeF1000(os, g_settings->getFloat("movement_liquid_fluidity_smooth"));
3353 writeF1000(os, g_settings->getFloat("movement_liquid_sink"));
3354 writeF1000(os, g_settings->getFloat("movement_gravity"));
3357 std::string s = os.str();
3358 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3360 con.Send(peer_id, 0, data, true);
3363 void Server::SendHP(con::Connection &con, u16 peer_id, u8 hp)
3365 DSTACK(__FUNCTION_NAME);
3366 std::ostringstream os(std::ios_base::binary);
3368 writeU16(os, TOCLIENT_HP);
3372 std::string s = os.str();
3373 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3375 con.Send(peer_id, 0, data, true);
3378 void Server::SendBreath(con::Connection &con, u16 peer_id, u16 breath)
3380 DSTACK(__FUNCTION_NAME);
3381 std::ostringstream os(std::ios_base::binary);
3383 writeU16(os, TOCLIENT_BREATH);
3384 writeU16(os, breath);
3387 std::string s = os.str();
3388 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3390 con.Send(peer_id, 0, data, true);
3393 void Server::SendAccessDenied(con::Connection &con, u16 peer_id,
3394 const std::wstring &reason)
3396 DSTACK(__FUNCTION_NAME);
3397 std::ostringstream os(std::ios_base::binary);
3399 writeU16(os, TOCLIENT_ACCESS_DENIED);
3400 os<<serializeWideString(reason);
3403 std::string s = os.str();
3404 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3406 con.Send(peer_id, 0, data, true);
3409 void Server::SendDeathscreen(con::Connection &con, u16 peer_id,
3410 bool set_camera_point_target, v3f camera_point_target)
3412 DSTACK(__FUNCTION_NAME);
3413 std::ostringstream os(std::ios_base::binary);
3415 writeU16(os, TOCLIENT_DEATHSCREEN);
3416 writeU8(os, set_camera_point_target);
3417 writeV3F1000(os, camera_point_target);
3420 std::string s = os.str();
3421 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3423 con.Send(peer_id, 0, data, true);
3426 void Server::SendItemDef(con::Connection &con, u16 peer_id,
3427 IItemDefManager *itemdef, u16 protocol_version)
3429 DSTACK(__FUNCTION_NAME);
3430 std::ostringstream os(std::ios_base::binary);
3434 u32 length of the next item
3435 zlib-compressed serialized ItemDefManager
3437 writeU16(os, TOCLIENT_ITEMDEF);
3438 std::ostringstream tmp_os(std::ios::binary);
3439 itemdef->serialize(tmp_os, protocol_version);
3440 std::ostringstream tmp_os2(std::ios::binary);
3441 compressZlib(tmp_os.str(), tmp_os2);
3442 os<<serializeLongString(tmp_os2.str());
3445 std::string s = os.str();
3446 verbosestream<<"Server: Sending item definitions to id("<<peer_id
3447 <<"): size="<<s.size()<<std::endl;
3448 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3450 con.Send(peer_id, 0, data, true);
3453 void Server::SendNodeDef(con::Connection &con, u16 peer_id,
3454 INodeDefManager *nodedef, u16 protocol_version)
3456 DSTACK(__FUNCTION_NAME);
3457 std::ostringstream os(std::ios_base::binary);
3461 u32 length of the next item
3462 zlib-compressed serialized NodeDefManager
3464 writeU16(os, TOCLIENT_NODEDEF);
3465 std::ostringstream tmp_os(std::ios::binary);
3466 nodedef->serialize(tmp_os, protocol_version);
3467 std::ostringstream tmp_os2(std::ios::binary);
3468 compressZlib(tmp_os.str(), tmp_os2);
3469 os<<serializeLongString(tmp_os2.str());
3472 std::string s = os.str();
3473 verbosestream<<"Server: Sending node definitions to id("<<peer_id
3474 <<"): size="<<s.size()<<std::endl;
3475 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3477 con.Send(peer_id, 0, data, true);
3481 Non-static send methods
3484 void Server::SendInventory(u16 peer_id)
3486 DSTACK(__FUNCTION_NAME);
3488 PlayerSAO *playersao = getPlayerSAO(peer_id);
3491 playersao->m_inventory_not_sent = false;
3497 std::ostringstream os;
3498 playersao->getInventory()->serialize(os);
3500 std::string s = os.str();
3502 SharedBuffer<u8> data(s.size()+2);
3503 writeU16(&data[0], TOCLIENT_INVENTORY);
3504 memcpy(&data[2], s.c_str(), s.size());
3507 m_con.Send(peer_id, 0, data, true);
3510 void Server::SendChatMessage(u16 peer_id, const std::wstring &message)
3512 DSTACK(__FUNCTION_NAME);
3514 std::ostringstream os(std::ios_base::binary);
3518 writeU16(buf, TOCLIENT_CHAT_MESSAGE);
3519 os.write((char*)buf, 2);
3522 writeU16(buf, message.size());
3523 os.write((char*)buf, 2);
3526 for(u32 i=0; i<message.size(); i++)
3530 os.write((char*)buf, 2);
3534 std::string s = os.str();
3535 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3537 m_con.Send(peer_id, 0, data, true);
3540 void Server::SendShowFormspecMessage(u16 peer_id, const std::string formspec,
3541 const std::string formname)
3543 DSTACK(__FUNCTION_NAME);
3545 std::ostringstream os(std::ios_base::binary);
3549 writeU16(buf, TOCLIENT_SHOW_FORMSPEC);
3550 os.write((char*)buf, 2);
3551 os<<serializeLongString(formspec);
3552 os<<serializeString(formname);
3555 std::string s = os.str();
3556 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3558 m_con.Send(peer_id, 0, data, true);
3561 // Spawns a particle on peer with peer_id
3562 void Server::SendSpawnParticle(u16 peer_id, v3f pos, v3f velocity, v3f acceleration,
3563 float expirationtime, float size, bool collisiondetection,
3564 std::string texture)
3566 DSTACK(__FUNCTION_NAME);
3568 std::ostringstream os(std::ios_base::binary);
3569 writeU16(os, TOCLIENT_SPAWN_PARTICLE);
3570 writeV3F1000(os, pos);
3571 writeV3F1000(os, velocity);
3572 writeV3F1000(os, acceleration);
3573 writeF1000(os, expirationtime);
3574 writeF1000(os, size);
3575 writeU8(os, collisiondetection);
3576 os<<serializeLongString(texture);
3579 std::string s = os.str();
3580 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3582 m_con.Send(peer_id, 0, data, true);
3585 // Spawns a particle on all peers
3586 void Server::SendSpawnParticleAll(v3f pos, v3f velocity, v3f acceleration,
3587 float expirationtime, float size, bool collisiondetection,
3588 std::string texture)
3590 for(std::map<u16, RemoteClient*>::iterator
3591 i = m_clients.begin();
3592 i != m_clients.end(); i++)
3594 // Get client and check that it is valid
3595 RemoteClient *client = i->second;
3596 assert(client->peer_id == i->first);
3597 if(client->serialization_version == SER_FMT_VER_INVALID)
3600 SendSpawnParticle(client->peer_id, pos, velocity, acceleration,
3601 expirationtime, size, collisiondetection, texture);
3605 // Adds a ParticleSpawner on peer with peer_id
3606 void Server::SendAddParticleSpawner(u16 peer_id, u16 amount, float spawntime, v3f minpos, v3f maxpos,
3607 v3f minvel, v3f maxvel, v3f minacc, v3f maxacc, float minexptime, float maxexptime,
3608 float minsize, float maxsize, bool collisiondetection, std::string texture, u32 id)
3610 DSTACK(__FUNCTION_NAME);
3612 std::ostringstream os(std::ios_base::binary);
3613 writeU16(os, TOCLIENT_ADD_PARTICLESPAWNER);
3615 writeU16(os, amount);
3616 writeF1000(os, spawntime);
3617 writeV3F1000(os, minpos);
3618 writeV3F1000(os, maxpos);
3619 writeV3F1000(os, minvel);
3620 writeV3F1000(os, maxvel);
3621 writeV3F1000(os, minacc);
3622 writeV3F1000(os, maxacc);
3623 writeF1000(os, minexptime);
3624 writeF1000(os, maxexptime);
3625 writeF1000(os, minsize);
3626 writeF1000(os, maxsize);
3627 writeU8(os, collisiondetection);
3628 os<<serializeLongString(texture);
3632 std::string s = os.str();
3633 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3635 m_con.Send(peer_id, 0, data, true);
3638 // Adds a ParticleSpawner on all peers
3639 void Server::SendAddParticleSpawnerAll(u16 amount, float spawntime, v3f minpos, v3f maxpos,
3640 v3f minvel, v3f maxvel, v3f minacc, v3f maxacc, float minexptime, float maxexptime,
3641 float minsize, float maxsize, bool collisiondetection, std::string texture, u32 id)
3643 for(std::map<u16, RemoteClient*>::iterator
3644 i = m_clients.begin();
3645 i != m_clients.end(); i++)
3647 // Get client and check that it is valid
3648 RemoteClient *client = i->second;
3649 assert(client->peer_id == i->first);
3650 if(client->serialization_version == SER_FMT_VER_INVALID)
3653 SendAddParticleSpawner(client->peer_id, amount, spawntime,
3654 minpos, maxpos, minvel, maxvel, minacc, maxacc,
3655 minexptime, maxexptime, minsize, maxsize, collisiondetection, texture, id);
3659 void Server::SendDeleteParticleSpawner(u16 peer_id, u32 id)
3661 DSTACK(__FUNCTION_NAME);
3663 std::ostringstream os(std::ios_base::binary);
3664 writeU16(os, TOCLIENT_DELETE_PARTICLESPAWNER);
3669 std::string s = os.str();
3670 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3672 m_con.Send(peer_id, 0, data, true);
3675 void Server::SendDeleteParticleSpawnerAll(u32 id)
3677 for(std::map<u16, RemoteClient*>::iterator
3678 i = m_clients.begin();
3679 i != m_clients.end(); i++)
3681 // Get client and check that it is valid
3682 RemoteClient *client = i->second;
3683 assert(client->peer_id == i->first);
3684 if(client->serialization_version == SER_FMT_VER_INVALID)
3687 SendDeleteParticleSpawner(client->peer_id, id);
3691 void Server::SendHUDAdd(u16 peer_id, u32 id, HudElement *form)
3693 std::ostringstream os(std::ios_base::binary);
3696 writeU16(os, TOCLIENT_HUDADD);
3698 writeU8(os, (u8)form->type);
3699 writeV2F1000(os, form->pos);
3700 os << serializeString(form->name);
3701 writeV2F1000(os, form->scale);
3702 os << serializeString(form->text);
3703 writeU32(os, form->number);
3704 writeU32(os, form->item);
3705 writeU32(os, form->dir);
3706 writeV2F1000(os, form->align);
3707 writeV2F1000(os, form->offset);
3710 std::string s = os.str();
3711 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3713 m_con.Send(peer_id, 0, data, true);
3716 void Server::SendHUDRemove(u16 peer_id, u32 id)
3718 std::ostringstream os(std::ios_base::binary);
3721 writeU16(os, TOCLIENT_HUDRM);
3725 std::string s = os.str();
3726 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3728 m_con.Send(peer_id, 0, data, true);
3731 void Server::SendHUDChange(u16 peer_id, u32 id, HudElementStat stat, void *value)
3733 std::ostringstream os(std::ios_base::binary);
3736 writeU16(os, TOCLIENT_HUDCHANGE);
3738 writeU8(os, (u8)stat);
3741 case HUD_STAT_SCALE:
3742 case HUD_STAT_ALIGN:
3743 case HUD_STAT_OFFSET:
3744 writeV2F1000(os, *(v2f *)value);
3748 os << serializeString(*(std::string *)value);
3750 case HUD_STAT_NUMBER:
3754 writeU32(os, *(u32 *)value);
3759 std::string s = os.str();
3760 SharedBuffer<u8> data((u8 *)s.c_str(), s.size());
3762 m_con.Send(peer_id, 0, data, true);
3765 void Server::SendHUDSetFlags(u16 peer_id, u32 flags, u32 mask)
3767 std::ostringstream os(std::ios_base::binary);
3770 writeU16(os, TOCLIENT_HUD_SET_FLAGS);
3771 writeU32(os, flags);
3775 std::string s = os.str();
3776 SharedBuffer<u8> data((u8 *)s.c_str(), s.size());
3778 m_con.Send(peer_id, 0, data, true);
3781 void Server::SendHUDSetParam(u16 peer_id, u16 param, const std::string &value)
3783 std::ostringstream os(std::ios_base::binary);
3786 writeU16(os, TOCLIENT_HUD_SET_PARAM);
3787 writeU16(os, param);
3788 os<<serializeString(value);
3791 std::string s = os.str();
3792 SharedBuffer<u8> data((u8 *)s.c_str(), s.size());
3794 m_con.Send(peer_id, 0, data, true);
3797 void Server::BroadcastChatMessage(const std::wstring &message)
3799 for(std::map<u16, RemoteClient*>::iterator
3800 i = m_clients.begin();
3801 i != m_clients.end(); ++i)
3803 // Get client and check that it is valid
3804 RemoteClient *client = i->second;
3805 assert(client->peer_id == i->first);
3806 if(client->serialization_version == SER_FMT_VER_INVALID)
3809 SendChatMessage(client->peer_id, message);
3813 void Server::SendTimeOfDay(u16 peer_id, u16 time, f32 time_speed)
3815 DSTACK(__FUNCTION_NAME);
3818 SharedBuffer<u8> data(2+2+4);
3819 writeU16(&data[0], TOCLIENT_TIME_OF_DAY);
3820 writeU16(&data[2], time);
3821 writeF1000(&data[4], time_speed);
3824 m_con.Send(peer_id, 0, data, true);
3827 void Server::SendPlayerHP(u16 peer_id)
3829 DSTACK(__FUNCTION_NAME);
3830 PlayerSAO *playersao = getPlayerSAO(peer_id);
3832 playersao->m_hp_not_sent = false;
3833 SendHP(m_con, peer_id, playersao->getHP());
3835 // Send to other clients
3836 std::string str = gob_cmd_punched(playersao->readDamage(), playersao->getHP());
3837 ActiveObjectMessage aom(playersao->getId(), true, str);
3838 playersao->m_messages_out.push_back(aom);
3841 void Server::SendPlayerBreath(u16 peer_id)
3843 DSTACK(__FUNCTION_NAME);
3844 PlayerSAO *playersao = getPlayerSAO(peer_id);
3846 playersao->m_breath_not_sent = false;
3847 SendBreath(m_con, peer_id, playersao->getBreath());
3850 void Server::SendMovePlayer(u16 peer_id)
3852 DSTACK(__FUNCTION_NAME);
3853 Player *player = m_env->getPlayer(peer_id);
3856 std::ostringstream os(std::ios_base::binary);
3857 writeU16(os, TOCLIENT_MOVE_PLAYER);
3858 writeV3F1000(os, player->getPosition());
3859 writeF1000(os, player->getPitch());
3860 writeF1000(os, player->getYaw());
3863 v3f pos = player->getPosition();
3864 f32 pitch = player->getPitch();
3865 f32 yaw = player->getYaw();
3866 verbosestream<<"Server: Sending TOCLIENT_MOVE_PLAYER"
3867 <<" pos=("<<pos.X<<","<<pos.Y<<","<<pos.Z<<")"
3874 std::string s = os.str();
3875 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3877 m_con.Send(peer_id, 0, data, true);
3880 void Server::SendPlayerPrivileges(u16 peer_id)
3882 Player *player = m_env->getPlayer(peer_id);
3884 if(player->peer_id == PEER_ID_INEXISTENT)
3887 std::set<std::string> privs;
3888 m_script->getAuth(player->getName(), NULL, &privs);
3890 std::ostringstream os(std::ios_base::binary);
3891 writeU16(os, TOCLIENT_PRIVILEGES);
3892 writeU16(os, privs.size());
3893 for(std::set<std::string>::const_iterator i = privs.begin();
3894 i != privs.end(); i++){
3895 os<<serializeString(*i);
3899 std::string s = os.str();
3900 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3902 m_con.Send(peer_id, 0, data, true);
3905 void Server::SendPlayerInventoryFormspec(u16 peer_id)
3907 Player *player = m_env->getPlayer(peer_id);
3909 if(player->peer_id == PEER_ID_INEXISTENT)
3912 std::ostringstream os(std::ios_base::binary);
3913 writeU16(os, TOCLIENT_INVENTORY_FORMSPEC);
3914 os<<serializeLongString(player->inventory_formspec);
3917 std::string s = os.str();
3918 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3920 m_con.Send(peer_id, 0, data, true);
3923 s32 Server::playSound(const SimpleSoundSpec &spec,
3924 const ServerSoundParams ¶ms)
3926 // Find out initial position of sound
3927 bool pos_exists = false;
3928 v3f pos = params.getPos(m_env, &pos_exists);
3929 // If position is not found while it should be, cancel sound
3930 if(pos_exists != (params.type != ServerSoundParams::SSP_LOCAL))
3932 // Filter destination clients
3933 std::set<RemoteClient*> dst_clients;
3934 if(params.to_player != "")
3936 Player *player = m_env->getPlayer(params.to_player.c_str());
3938 infostream<<"Server::playSound: Player \""<<params.to_player
3939 <<"\" not found"<<std::endl;
3942 if(player->peer_id == PEER_ID_INEXISTENT){
3943 infostream<<"Server::playSound: Player \""<<params.to_player
3944 <<"\" not connected"<<std::endl;
3947 RemoteClient *client = getClient(player->peer_id);
3948 dst_clients.insert(client);
3952 for(std::map<u16, RemoteClient*>::iterator
3953 i = m_clients.begin(); i != m_clients.end(); ++i)
3955 RemoteClient *client = i->second;
3956 Player *player = m_env->getPlayer(client->peer_id);
3960 if(player->getPosition().getDistanceFrom(pos) >
3961 params.max_hear_distance)
3964 dst_clients.insert(client);
3967 if(dst_clients.size() == 0)
3970 s32 id = m_next_sound_id++;
3971 // The sound will exist as a reference in m_playing_sounds
3972 m_playing_sounds[id] = ServerPlayingSound();
3973 ServerPlayingSound &psound = m_playing_sounds[id];
3974 psound.params = params;
3975 for(std::set<RemoteClient*>::iterator i = dst_clients.begin();
3976 i != dst_clients.end(); i++)
3977 psound.clients.insert((*i)->peer_id);
3979 std::ostringstream os(std::ios_base::binary);
3980 writeU16(os, TOCLIENT_PLAY_SOUND);
3982 os<<serializeString(spec.name);
3983 writeF1000(os, spec.gain * params.gain);
3984 writeU8(os, params.type);
3985 writeV3F1000(os, pos);
3986 writeU16(os, params.object);
3987 writeU8(os, params.loop);
3989 std::string s = os.str();
3990 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3992 for(std::set<RemoteClient*>::iterator i = dst_clients.begin();
3993 i != dst_clients.end(); i++){
3995 m_con.Send((*i)->peer_id, 0, data, true);
3999 void Server::stopSound(s32 handle)
4001 // Get sound reference
4002 std::map<s32, ServerPlayingSound>::iterator i =
4003 m_playing_sounds.find(handle);
4004 if(i == m_playing_sounds.end())
4006 ServerPlayingSound &psound = i->second;
4008 std::ostringstream os(std::ios_base::binary);
4009 writeU16(os, TOCLIENT_STOP_SOUND);
4010 writeS32(os, handle);
4012 std::string s = os.str();
4013 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
4015 for(std::set<u16>::iterator i = psound.clients.begin();
4016 i != psound.clients.end(); i++){
4018 m_con.Send(*i, 0, data, true);
4020 // Remove sound reference
4021 m_playing_sounds.erase(i);
4024 void Server::sendRemoveNode(v3s16 p, u16 ignore_id,
4025 std::list<u16> *far_players, float far_d_nodes)
4027 float maxd = far_d_nodes*BS;
4028 v3f p_f = intToFloat(p, BS);
4032 SharedBuffer<u8> reply(replysize);
4033 writeU16(&reply[0], TOCLIENT_REMOVENODE);
4034 writeS16(&reply[2], p.X);
4035 writeS16(&reply[4], p.Y);
4036 writeS16(&reply[6], p.Z);
4038 for(std::map<u16, RemoteClient*>::iterator
4039 i = m_clients.begin();
4040 i != m_clients.end(); ++i)
4042 // Get client and check that it is valid
4043 RemoteClient *client = i->second;
4044 assert(client->peer_id == i->first);
4045 if(client->serialization_version == SER_FMT_VER_INVALID)
4048 // Don't send if it's the same one
4049 if(client->peer_id == ignore_id)
4055 Player *player = m_env->getPlayer(client->peer_id);
4058 // If player is far away, only set modified blocks not sent
4059 v3f player_pos = player->getPosition();
4060 if(player_pos.getDistanceFrom(p_f) > maxd)
4062 far_players->push_back(client->peer_id);
4069 m_con.Send(client->peer_id, 0, reply, true);
4073 void Server::sendAddNode(v3s16 p, MapNode n, u16 ignore_id,
4074 std::list<u16> *far_players, float far_d_nodes)
4076 float maxd = far_d_nodes*BS;
4077 v3f p_f = intToFloat(p, BS);
4079 for(std::map<u16, RemoteClient*>::iterator
4080 i = m_clients.begin();
4081 i != m_clients.end(); ++i)
4083 // Get client and check that it is valid
4084 RemoteClient *client = i->second;
4085 assert(client->peer_id == i->first);
4086 if(client->serialization_version == SER_FMT_VER_INVALID)
4089 // Don't send if it's the same one
4090 if(client->peer_id == ignore_id)
4096 Player *player = m_env->getPlayer(client->peer_id);
4099 // If player is far away, only set modified blocks not sent
4100 v3f player_pos = player->getPosition();
4101 if(player_pos.getDistanceFrom(p_f) > maxd)
4103 far_players->push_back(client->peer_id);
4110 u32 replysize = 8 + MapNode::serializedLength(client->serialization_version);
4111 SharedBuffer<u8> reply(replysize);
4112 writeU16(&reply[0], TOCLIENT_ADDNODE);
4113 writeS16(&reply[2], p.X);
4114 writeS16(&reply[4], p.Y);
4115 writeS16(&reply[6], p.Z);
4116 n.serialize(&reply[8], client->serialization_version);
4119 m_con.Send(client->peer_id, 0, reply, true);
4123 void Server::setBlockNotSent(v3s16 p)
4125 for(std::map<u16, RemoteClient*>::iterator
4126 i = m_clients.begin();
4127 i != m_clients.end(); ++i)
4129 RemoteClient *client = i->second;
4130 client->SetBlockNotSent(p);
4134 void Server::SendBlockNoLock(u16 peer_id, MapBlock *block, u8 ver, u16 net_proto_version)
4136 DSTACK(__FUNCTION_NAME);
4138 v3s16 p = block->getPos();
4142 bool completely_air = true;
4143 for(s16 z0=0; z0<MAP_BLOCKSIZE; z0++)
4144 for(s16 x0=0; x0<MAP_BLOCKSIZE; x0++)
4145 for(s16 y0=0; y0<MAP_BLOCKSIZE; y0++)
4147 if(block->getNodeNoEx(v3s16(x0,y0,z0)).d != CONTENT_AIR)
4149 completely_air = false;
4150 x0 = y0 = z0 = MAP_BLOCKSIZE; // Break out
4155 infostream<<"Server: Sending block ("<<p.X<<","<<p.Y<<","<<p.Z<<"): ";
4157 infostream<<"[completely air] ";
4158 infostream<<std::endl;
4162 Create a packet with the block in the right format
4165 std::ostringstream os(std::ios_base::binary);
4166 block->serialize(os, ver, false);
4167 block->serializeNetworkSpecific(os, net_proto_version);
4168 std::string s = os.str();
4169 SharedBuffer<u8> blockdata((u8*)s.c_str(), s.size());
4171 u32 replysize = 8 + blockdata.getSize();
4172 SharedBuffer<u8> reply(replysize);
4173 writeU16(&reply[0], TOCLIENT_BLOCKDATA);
4174 writeS16(&reply[2], p.X);
4175 writeS16(&reply[4], p.Y);
4176 writeS16(&reply[6], p.Z);
4177 memcpy(&reply[8], *blockdata, blockdata.getSize());
4179 /*infostream<<"Server: Sending block ("<<p.X<<","<<p.Y<<","<<p.Z<<")"
4180 <<": \tpacket size: "<<replysize<<std::endl;*/
4185 m_con.Send(peer_id, 1, reply, true);
4188 void Server::SendBlocks(float dtime)
4190 DSTACK(__FUNCTION_NAME);
4192 JMutexAutoLock envlock(m_env_mutex);
4193 JMutexAutoLock conlock(m_con_mutex);
4195 ScopeProfiler sp(g_profiler, "Server: sel and send blocks to clients");
4197 std::vector<PrioritySortedBlockTransfer> queue;
4199 s32 total_sending = 0;
4202 ScopeProfiler sp(g_profiler, "Server: selecting blocks for sending");
4204 for(std::map<u16, RemoteClient*>::iterator
4205 i = m_clients.begin();
4206 i != m_clients.end(); ++i)
4208 RemoteClient *client = i->second;
4209 assert(client->peer_id == i->first);
4211 // If definitions and textures have not been sent, don't
4212 // send MapBlocks either
4213 if(!client->definitions_sent)
4216 total_sending += client->SendingCount();
4218 if(client->serialization_version == SER_FMT_VER_INVALID)
4221 client->GetNextBlocks(this, dtime, queue);
4226 // Lowest priority number comes first.
4227 // Lowest is most important.
4228 std::sort(queue.begin(), queue.end());
4230 for(u32 i=0; i<queue.size(); i++)
4232 //TODO: Calculate limit dynamically
4233 if(total_sending >= g_settings->getS32
4234 ("max_simultaneous_block_sends_server_total"))
4237 PrioritySortedBlockTransfer q = queue[i];
4239 MapBlock *block = NULL;
4242 block = m_env->getMap().getBlockNoCreate(q.pos);
4244 catch(InvalidPositionException &e)
4249 RemoteClient *client = getClientNoEx(q.peer_id);
4255 SendBlockNoLock(q.peer_id, block, client->serialization_version, client->net_proto_version);
4257 client->SentBlock(q.pos);
4263 void Server::fillMediaCache()
4265 DSTACK(__FUNCTION_NAME);
4267 infostream<<"Server: Calculating media file checksums"<<std::endl;
4269 // Collect all media file paths
4270 std::list<std::string> paths;
4271 for(std::vector<ModSpec>::iterator i = m_mods.begin();
4272 i != m_mods.end(); i++){
4273 const ModSpec &mod = *i;
4274 paths.push_back(mod.path + DIR_DELIM + "textures");
4275 paths.push_back(mod.path + DIR_DELIM + "sounds");
4276 paths.push_back(mod.path + DIR_DELIM + "media");
4277 paths.push_back(mod.path + DIR_DELIM + "models");
4279 paths.push_back(porting::path_user + DIR_DELIM + "textures" + DIR_DELIM + "server");
4281 // Collect media file information from paths into cache
4282 for(std::list<std::string>::iterator i = paths.begin();
4283 i != paths.end(); i++)
4285 std::string mediapath = *i;
4286 std::vector<fs::DirListNode> dirlist = fs::GetDirListing(mediapath);
4287 for(u32 j=0; j<dirlist.size(); j++){
4288 if(dirlist[j].dir) // Ignode dirs
4290 std::string filename = dirlist[j].name;
4291 // If name contains illegal characters, ignore the file
4292 if(!string_allowed(filename, TEXTURENAME_ALLOWED_CHARS)){
4293 infostream<<"Server: ignoring illegal file name: \""
4294 <<filename<<"\""<<std::endl;
4297 // If name is not in a supported format, ignore it
4298 const char *supported_ext[] = {
4299 ".png", ".jpg", ".bmp", ".tga",
4300 ".pcx", ".ppm", ".psd", ".wal", ".rgb",
4302 ".x", ".b3d", ".md2", ".obj",
4305 if(removeStringEnd(filename, supported_ext) == ""){
4306 infostream<<"Server: ignoring unsupported file extension: \""
4307 <<filename<<"\""<<std::endl;
4310 // Ok, attempt to load the file and add to cache
4311 std::string filepath = mediapath + DIR_DELIM + filename;
4313 std::ifstream fis(filepath.c_str(), std::ios_base::binary);
4314 if(fis.good() == false){
4315 errorstream<<"Server::fillMediaCache(): Could not open \""
4316 <<filename<<"\" for reading"<<std::endl;
4319 std::ostringstream tmp_os(std::ios_base::binary);
4323 fis.read(buf, 1024);
4324 std::streamsize len = fis.gcount();
4325 tmp_os.write(buf, len);
4334 errorstream<<"Server::fillMediaCache(): Failed to read \""
4335 <<filename<<"\""<<std::endl;
4338 if(tmp_os.str().length() == 0){
4339 errorstream<<"Server::fillMediaCache(): Empty file \""
4340 <<filepath<<"\""<<std::endl;
4345 sha1.addBytes(tmp_os.str().c_str(), tmp_os.str().length());
4347 unsigned char *digest = sha1.getDigest();
4348 std::string sha1_base64 = base64_encode(digest, 20);
4349 std::string sha1_hex = hex_encode((char*)digest, 20);
4353 this->m_media[filename] = MediaInfo(filepath, sha1_base64);
4354 verbosestream<<"Server: "<<sha1_hex<<" is "<<filename<<std::endl;
4359 struct SendableMediaAnnouncement
4362 std::string sha1_digest;
4364 SendableMediaAnnouncement(const std::string name_="",
4365 const std::string sha1_digest_=""):
4367 sha1_digest(sha1_digest_)
4371 void Server::sendMediaAnnouncement(u16 peer_id)
4373 DSTACK(__FUNCTION_NAME);
4375 verbosestream<<"Server: Announcing files to id("<<peer_id<<")"
4378 std::list<SendableMediaAnnouncement> file_announcements;
4380 for(std::map<std::string, MediaInfo>::iterator i = m_media.begin();
4381 i != m_media.end(); i++){
4383 file_announcements.push_back(
4384 SendableMediaAnnouncement(i->first, i->second.sha1_digest));
4388 std::ostringstream os(std::ios_base::binary);
4396 u16 length of sha1_digest
4401 writeU16(os, TOCLIENT_ANNOUNCE_MEDIA);
4402 writeU16(os, file_announcements.size());
4404 for(std::list<SendableMediaAnnouncement>::iterator
4405 j = file_announcements.begin();
4406 j != file_announcements.end(); ++j){
4407 os<<serializeString(j->name);
4408 os<<serializeString(j->sha1_digest);
4410 os<<serializeString(g_settings->get("remote_media"));
4413 std::string s = os.str();
4414 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
4417 m_con.Send(peer_id, 0, data, true);
4420 struct SendableMedia
4426 SendableMedia(const std::string &name_="", const std::string path_="",
4427 const std::string &data_=""):
4434 void Server::sendRequestedMedia(u16 peer_id,
4435 const std::list<MediaRequest> &tosend)
4437 DSTACK(__FUNCTION_NAME);
4439 verbosestream<<"Server::sendRequestedMedia(): "
4440 <<"Sending files to client"<<std::endl;
4444 // Put 5kB in one bunch (this is not accurate)
4445 u32 bytes_per_bunch = 5000;
4447 std::vector< std::list<SendableMedia> > file_bunches;
4448 file_bunches.push_back(std::list<SendableMedia>());
4450 u32 file_size_bunch_total = 0;
4452 for(std::list<MediaRequest>::const_iterator i = tosend.begin();
4453 i != tosend.end(); ++i)
4455 if(m_media.find(i->name) == m_media.end()){
4456 errorstream<<"Server::sendRequestedMedia(): Client asked for "
4457 <<"unknown file \""<<(i->name)<<"\""<<std::endl;
4461 //TODO get path + name
4462 std::string tpath = m_media[(*i).name].path;
4465 std::ifstream fis(tpath.c_str(), std::ios_base::binary);
4466 if(fis.good() == false){
4467 errorstream<<"Server::sendRequestedMedia(): Could not open \""
4468 <<tpath<<"\" for reading"<<std::endl;
4471 std::ostringstream tmp_os(std::ios_base::binary);
4475 fis.read(buf, 1024);
4476 std::streamsize len = fis.gcount();
4477 tmp_os.write(buf, len);
4478 file_size_bunch_total += len;
4487 errorstream<<"Server::sendRequestedMedia(): Failed to read \""
4488 <<(*i).name<<"\""<<std::endl;
4491 /*infostream<<"Server::sendRequestedMedia(): Loaded \""
4492 <<tname<<"\""<<std::endl;*/
4494 file_bunches[file_bunches.size()-1].push_back(
4495 SendableMedia((*i).name, tpath, tmp_os.str()));
4497 // Start next bunch if got enough data
4498 if(file_size_bunch_total >= bytes_per_bunch){
4499 file_bunches.push_back(std::list<SendableMedia>());
4500 file_size_bunch_total = 0;
4505 /* Create and send packets */
4507 u32 num_bunches = file_bunches.size();
4508 for(u32 i=0; i<num_bunches; i++)
4510 std::ostringstream os(std::ios_base::binary);
4514 u16 total number of texture bunches
4515 u16 index of this bunch
4516 u32 number of files in this bunch
4525 writeU16(os, TOCLIENT_MEDIA);
4526 writeU16(os, num_bunches);
4528 writeU32(os, file_bunches[i].size());
4530 for(std::list<SendableMedia>::iterator
4531 j = file_bunches[i].begin();
4532 j != file_bunches[i].end(); ++j){
4533 os<<serializeString(j->name);
4534 os<<serializeLongString(j->data);
4538 std::string s = os.str();
4539 verbosestream<<"Server::sendRequestedMedia(): bunch "
4540 <<i<<"/"<<num_bunches
4541 <<" files="<<file_bunches[i].size()
4542 <<" size=" <<s.size()<<std::endl;
4543 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
4545 m_con.Send(peer_id, 0, data, true);
4549 void Server::sendDetachedInventory(const std::string &name, u16 peer_id)
4551 if(m_detached_inventories.count(name) == 0){
4552 errorstream<<__FUNCTION_NAME<<": \""<<name<<"\" not found"<<std::endl;
4555 Inventory *inv = m_detached_inventories[name];
4557 std::ostringstream os(std::ios_base::binary);
4558 writeU16(os, TOCLIENT_DETACHED_INVENTORY);
4559 os<<serializeString(name);
4563 std::string s = os.str();
4564 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
4566 m_con.Send(peer_id, 0, data, true);
4569 void Server::sendDetachedInventoryToAll(const std::string &name)
4571 DSTACK(__FUNCTION_NAME);
4573 for(std::map<u16, RemoteClient*>::iterator
4574 i = m_clients.begin();
4575 i != m_clients.end(); ++i){
4576 RemoteClient *client = i->second;
4577 sendDetachedInventory(name, client->peer_id);
4581 void Server::sendDetachedInventories(u16 peer_id)
4583 DSTACK(__FUNCTION_NAME);
4585 for(std::map<std::string, Inventory*>::iterator
4586 i = m_detached_inventories.begin();
4587 i != m_detached_inventories.end(); i++){
4588 const std::string &name = i->first;
4589 //Inventory *inv = i->second;
4590 sendDetachedInventory(name, peer_id);
4598 void Server::DiePlayer(u16 peer_id)
4600 DSTACK(__FUNCTION_NAME);
4602 PlayerSAO *playersao = getPlayerSAO(peer_id);
4605 infostream<<"Server::DiePlayer(): Player "
4606 <<playersao->getPlayer()->getName()
4607 <<" dies"<<std::endl;
4609 playersao->setHP(0);
4611 // Trigger scripted stuff
4612 m_script->on_dieplayer(playersao);
4614 SendPlayerHP(peer_id);
4615 SendDeathscreen(m_con, peer_id, false, v3f(0,0,0));
4618 void Server::RespawnPlayer(u16 peer_id)
4620 DSTACK(__FUNCTION_NAME);
4622 PlayerSAO *playersao = getPlayerSAO(peer_id);
4625 infostream<<"Server::RespawnPlayer(): Player "
4626 <<playersao->getPlayer()->getName()
4627 <<" respawns"<<std::endl;
4629 playersao->setHP(PLAYER_MAX_HP);
4631 bool repositioned = m_script->on_respawnplayer(playersao);
4633 v3f pos = findSpawnPos(m_env->getServerMap());
4634 playersao->setPos(pos);
4638 void Server::DenyAccess(u16 peer_id, const std::wstring &reason)
4640 DSTACK(__FUNCTION_NAME);
4642 SendAccessDenied(m_con, peer_id, reason);
4644 RemoteClient *client = getClientNoEx(peer_id);
4646 client->denied = true;
4648 // If there are way too many clients, get rid of denied new ones immediately
4649 if((int)m_clients.size() > 2 * g_settings->getU16("max_users")){
4650 verbosestream<<"Server: DenyAccess: Too many clients; getting rid of "
4651 <<"peer_id="<<peer_id<<" immediately"<<std::endl;
4652 // Delete peer to stop sending it data
4653 m_con.DeletePeer(peer_id);
4654 // Delete client also to stop block sends and other stuff
4655 DeleteClient(peer_id, CDR_DENY);
4659 void Server::DeleteClient(u16 peer_id, ClientDeletionReason reason)
4661 DSTACK(__FUNCTION_NAME);
4664 std::map<u16, RemoteClient*>::iterator n;
4665 n = m_clients.find(peer_id);
4666 // The client may not exist; clients are immediately removed if their
4667 // access is denied, and this event occurs later then.
4668 if(n == m_clients.end())
4672 Mark objects to be not known by the client
4674 RemoteClient *client = n->second;
4676 for(std::set<u16>::iterator
4677 i = client->m_known_objects.begin();
4678 i != client->m_known_objects.end(); ++i)
4682 ServerActiveObject* obj = m_env->getActiveObject(id);
4684 if(obj && obj->m_known_by_count > 0)
4685 obj->m_known_by_count--;
4689 Clear references to playing sounds
4691 for(std::map<s32, ServerPlayingSound>::iterator
4692 i = m_playing_sounds.begin();
4693 i != m_playing_sounds.end();)
4695 ServerPlayingSound &psound = i->second;
4696 psound.clients.erase(peer_id);
4697 if(psound.clients.size() == 0)
4698 m_playing_sounds.erase(i++);
4703 Player *player = m_env->getPlayer(peer_id);
4705 // Collect information about leaving in chat
4706 std::wstring message;
4708 if(player != NULL && reason != CDR_DENY)
4710 std::wstring name = narrow_to_wide(player->getName());
4713 message += L" left the game.";
4714 if(reason == CDR_TIMEOUT)
4715 message += L" (timed out)";
4719 /* Run scripts and remove from environment */
4723 PlayerSAO *playersao = player->getPlayerSAO();
4726 m_script->on_leaveplayer(playersao);
4728 playersao->disconnected();
4736 if(player != NULL && reason != CDR_DENY)
4738 std::ostringstream os(std::ios_base::binary);
4739 for(std::map<u16, RemoteClient*>::iterator
4740 i = m_clients.begin();
4741 i != m_clients.end(); ++i)
4743 RemoteClient *client = i->second;
4744 assert(client->peer_id == i->first);
4745 if(client->serialization_version == SER_FMT_VER_INVALID)
4748 Player *player = m_env->getPlayer(client->peer_id);
4751 // Get name of player
4752 os<<player->getName()<<" ";
4755 actionstream<<player->getName()<<" "
4756 <<(reason==CDR_TIMEOUT?"times out.":"leaves game.")
4757 <<" List of players: "<<os.str()<<std::endl;
4762 delete m_clients[peer_id];
4763 m_clients.erase(peer_id);
4765 // Send leave chat message to all remaining clients
4766 if(message.length() != 0)
4767 BroadcastChatMessage(message);
4770 void Server::UpdateCrafting(u16 peer_id)
4772 DSTACK(__FUNCTION_NAME);
4774 Player* player = m_env->getPlayer(peer_id);
4777 // Get a preview for crafting
4779 getCraftingResult(&player->inventory, preview, false, this);
4781 // Put the new preview in
4782 InventoryList *plist = player->inventory.getList("craftpreview");
4784 assert(plist->getSize() >= 1);
4785 plist->changeItem(0, preview);
4788 RemoteClient* Server::getClient(u16 peer_id)
4790 RemoteClient *client = getClientNoEx(peer_id);
4792 throw ClientNotFoundException("Client not found");
4795 RemoteClient* Server::getClientNoEx(u16 peer_id)
4797 std::map<u16, RemoteClient*>::iterator n;
4798 n = m_clients.find(peer_id);
4799 // The client may not exist; clients are immediately removed if their
4800 // access is denied, and this event occurs later then.
4801 if(n == m_clients.end())
4806 std::string Server::getPlayerName(u16 peer_id)
4808 Player *player = m_env->getPlayer(peer_id);
4810 return "[id="+itos(peer_id)+"]";
4811 return player->getName();
4814 PlayerSAO* Server::getPlayerSAO(u16 peer_id)
4816 Player *player = m_env->getPlayer(peer_id);
4819 return player->getPlayerSAO();
4822 std::wstring Server::getStatusString()
4824 std::wostringstream os(std::ios_base::binary);
4827 os<<L"version="<<narrow_to_wide(minetest_version_simple);
4829 os<<L", uptime="<<m_uptime.get();
4831 os<<L", max_lag="<<m_env->getMaxLagEstimate();
4832 // Information about clients
4833 std::map<u16, RemoteClient*>::iterator i;
4836 for(i = m_clients.begin(), first = true;
4837 i != m_clients.end(); ++i)
4839 // Get client and check that it is valid
4840 RemoteClient *client = i->second;
4841 assert(client->peer_id == i->first);
4842 if(client->serialization_version == SER_FMT_VER_INVALID)
4845 Player *player = m_env->getPlayer(client->peer_id);
4846 // Get name of player
4847 std::wstring name = L"unknown";
4849 name = narrow_to_wide(player->getName());
4850 // Add name to information string
4858 if(((ServerMap*)(&m_env->getMap()))->isSavingEnabled() == false)
4859 os<<std::endl<<L"# Server: "<<" WARNING: Map saving is disabled.";
4860 if(g_settings->get("motd") != "")
4861 os<<std::endl<<L"# Server: "<<narrow_to_wide(g_settings->get("motd"));
4865 std::set<std::string> Server::getPlayerEffectivePrivs(const std::string &name)
4867 std::set<std::string> privs;
4868 m_script->getAuth(name, NULL, &privs);
4872 bool Server::checkPriv(const std::string &name, const std::string &priv)
4874 std::set<std::string> privs = getPlayerEffectivePrivs(name);
4875 return (privs.count(priv) != 0);
4878 void Server::reportPrivsModified(const std::string &name)
4881 for(std::map<u16, RemoteClient*>::iterator
4882 i = m_clients.begin();
4883 i != m_clients.end(); ++i){
4884 RemoteClient *client = i->second;
4885 Player *player = m_env->getPlayer(client->peer_id);
4886 reportPrivsModified(player->getName());
4889 Player *player = m_env->getPlayer(name.c_str());
4892 SendPlayerPrivileges(player->peer_id);
4893 PlayerSAO *sao = player->getPlayerSAO();
4896 sao->updatePrivileges(
4897 getPlayerEffectivePrivs(name),
4902 void Server::reportInventoryFormspecModified(const std::string &name)
4904 Player *player = m_env->getPlayer(name.c_str());
4907 SendPlayerInventoryFormspec(player->peer_id);
4910 void Server::setIpBanned(const std::string &ip, const std::string &name)
4912 m_banmanager->add(ip, name);
4915 void Server::unsetIpBanned(const std::string &ip_or_name)
4917 m_banmanager->remove(ip_or_name);
4920 std::string Server::getBanDescription(const std::string &ip_or_name)
4922 return m_banmanager->getBanDescription(ip_or_name);
4925 void Server::notifyPlayer(const char *name, const std::wstring msg, const bool prepend = true)
4927 Player *player = m_env->getPlayer(name);
4931 SendChatMessage(player->peer_id, std::wstring(L"Server -!- ")+msg);
4933 SendChatMessage(player->peer_id, msg);
4936 bool Server::showFormspec(const char *playername, const std::string &formspec, const std::string &formname)
4938 Player *player = m_env->getPlayer(playername);
4942 infostream<<"showFormspec: couldn't find player:"<<playername<<std::endl;
4946 SendShowFormspecMessage(player->peer_id, formspec, formname);
4950 u32 Server::hudAdd(Player *player, HudElement *form) {
4954 u32 id = player->getFreeHudID();
4955 if (id < player->hud.size())
4956 player->hud[id] = form;
4958 player->hud.push_back(form);
4960 SendHUDAdd(player->peer_id, id, form);
4964 bool Server::hudRemove(Player *player, u32 id) {
4965 if (!player || id >= player->hud.size() || !player->hud[id])
4968 delete player->hud[id];
4969 player->hud[id] = NULL;
4971 SendHUDRemove(player->peer_id, id);
4975 bool Server::hudChange(Player *player, u32 id, HudElementStat stat, void *data) {
4979 SendHUDChange(player->peer_id, id, stat, data);
4983 bool Server::hudSetFlags(Player *player, u32 flags, u32 mask) {
4987 SendHUDSetFlags(player->peer_id, flags, mask);
4991 bool Server::hudSetHotbarItemcount(Player *player, s32 hotbar_itemcount) {
4994 if (hotbar_itemcount <= 0 || hotbar_itemcount > HUD_HOTBAR_ITEMCOUNT_MAX)
4997 std::ostringstream os(std::ios::binary);
4998 writeS32(os, hotbar_itemcount);
4999 SendHUDSetParam(player->peer_id, HUD_PARAM_HOTBAR_ITEMCOUNT, os.str());
5003 void Server::hudSetHotbarImage(Player *player, std::string name) {
5007 SendHUDSetParam(player->peer_id, HUD_PARAM_HOTBAR_IMAGE, name);
5010 void Server::hudSetHotbarSelectedImage(Player *player, std::string name) {
5014 SendHUDSetParam(player->peer_id, HUD_PARAM_HOTBAR_SELECTED_IMAGE, name);
5017 void Server::notifyPlayers(const std::wstring msg)
5019 BroadcastChatMessage(msg);
5022 void Server::spawnParticle(const char *playername, v3f pos,
5023 v3f velocity, v3f acceleration,
5024 float expirationtime, float size, bool
5025 collisiondetection, std::string texture)
5027 Player *player = m_env->getPlayer(playername);
5030 SendSpawnParticle(player->peer_id, pos, velocity, acceleration,
5031 expirationtime, size, collisiondetection, texture);
5034 void Server::spawnParticleAll(v3f pos, v3f velocity, v3f acceleration,
5035 float expirationtime, float size,
5036 bool collisiondetection, std::string texture)
5038 SendSpawnParticleAll(pos, velocity, acceleration,
5039 expirationtime, size, collisiondetection, texture);
5042 u32 Server::addParticleSpawner(const char *playername,
5043 u16 amount, float spawntime,
5044 v3f minpos, v3f maxpos,
5045 v3f minvel, v3f maxvel,
5046 v3f minacc, v3f maxacc,
5047 float minexptime, float maxexptime,
5048 float minsize, float maxsize,
5049 bool collisiondetection, std::string texture)
5051 Player *player = m_env->getPlayer(playername);
5056 for(;;) // look for unused particlespawner id
5059 if (std::find(m_particlespawner_ids.begin(),
5060 m_particlespawner_ids.end(), id)
5061 == m_particlespawner_ids.end())
5063 m_particlespawner_ids.push_back(id);
5068 SendAddParticleSpawner(player->peer_id, amount, spawntime,
5069 minpos, maxpos, minvel, maxvel, minacc, maxacc,
5070 minexptime, maxexptime, minsize, maxsize,
5071 collisiondetection, texture, id);
5076 u32 Server::addParticleSpawnerAll(u16 amount, float spawntime,
5077 v3f minpos, v3f maxpos,
5078 v3f minvel, v3f maxvel,
5079 v3f minacc, v3f maxacc,
5080 float minexptime, float maxexptime,
5081 float minsize, float maxsize,
5082 bool collisiondetection, std::string texture)
5085 for(;;) // look for unused particlespawner id
5088 if (std::find(m_particlespawner_ids.begin(),
5089 m_particlespawner_ids.end(), id)
5090 == m_particlespawner_ids.end())
5092 m_particlespawner_ids.push_back(id);
5097 SendAddParticleSpawnerAll(amount, spawntime,
5098 minpos, maxpos, minvel, maxvel, minacc, maxacc,
5099 minexptime, maxexptime, minsize, maxsize,
5100 collisiondetection, texture, id);
5105 void Server::deleteParticleSpawner(const char *playername, u32 id)
5107 Player *player = m_env->getPlayer(playername);
5111 m_particlespawner_ids.erase(
5112 std::remove(m_particlespawner_ids.begin(),
5113 m_particlespawner_ids.end(), id),
5114 m_particlespawner_ids.end());
5115 SendDeleteParticleSpawner(player->peer_id, id);
5118 void Server::deleteParticleSpawnerAll(u32 id)
5120 m_particlespawner_ids.erase(
5121 std::remove(m_particlespawner_ids.begin(),
5122 m_particlespawner_ids.end(), id),
5123 m_particlespawner_ids.end());
5124 SendDeleteParticleSpawnerAll(id);
5127 Inventory* Server::createDetachedInventory(const std::string &name)
5129 if(m_detached_inventories.count(name) > 0){
5130 infostream<<"Server clearing detached inventory \""<<name<<"\""<<std::endl;
5131 delete m_detached_inventories[name];
5133 infostream<<"Server creating detached inventory \""<<name<<"\""<<std::endl;
5135 Inventory *inv = new Inventory(m_itemdef);
5137 m_detached_inventories[name] = inv;
5138 sendDetachedInventoryToAll(name);
5145 BoolScopeSet(bool *dst, bool val):
5148 m_orig_state = *m_dst;
5153 *m_dst = m_orig_state;
5160 // actions: time-reversed list
5161 // Return value: success/failure
5162 bool Server::rollbackRevertActions(const std::list<RollbackAction> &actions,
5163 std::list<std::string> *log)
5165 infostream<<"Server::rollbackRevertActions(len="<<actions.size()<<")"<<std::endl;
5166 ServerMap *map = (ServerMap*)(&m_env->getMap());
5167 // Disable rollback report sink while reverting
5168 BoolScopeSet rollback_scope_disable(&m_rollback_sink_enabled, false);
5170 // Fail if no actions to handle
5171 if(actions.empty()){
5172 log->push_back("Nothing to do.");
5179 for(std::list<RollbackAction>::const_iterator
5180 i = actions.begin();
5181 i != actions.end(); i++)
5183 const RollbackAction &action = *i;
5185 bool success = action.applyRevert(map, this, this);
5188 std::ostringstream os;
5189 os<<"Revert of step ("<<num_tried<<") "<<action.toString()<<" failed";
5190 infostream<<"Map::rollbackRevertActions(): "<<os.str()<<std::endl;
5192 log->push_back(os.str());
5194 std::ostringstream os;
5195 os<<"Successfully reverted step ("<<num_tried<<") "<<action.toString();
5196 infostream<<"Map::rollbackRevertActions(): "<<os.str()<<std::endl;
5198 log->push_back(os.str());
5202 infostream<<"Map::rollbackRevertActions(): "<<num_failed<<"/"<<num_tried
5203 <<" failed"<<std::endl;
5205 // Call it done if less than half failed
5206 return num_failed <= num_tried/2;
5209 // IGameDef interface
5211 IItemDefManager* Server::getItemDefManager()
5215 INodeDefManager* Server::getNodeDefManager()
5219 ICraftDefManager* Server::getCraftDefManager()
5223 ITextureSource* Server::getTextureSource()
5227 IShaderSource* Server::getShaderSource()
5231 u16 Server::allocateUnknownNodeId(const std::string &name)
5233 return m_nodedef->allocateDummy(name);
5235 ISoundManager* Server::getSoundManager()
5237 return &dummySoundManager;
5239 MtEventManager* Server::getEventManager()
5243 IRollbackReportSink* Server::getRollbackReportSink()
5245 if(!m_enable_rollback_recording)
5247 if(!m_rollback_sink_enabled)
5252 IWritableItemDefManager* Server::getWritableItemDefManager()
5256 IWritableNodeDefManager* Server::getWritableNodeDefManager()
5260 IWritableCraftDefManager* Server::getWritableCraftDefManager()
5265 const ModSpec* Server::getModSpec(const std::string &modname)
5267 for(std::vector<ModSpec>::iterator i = m_mods.begin();
5268 i != m_mods.end(); i++){
5269 const ModSpec &mod = *i;
5270 if(mod.name == modname)
5275 void Server::getModNames(std::list<std::string> &modlist)
5277 for(std::vector<ModSpec>::iterator i = m_mods.begin(); i != m_mods.end(); i++)
5279 modlist.push_back(i->name);
5282 std::string Server::getBuiltinLuaPath()
5284 return porting::path_share + DIR_DELIM + "builtin";
5287 v3f findSpawnPos(ServerMap &map)
5289 //return v3f(50,50,50)*BS;
5294 nodepos = v2s16(0,0);
5299 s16 water_level = map.m_mgparams->water_level;
5301 // Try to find a good place a few times
5302 for(s32 i=0; i<1000; i++)
5305 // We're going to try to throw the player to this position
5306 v2s16 nodepos2d = v2s16(
5307 -range + (myrand() % (range * 2)),
5308 -range + (myrand() % (range * 2)));
5310 // Get ground height at point
5311 s16 groundheight = map.findGroundLevel(nodepos2d);
5312 if (groundheight <= water_level) // Don't go underwater
5314 if (groundheight > water_level + 6) // Don't go to high places
5317 nodepos = v3s16(nodepos2d.X, groundheight, nodepos2d.Y);
5318 bool is_good = false;
5320 for (s32 i = 0; i < 10; i++) {
5321 v3s16 blockpos = getNodeBlockPos(nodepos);
5322 map.emergeBlock(blockpos, true);
5323 content_t c = map.getNodeNoEx(nodepos).getContent();
5324 if (c == CONTENT_AIR || c == CONTENT_IGNORE) {
5326 if (air_count >= 2){
5334 // Found a good place
5335 //infostream<<"Searched through "<<i<<" places."<<std::endl;
5341 return intToFloat(nodepos, BS);
5344 PlayerSAO* Server::emergePlayer(const char *name, u16 peer_id)
5346 RemotePlayer *player = NULL;
5347 bool newplayer = false;
5350 Try to get an existing player
5352 player = static_cast<RemotePlayer*>(m_env->getPlayer(name));
5354 // If player is already connected, cancel
5355 if(player != NULL && player->peer_id != 0)
5357 infostream<<"emergePlayer(): Player already connected"<<std::endl;
5362 If player with the wanted peer_id already exists, cancel.
5364 if(m_env->getPlayer(peer_id) != NULL)
5366 infostream<<"emergePlayer(): Player with wrong name but same"
5367 " peer_id already exists"<<std::endl;
5372 Create a new player if it doesn't exist yet
5377 player = new RemotePlayer(this);
5378 player->updateName(name);
5380 /* Set player position */
5381 infostream<<"Server: Finding spawn place for player \""
5382 <<name<<"\""<<std::endl;
5383 v3f pos = findSpawnPos(m_env->getServerMap());
5384 player->setPosition(pos);
5386 /* Add player to environment */
5387 m_env->addPlayer(player);
5391 Create a new player active object
5393 PlayerSAO *playersao = new PlayerSAO(m_env, player, peer_id,
5394 getPlayerEffectivePrivs(player->getName()),
5397 /* Clean up old HUD elements from previous sessions */
5398 player->hud.clear();
5400 /* Add object to environment */
5401 m_env->addActiveObject(playersao);
5405 m_script->on_newplayer(playersao);
5407 m_script->on_joinplayer(playersao);
5412 void Server::handlePeerChange(PeerChange &c)
5414 JMutexAutoLock envlock(m_env_mutex);
5415 JMutexAutoLock conlock(m_con_mutex);
5417 if(c.type == PEER_ADDED)
5424 std::map<u16, RemoteClient*>::iterator n;
5425 n = m_clients.find(c.peer_id);
5426 // The client shouldn't already exist
5427 assert(n == m_clients.end());
5430 RemoteClient *client = new RemoteClient();
5431 client->peer_id = c.peer_id;
5432 m_clients[client->peer_id] = client;
5435 else if(c.type == PEER_REMOVED)
5441 DeleteClient(c.peer_id, c.timeout?CDR_TIMEOUT:CDR_LEAVE);
5450 void Server::handlePeerChanges()
5452 while(m_peer_change_queue.size() > 0)
5454 PeerChange c = m_peer_change_queue.pop_front();
5456 verbosestream<<"Server: Handling peer change: "
5457 <<"id="<<c.peer_id<<", timeout="<<c.timeout
5460 handlePeerChange(c);
5464 void dedicated_server_loop(Server &server, bool &kill)
5466 DSTACK(__FUNCTION_NAME);
5468 verbosestream<<"dedicated_server_loop()"<<std::endl;
5470 IntervalLimiter m_profiler_interval;
5474 float steplen = g_settings->getFloat("dedicated_server_step");
5475 // This is kind of a hack but can be done like this
5476 // because server.step() is very light
5478 ScopeProfiler sp(g_profiler, "dedicated server sleep");
5479 sleep_ms((int)(steplen*1000.0));
5481 server.step(steplen);
5483 if(server.getShutdownRequested() || kill)
5485 infostream<<"Dedicated server quitting"<<std::endl;
5487 if(g_settings->getBool("server_announce") == true)
5488 ServerList::sendAnnounce("delete");
5496 float profiler_print_interval =
5497 g_settings->getFloat("profiler_print_interval");
5498 if(profiler_print_interval != 0)
5500 if(m_profiler_interval.step(steplen, profiler_print_interval))
5502 infostream<<"Profiler:"<<std::endl;
5503 g_profiler->print(infostream);
5504 g_profiler->clear();