3 Copyright (C) 2010-2013 celeron55, Perttu Ahola <celeron55@gmail.com>
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU Lesser General Public License as published by
7 the Free Software Foundation; either version 2.1 of the License, or
8 (at your option) any later version.
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU Lesser General Public License for more details.
15 You should have received a copy of the GNU Lesser General Public License along
16 with this program; if not, write to the Free Software Foundation, Inc.,
17 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
24 #include "clientserver.h"
26 #include "environment.h"
28 #include "jmutexautolock.h"
30 #include "constants.h"
35 #include "serverobject.h"
39 #include "scripting_game.h"
46 #include "content_mapnode.h"
47 #include "content_nodemeta.h"
48 #include "content_abm.h"
49 #include "content_sao.h"
54 #include "sound.h" // dummySoundManager
55 #include "event_manager.h"
57 #include "serverlist.h"
58 #include "util/string.h"
59 #include "util/pointedthing.h"
60 #include "util/mathconstants.h"
62 #include "util/serialize.h"
63 #include "util/thread.h"
64 #include "defaultsettings.h"
66 class ClientNotFoundException : public BaseException
69 ClientNotFoundException(const char *s):
74 class ServerThread : public SimpleThread
80 ServerThread(Server *server):
89 void * ServerThread::Thread()
93 log_register_thread("ServerThread");
95 DSTACK(__FUNCTION_NAME);
97 BEGIN_DEBUG_EXCEPTION_HANDLER
102 //TimeTaker timer("AsyncRunStep() + Receive()");
105 //TimeTaker timer("AsyncRunStep()");
106 m_server->AsyncRunStep();
109 //infostream<<"Running m_server->Receive()"<<std::endl;
112 catch(con::NoIncomingDataException &e)
115 catch(con::PeerNotFoundException &e)
117 infostream<<"Server: PeerNotFoundException"<<std::endl;
119 catch(ClientNotFoundException &e)
122 catch(con::ConnectionBindFailed &e)
124 m_server->setAsyncFatalError(e.what());
128 m_server->setAsyncFatalError(e.what());
132 END_DEBUG_EXCEPTION_HANDLER(errorstream)
137 v3f ServerSoundParams::getPos(ServerEnvironment *env, bool *pos_exists) const
139 if(pos_exists) *pos_exists = false;
144 if(pos_exists) *pos_exists = true;
149 ServerActiveObject *sao = env->getActiveObject(object);
152 if(pos_exists) *pos_exists = true;
153 return sao->getBasePosition(); }
158 void RemoteClient::GetNextBlocks(Server *server, float dtime,
159 std::vector<PrioritySortedBlockTransfer> &dest)
161 DSTACK(__FUNCTION_NAME);
164 TimeTaker timer("RemoteClient::GetNextBlocks", &timer_result);*/
167 m_nothing_to_send_pause_timer -= dtime;
168 m_nearest_unsent_reset_timer += dtime;
170 if(m_nothing_to_send_pause_timer >= 0)
173 Player *player = server->m_env->getPlayer(peer_id);
174 // This can happen sometimes; clients and players are not in perfect sync.
178 // Won't send anything if already sending
179 if(m_blocks_sending.size() >= g_settings->getU16
180 ("max_simultaneous_block_sends_per_client"))
182 //infostream<<"Not sending any blocks, Queue full."<<std::endl;
186 //TimeTaker timer("RemoteClient::GetNextBlocks");
188 v3f playerpos = player->getPosition();
189 v3f playerspeed = player->getSpeed();
190 v3f playerspeeddir(0,0,0);
191 if(playerspeed.getLength() > 1.0*BS)
192 playerspeeddir = playerspeed / playerspeed.getLength();
193 // Predict to next block
194 v3f playerpos_predicted = playerpos + playerspeeddir*MAP_BLOCKSIZE*BS;
196 v3s16 center_nodepos = floatToInt(playerpos_predicted, BS);
198 v3s16 center = getNodeBlockPos(center_nodepos);
200 // Camera position and direction
201 v3f camera_pos = player->getEyePosition();
202 v3f camera_dir = v3f(0,0,1);
203 camera_dir.rotateYZBy(player->getPitch());
204 camera_dir.rotateXZBy(player->getYaw());
206 /*infostream<<"camera_dir=("<<camera_dir.X<<","<<camera_dir.Y<<","
207 <<camera_dir.Z<<")"<<std::endl;*/
210 Get the starting value of the block finder radius.
213 if(m_last_center != center)
215 m_nearest_unsent_d = 0;
216 m_last_center = center;
219 /*infostream<<"m_nearest_unsent_reset_timer="
220 <<m_nearest_unsent_reset_timer<<std::endl;*/
222 // Reset periodically to workaround for some bugs or stuff
223 if(m_nearest_unsent_reset_timer > 20.0)
225 m_nearest_unsent_reset_timer = 0;
226 m_nearest_unsent_d = 0;
227 //infostream<<"Resetting m_nearest_unsent_d for "
228 // <<server->getPlayerName(peer_id)<<std::endl;
231 //s16 last_nearest_unsent_d = m_nearest_unsent_d;
232 s16 d_start = m_nearest_unsent_d;
234 //infostream<<"d_start="<<d_start<<std::endl;
236 u16 max_simul_sends_setting = g_settings->getU16
237 ("max_simultaneous_block_sends_per_client");
238 u16 max_simul_sends_usually = max_simul_sends_setting;
241 Check the time from last addNode/removeNode.
243 Decrease send rate if player is building stuff.
245 m_time_from_building += dtime;
246 if(m_time_from_building < g_settings->getFloat(
247 "full_block_send_enable_min_time_from_building"))
249 max_simul_sends_usually
250 = LIMITED_MAX_SIMULTANEOUS_BLOCK_SENDS;
254 Number of blocks sending + number of blocks selected for sending
256 u32 num_blocks_selected = m_blocks_sending.size();
259 next time d will be continued from the d from which the nearest
260 unsent block was found this time.
262 This is because not necessarily any of the blocks found this
263 time are actually sent.
265 s32 new_nearest_unsent_d = -1;
267 s16 d_max = g_settings->getS16("max_block_send_distance");
268 s16 d_max_gen = g_settings->getS16("max_block_generate_distance");
270 // Don't loop very much at a time
271 s16 max_d_increment_at_time = 2;
272 if(d_max > d_start + max_d_increment_at_time)
273 d_max = d_start + max_d_increment_at_time;
274 /*if(d_max_gen > d_start+2)
275 d_max_gen = d_start+2;*/
277 //infostream<<"Starting from "<<d_start<<std::endl;
279 s32 nearest_emerged_d = -1;
280 s32 nearest_emergefull_d = -1;
281 s32 nearest_sent_d = -1;
282 bool queue_is_full = false;
285 for(d = d_start; d <= d_max; d++)
287 /*errorstream<<"checking d="<<d<<" for "
288 <<server->getPlayerName(peer_id)<<std::endl;*/
289 //infostream<<"RemoteClient::SendBlocks(): d="<<d<<std::endl;
292 If m_nearest_unsent_d was changed by the EmergeThread
293 (it can change it to 0 through SetBlockNotSent),
295 Else update m_nearest_unsent_d
297 /*if(m_nearest_unsent_d != last_nearest_unsent_d)
299 d = m_nearest_unsent_d;
300 last_nearest_unsent_d = m_nearest_unsent_d;
304 Get the border/face dot coordinates of a "d-radiused"
307 std::list<v3s16> list;
308 getFacePositions(list, d);
310 std::list<v3s16>::iterator li;
311 for(li=list.begin(); li!=list.end(); ++li)
313 v3s16 p = *li + center;
317 - Don't allow too many simultaneous transfers
318 - EXCEPT when the blocks are very close
320 Also, don't send blocks that are already flying.
323 // Start with the usual maximum
324 u16 max_simul_dynamic = max_simul_sends_usually;
326 // If block is very close, allow full maximum
327 if(d <= BLOCK_SEND_DISABLE_LIMITS_MAX_D)
328 max_simul_dynamic = max_simul_sends_setting;
330 // Don't select too many blocks for sending
331 if(num_blocks_selected >= max_simul_dynamic)
333 queue_is_full = true;
334 goto queue_full_break;
337 // Don't send blocks that are currently being transferred
338 if(m_blocks_sending.find(p) != m_blocks_sending.end())
344 if(p.X < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
345 || p.X > MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
346 || p.Y < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
347 || p.Y > MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
348 || p.Z < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
349 || p.Z > MAP_GENERATION_LIMIT / MAP_BLOCKSIZE)
352 // If this is true, inexistent block will be made from scratch
353 bool generate = d <= d_max_gen;
356 /*// Limit the generating area vertically to 2/3
357 if(abs(p.Y - center.Y) > d_max_gen - d_max_gen / 3)
360 // Limit the send area vertically to 1/2
361 if(abs(p.Y - center.Y) > d_max / 2)
367 If block is far away, don't generate it unless it is
373 // Block center y in nodes
374 f32 y = (f32)(p.Y * MAP_BLOCKSIZE + MAP_BLOCKSIZE/2);
375 // Don't generate if it's very high or very low
376 if(y < -64 || y > 64)
380 v2s16 p2d_nodes_center(
384 // Get ground height in nodes
385 s16 gh = server->m_env->getServerMap().findGroundLevel(
388 // If differs a lot, don't generate
389 if(fabs(gh - y) > MAP_BLOCKSIZE*2)
391 // Actually, don't even send it
397 //infostream<<"d="<<d<<std::endl;
400 Don't generate or send if not in sight
401 FIXME This only works if the client uses a small enough
402 FOV setting. The default of 72 degrees is fine.
405 float camera_fov = (72.0*M_PI/180) * 4./3.;
406 if(isBlockInSight(p, camera_pos, camera_dir, camera_fov, 10000*BS) == false)
412 Don't send already sent blocks
415 if(m_blocks_sent.find(p) != m_blocks_sent.end())
422 Check if map has this block
424 MapBlock *block = server->m_env->getMap().getBlockNoCreateNoEx(p);
426 bool surely_not_found_on_disk = false;
427 bool block_is_invalid = false;
430 // Reset usage timer, this block will be of use in the future.
431 block->resetUsageTimer();
433 // Block is dummy if data doesn't exist.
434 // It means it has been not found from disk and not generated
437 surely_not_found_on_disk = true;
440 // Block is valid if lighting is up-to-date and data exists
441 if(block->isValid() == false)
443 block_is_invalid = true;
446 /*if(block->isFullyGenerated() == false)
448 block_is_invalid = true;
453 ServerMap *map = (ServerMap*)(&server->m_env->getMap());
454 v2s16 chunkpos = map->sector_to_chunk(p2d);
455 if(map->chunkNonVolatile(chunkpos) == false)
456 block_is_invalid = true;
458 if(block->isGenerated() == false)
459 block_is_invalid = true;
462 If block is not close, don't send it unless it is near
465 Block is near ground level if night-time mesh
466 differs from day-time mesh.
470 if(block->getDayNightDiff() == false)
477 If block has been marked to not exist on disk (dummy)
478 and generating new ones is not wanted, skip block.
480 if(generate == false && surely_not_found_on_disk == true)
487 Add inexistent block to emerge queue.
489 if(block == NULL || surely_not_found_on_disk || block_is_invalid)
491 /* //TODO: Get value from somewhere
492 // Allow only one block in emerge queue
493 //if(server->m_emerge_queue.peerItemCount(peer_id) < 1)
494 // Allow two blocks in queue per client
495 //if(server->m_emerge_queue.peerItemCount(peer_id) < 2)
497 // Make it more responsive when needing to generate stuff
498 if(surely_not_found_on_disk)
500 if(server->m_emerge_queue.peerItemCount(peer_id) < max_emerge)
502 //infostream<<"Adding block to emerge queue"<<std::endl;
504 // Add it to the emerge queue and trigger the thread
507 if(generate == false)
508 flags |= BLOCK_EMERGE_FLAG_FROMDISK;
510 server->m_emerge_queue.addBlock(peer_id, p, flags);
511 server->m_emergethread.trigger();
513 if(nearest_emerged_d == -1)
514 nearest_emerged_d = d;
516 if(nearest_emergefull_d == -1)
517 nearest_emergefull_d = d;
518 goto queue_full_break;
522 if (server->m_emerge->enqueueBlockEmerge(peer_id, p, generate)) {
523 if (nearest_emerged_d == -1)
524 nearest_emerged_d = d;
526 if (nearest_emergefull_d == -1)
527 nearest_emergefull_d = d;
528 goto queue_full_break;
535 if(nearest_sent_d == -1)
539 Add block to send queue
542 /*errorstream<<"sending from d="<<d<<" to "
543 <<server->getPlayerName(peer_id)<<std::endl;*/
545 PrioritySortedBlockTransfer q((float)d, p, peer_id);
549 num_blocks_selected += 1;
554 //infostream<<"Stopped at "<<d<<std::endl;
556 // If nothing was found for sending and nothing was queued for
557 // emerging, continue next time browsing from here
558 if(nearest_emerged_d != -1){
559 new_nearest_unsent_d = nearest_emerged_d;
560 } else if(nearest_emergefull_d != -1){
561 new_nearest_unsent_d = nearest_emergefull_d;
563 if(d > g_settings->getS16("max_block_send_distance")){
564 new_nearest_unsent_d = 0;
565 m_nothing_to_send_pause_timer = 2.0;
566 /*infostream<<"GetNextBlocks(): d wrapped around for "
567 <<server->getPlayerName(peer_id)
568 <<"; setting to 0 and pausing"<<std::endl;*/
570 if(nearest_sent_d != -1)
571 new_nearest_unsent_d = nearest_sent_d;
573 new_nearest_unsent_d = d;
577 if(new_nearest_unsent_d != -1)
578 m_nearest_unsent_d = new_nearest_unsent_d;
580 /*timer_result = timer.stop(true);
581 if(timer_result != 0)
582 infostream<<"GetNextBlocks timeout: "<<timer_result<<" (!=0)"<<std::endl;*/
585 void RemoteClient::GotBlock(v3s16 p)
587 if(m_blocks_sending.find(p) != m_blocks_sending.end())
588 m_blocks_sending.erase(p);
591 /*infostream<<"RemoteClient::GotBlock(): Didn't find in"
592 " m_blocks_sending"<<std::endl;*/
593 m_excess_gotblocks++;
595 m_blocks_sent.insert(p);
598 void RemoteClient::SentBlock(v3s16 p)
600 if(m_blocks_sending.find(p) == m_blocks_sending.end())
601 m_blocks_sending[p] = 0.0;
603 infostream<<"RemoteClient::SentBlock(): Sent block"
604 " already in m_blocks_sending"<<std::endl;
607 void RemoteClient::SetBlockNotSent(v3s16 p)
609 m_nearest_unsent_d = 0;
611 if(m_blocks_sending.find(p) != m_blocks_sending.end())
612 m_blocks_sending.erase(p);
613 if(m_blocks_sent.find(p) != m_blocks_sent.end())
614 m_blocks_sent.erase(p);
617 void RemoteClient::SetBlocksNotSent(std::map<v3s16, MapBlock*> &blocks)
619 m_nearest_unsent_d = 0;
621 for(std::map<v3s16, MapBlock*>::iterator
623 i != blocks.end(); ++i)
627 if(m_blocks_sending.find(p) != m_blocks_sending.end())
628 m_blocks_sending.erase(p);
629 if(m_blocks_sent.find(p) != m_blocks_sent.end())
630 m_blocks_sent.erase(p);
639 const std::string &path_world,
640 const SubgameSpec &gamespec,
641 bool simple_singleplayer_mode
643 m_path_world(path_world),
644 m_gamespec(gamespec),
645 m_simple_singleplayer_mode(simple_singleplayer_mode),
646 m_async_fatal_error(""),
648 m_con(PROTOCOL_ID, 512, CONNECTION_TIMEOUT,
649 g_settings->getBool("enable_ipv6") && g_settings->getBool("ipv6_server"), this),
652 m_rollback_sink_enabled(true),
653 m_enable_rollback_recording(false),
656 m_itemdef(createItemDefManager()),
657 m_nodedef(createNodeDefManager()),
658 m_craftdef(createCraftDefManager()),
659 m_event(new EventManager()),
661 m_time_of_day_send_timer(0),
663 m_shutdown_requested(false),
664 m_ignore_map_edit_events(false),
665 m_ignore_map_edit_events_peer_id(0)
667 m_liquid_transform_timer = 0.0;
668 m_liquid_transform_every = 1.0;
669 m_print_info_timer = 0.0;
670 m_masterserver_timer = 0.0;
671 m_objectdata_timer = 0.0;
672 m_emergethread_trigger_timer = 0.0;
673 m_savemap_timer = 0.0;
674 m_clients_number = 0;
678 m_step_dtime_mutex.Init();
682 throw ServerError("Supplied empty world path");
684 if(!gamespec.isValid())
685 throw ServerError("Supplied invalid gamespec");
687 infostream<<"Server created for gameid \""<<m_gamespec.id<<"\"";
688 if(m_simple_singleplayer_mode)
689 infostream<<" in simple singleplayer mode"<<std::endl;
691 infostream<<std::endl;
692 infostream<<"- world: "<<m_path_world<<std::endl;
693 infostream<<"- game: "<<m_gamespec.path<<std::endl;
695 // Initialize default settings and override defaults with those provided
697 set_default_settings(g_settings);
698 Settings gamedefaults;
699 getGameMinetestConfig(gamespec.path, gamedefaults);
700 override_default_settings(g_settings, &gamedefaults);
702 // Create server thread
703 m_thread = new ServerThread(this);
705 // Create emerge manager
706 m_emerge = new EmergeManager(this);
708 // Create ban manager
709 std::string ban_path = m_path_world+DIR_DELIM+"ipban.txt";
710 m_banmanager = new BanManager(ban_path);
712 // Create rollback manager
713 std::string rollback_path = m_path_world+DIR_DELIM+"rollback.txt";
714 m_rollback = createRollbackManager(rollback_path, this);
716 // Create world if it doesn't exist
717 if(!initializeWorld(m_path_world, m_gamespec.id))
718 throw ServerError("Failed to initialize world");
720 ModConfiguration modconf(m_path_world);
721 m_mods = modconf.getMods();
722 std::vector<ModSpec> unsatisfied_mods = modconf.getUnsatisfiedMods();
723 // complain about mods with unsatisfied dependencies
724 if(!modconf.isConsistent())
726 for(std::vector<ModSpec>::iterator it = unsatisfied_mods.begin();
727 it != unsatisfied_mods.end(); ++it)
730 errorstream << "mod \"" << mod.name << "\" has unsatisfied dependencies: ";
731 for(std::set<std::string>::iterator dep_it = mod.unsatisfied_depends.begin();
732 dep_it != mod.unsatisfied_depends.end(); ++dep_it)
733 errorstream << " \"" << *dep_it << "\"";
734 errorstream << std::endl;
738 Settings worldmt_settings;
739 std::string worldmt = m_path_world + DIR_DELIM + "world.mt";
740 worldmt_settings.readConfigFile(worldmt.c_str());
741 std::vector<std::string> names = worldmt_settings.getNames();
742 std::set<std::string> load_mod_names;
743 for(std::vector<std::string>::iterator it = names.begin();
744 it != names.end(); ++it)
746 std::string name = *it;
747 if(name.compare(0,9,"load_mod_")==0 && worldmt_settings.getBool(name))
748 load_mod_names.insert(name.substr(9));
750 // complain about mods declared to be loaded, but not found
751 for(std::vector<ModSpec>::iterator it = m_mods.begin();
752 it != m_mods.end(); ++it)
753 load_mod_names.erase((*it).name);
754 for(std::vector<ModSpec>::iterator it = unsatisfied_mods.begin();
755 it != unsatisfied_mods.end(); ++it)
756 load_mod_names.erase((*it).name);
757 if(!load_mod_names.empty())
759 errorstream << "The following mods could not be found:";
760 for(std::set<std::string>::iterator it = load_mod_names.begin();
761 it != load_mod_names.end(); ++it)
762 errorstream << " \"" << (*it) << "\"";
763 errorstream << std::endl;
766 // Path to builtin.lua
767 std::string builtinpath = getBuiltinLuaPath() + DIR_DELIM + "builtin.lua";
770 JMutexAutoLock envlock(m_env_mutex);
771 JMutexAutoLock conlock(m_con_mutex);
773 // Initialize scripting
775 infostream<<"Server: Initializing Lua"<<std::endl;
777 m_script = new GameScripting(this);
780 // Load and run builtin.lua
781 infostream<<"Server: Loading builtin.lua [\""
782 <<builtinpath<<"\"]"<<std::endl;
783 bool success = m_script->loadMod(builtinpath, "__builtin");
785 errorstream<<"Server: Failed to load and run "
786 <<builtinpath<<std::endl;
787 throw ModError("Failed to load and run "+builtinpath);
790 infostream<<"Server: Loading mods: ";
791 for(std::vector<ModSpec>::iterator i = m_mods.begin();
792 i != m_mods.end(); i++){
793 const ModSpec &mod = *i;
794 infostream<<mod.name<<" ";
796 infostream<<std::endl;
797 // Load and run "mod" scripts
798 for(std::vector<ModSpec>::iterator i = m_mods.begin();
799 i != m_mods.end(); i++){
800 const ModSpec &mod = *i;
801 std::string scriptpath = mod.path + DIR_DELIM + "init.lua";
802 infostream<<" ["<<padStringRight(mod.name, 12)<<"] [\""
803 <<scriptpath<<"\"]"<<std::endl;
804 bool success = m_script->loadMod(scriptpath, mod.name);
806 errorstream<<"Server: Failed to load and run "
807 <<scriptpath<<std::endl;
808 throw ModError("Failed to load and run "+scriptpath);
812 // Read Textures and calculate sha1 sums
815 // Apply item aliases in the node definition manager
816 m_nodedef->updateAliases(m_itemdef);
818 // Initialize Environment
819 ServerMap *servermap = new ServerMap(path_world, this, m_emerge);
820 m_env = new ServerEnvironment(servermap, m_script, this, m_emerge);
822 // Run some callbacks after the MG params have been set up but before activation
823 MapgenParams *mgparams = servermap->getMapgenParams();
824 m_script->environment_OnMapgenInit(mgparams);
826 // Initialize mapgens
827 m_emerge->initMapgens(mgparams);
829 // Give environment reference to scripting api
830 m_script->initializeEnvironment(m_env);
832 // Register us to receive map edit events
833 servermap->addEventReceiver(this);
835 // If file exists, load environment metadata
836 if(fs::PathExists(m_path_world+DIR_DELIM+"env_meta.txt"))
838 infostream<<"Server: Loading environment metadata"<<std::endl;
839 m_env->loadMeta(m_path_world);
843 infostream<<"Server: Loading players"<<std::endl;
844 m_env->deSerializePlayers(m_path_world);
847 Add some test ActiveBlockModifiers to environment
849 add_legacy_abms(m_env, m_nodedef);
851 m_liquid_transform_every = g_settings->getFloat("liquid_update");
856 infostream<<"Server destructing"<<std::endl;
859 Send shutdown message
862 JMutexAutoLock conlock(m_con_mutex);
864 std::wstring line = L"*** Server shutting down";
867 Send the message to clients
869 for(std::map<u16, RemoteClient*>::iterator
870 i = m_clients.begin();
871 i != m_clients.end(); ++i)
873 // Get client and check that it is valid
874 RemoteClient *client = i->second;
875 assert(client->peer_id == i->first);
876 if(client->serialization_version == SER_FMT_VER_INVALID)
880 SendChatMessage(client->peer_id, line);
882 catch(con::PeerNotFoundException &e)
888 JMutexAutoLock envlock(m_env_mutex);
889 JMutexAutoLock conlock(m_con_mutex);
892 Execute script shutdown hooks
894 m_script->on_shutdown();
898 JMutexAutoLock envlock(m_env_mutex);
903 infostream<<"Server: Saving players"<<std::endl;
904 m_env->serializePlayers(m_path_world);
907 Save environment metadata
909 infostream<<"Server: Saving environment metadata"<<std::endl;
910 m_env->saveMeta(m_path_world);
919 //shutdown all emerge threads first!
926 JMutexAutoLock clientslock(m_con_mutex);
928 for(std::map<u16, RemoteClient*>::iterator
929 i = m_clients.begin();
930 i != m_clients.end(); ++i)
938 // Delete things in the reverse order of creation
947 // Deinitialize scripting
948 infostream<<"Server: Deinitializing scripting"<<std::endl;
951 // Delete detached inventories
953 for(std::map<std::string, Inventory*>::iterator
954 i = m_detached_inventories.begin();
955 i != m_detached_inventories.end(); i++){
961 void Server::start(unsigned short port)
963 DSTACK(__FUNCTION_NAME);
964 infostream<<"Starting server on port "<<port<<"..."<<std::endl;
966 // Stop thread if already running
969 // Initialize connection
970 m_con.SetTimeoutMs(30);
974 m_thread->setRun(true);
977 // ASCII art for the win!
979 <<" .__ __ __ "<<std::endl
980 <<" _____ |__| ____ _____/ |_ ____ _______/ |_ "<<std::endl
981 <<" / \\| |/ \\_/ __ \\ __\\/ __ \\ / ___/\\ __\\"<<std::endl
982 <<"| Y Y \\ | | \\ ___/| | \\ ___/ \\___ \\ | | "<<std::endl
983 <<"|__|_| /__|___| /\\___ >__| \\___ >____ > |__| "<<std::endl
984 <<" \\/ \\/ \\/ \\/ \\/ "<<std::endl;
985 actionstream<<"World at ["<<m_path_world<<"]"<<std::endl;
986 actionstream<<"Server for gameid=\""<<m_gamespec.id
987 <<"\" listening on port "<<port<<"."<<std::endl;
992 DSTACK(__FUNCTION_NAME);
994 infostream<<"Server: Stopping and waiting threads"<<std::endl;
996 // Stop threads (set run=false first so both start stopping)
997 m_thread->setRun(false);
998 //m_emergethread.setRun(false);
1000 //m_emergethread.stop();
1002 infostream<<"Server: Threads stopped"<<std::endl;
1005 void Server::step(float dtime)
1007 DSTACK(__FUNCTION_NAME);
1012 JMutexAutoLock lock(m_step_dtime_mutex);
1013 m_step_dtime += dtime;
1015 // Throw if fatal error occurred in thread
1016 std::string async_err = m_async_fatal_error.get();
1017 if(async_err != ""){
1018 throw ServerError(async_err);
1022 void Server::AsyncRunStep()
1024 DSTACK(__FUNCTION_NAME);
1026 g_profiler->add("Server::AsyncRunStep (num)", 1);
1030 JMutexAutoLock lock1(m_step_dtime_mutex);
1031 dtime = m_step_dtime;
1035 // Send blocks to clients
1042 g_profiler->add("Server::AsyncRunStep with dtime (num)", 1);
1044 //infostream<<"Server steps "<<dtime<<std::endl;
1045 //infostream<<"Server::AsyncRunStep(): dtime="<<dtime<<std::endl;
1048 JMutexAutoLock lock1(m_step_dtime_mutex);
1049 m_step_dtime -= dtime;
1056 m_uptime.set(m_uptime.get() + dtime);
1060 // Process connection's timeouts
1061 JMutexAutoLock lock2(m_con_mutex);
1062 ScopeProfiler sp(g_profiler, "Server: connection timeout processing");
1063 m_con.RunTimeouts(dtime);
1067 // This has to be called so that the client list gets synced
1068 // with the peer list of the connection
1069 handlePeerChanges();
1073 Update time of day and overall game time
1076 JMutexAutoLock envlock(m_env_mutex);
1078 m_env->setTimeOfDaySpeed(g_settings->getFloat("time_speed"));
1081 Send to clients at constant intervals
1084 m_time_of_day_send_timer -= dtime;
1085 if(m_time_of_day_send_timer < 0.0)
1087 m_time_of_day_send_timer = g_settings->getFloat("time_send_interval");
1089 //JMutexAutoLock envlock(m_env_mutex);
1090 JMutexAutoLock conlock(m_con_mutex);
1092 u16 time = m_env->getTimeOfDay();
1093 float time_speed = g_settings->getFloat("time_speed");
1095 for(std::map<u16, RemoteClient*>::iterator
1096 i = m_clients.begin();
1097 i != m_clients.end(); ++i)
1099 RemoteClient *client = i->second;
1100 SendTimeOfDay(client->peer_id, time, time_speed);
1106 JMutexAutoLock lock(m_env_mutex);
1107 // Figure out and report maximum lag to environment
1108 float max_lag = m_env->getMaxLagEstimate();
1109 max_lag *= 0.9998; // Decrease slowly (about half per 5 minutes)
1110 if(dtime > max_lag){
1111 if(dtime > 0.1 && dtime > max_lag * 2.0)
1112 infostream<<"Server: Maximum lag peaked to "<<dtime
1116 m_env->reportMaxLagEstimate(max_lag);
1118 ScopeProfiler sp(g_profiler, "SEnv step");
1119 ScopeProfiler sp2(g_profiler, "SEnv step avg", SPT_AVG);
1123 const float map_timer_and_unload_dtime = 2.92;
1124 if(m_map_timer_and_unload_interval.step(dtime, map_timer_and_unload_dtime))
1126 JMutexAutoLock lock(m_env_mutex);
1127 // Run Map's timers and unload unused data
1128 ScopeProfiler sp(g_profiler, "Server: map timer and unload");
1129 m_env->getMap().timerUpdate(map_timer_and_unload_dtime,
1130 g_settings->getFloat("server_unload_unused_data_timeout"));
1141 JMutexAutoLock lock(m_env_mutex);
1142 JMutexAutoLock lock2(m_con_mutex);
1144 ScopeProfiler sp(g_profiler, "Server: handle players");
1146 for(std::map<u16, RemoteClient*>::iterator
1147 i = m_clients.begin();
1148 i != m_clients.end(); ++i)
1150 RemoteClient *client = i->second;
1151 PlayerSAO *playersao = getPlayerSAO(client->peer_id);
1152 if(playersao == NULL)
1156 Handle player HPs (die if hp=0)
1158 if(playersao->m_hp_not_sent && g_settings->getBool("enable_damage"))
1160 if(playersao->getHP() == 0)
1161 DiePlayer(client->peer_id);
1163 SendPlayerHP(client->peer_id);
1167 Send player breath if changed
1169 if(playersao->m_breath_not_sent){
1170 SendPlayerBreath(client->peer_id);
1174 Send player inventories if necessary
1176 if(playersao->m_moved){
1177 SendMovePlayer(client->peer_id);
1178 playersao->m_moved = false;
1180 if(playersao->m_inventory_not_sent){
1181 UpdateCrafting(client->peer_id);
1182 SendInventory(client->peer_id);
1187 /* Transform liquids */
1188 m_liquid_transform_timer += dtime;
1189 if(m_liquid_transform_timer >= m_liquid_transform_every)
1191 m_liquid_transform_timer -= m_liquid_transform_every;
1193 JMutexAutoLock lock(m_env_mutex);
1195 ScopeProfiler sp(g_profiler, "Server: liquid transform");
1197 std::map<v3s16, MapBlock*> modified_blocks;
1198 m_env->getMap().transformLiquids(modified_blocks);
1203 core::map<v3s16, MapBlock*> lighting_modified_blocks;
1204 ServerMap &map = ((ServerMap&)m_env->getMap());
1205 map.updateLighting(modified_blocks, lighting_modified_blocks);
1207 // Add blocks modified by lighting to modified_blocks
1208 for(core::map<v3s16, MapBlock*>::Iterator
1209 i = lighting_modified_blocks.getIterator();
1210 i.atEnd() == false; i++)
1212 MapBlock *block = i.getNode()->getValue();
1213 modified_blocks.insert(block->getPos(), block);
1217 Set the modified blocks unsent for all the clients
1220 JMutexAutoLock lock2(m_con_mutex);
1222 for(std::map<u16, RemoteClient*>::iterator
1223 i = m_clients.begin();
1224 i != m_clients.end(); ++i)
1226 RemoteClient *client = i->second;
1228 if(modified_blocks.size() > 0)
1230 // Remove block from sent history
1231 client->SetBlocksNotSent(modified_blocks);
1236 // Periodically print some info
1238 float &counter = m_print_info_timer;
1244 JMutexAutoLock lock2(m_con_mutex);
1245 m_clients_number = 0;
1246 if(m_clients.size() != 0)
1247 infostream<<"Players:"<<std::endl;
1248 for(std::map<u16, RemoteClient*>::iterator
1249 i = m_clients.begin();
1250 i != m_clients.end(); ++i)
1252 //u16 peer_id = i.getNode()->getKey();
1253 RemoteClient *client = i->second;
1254 Player *player = m_env->getPlayer(client->peer_id);
1257 infostream<<"* "<<player->getName()<<"\t";
1258 client->PrintInfo(infostream);
1266 // send masterserver announce
1268 float &counter = m_masterserver_timer;
1269 if(!isSingleplayer() && (!counter || counter >= 300.0) && g_settings->getBool("server_announce") == true)
1271 ServerList::sendAnnounce(!counter ? "start" : "update", m_clients_number, m_uptime.get(), m_gamespec.id, m_mods);
1278 //if(g_settings->getBool("enable_experimental"))
1282 Check added and deleted active objects
1285 //infostream<<"Server: Checking added and deleted active objects"<<std::endl;
1286 JMutexAutoLock envlock(m_env_mutex);
1287 JMutexAutoLock conlock(m_con_mutex);
1289 ScopeProfiler sp(g_profiler, "Server: checking added and deleted objs");
1291 // Radius inside which objects are active
1292 s16 radius = g_settings->getS16("active_object_send_range_blocks");
1293 radius *= MAP_BLOCKSIZE;
1295 for(std::map<u16, RemoteClient*>::iterator
1296 i = m_clients.begin();
1297 i != m_clients.end(); ++i)
1299 RemoteClient *client = i->second;
1301 // If definitions and textures have not been sent, don't
1302 // send objects either
1303 if(!client->definitions_sent)
1306 Player *player = m_env->getPlayer(client->peer_id);
1309 // This can happen if the client timeouts somehow
1310 /*infostream<<"WARNING: "<<__FUNCTION_NAME<<": Client "
1312 <<" has no associated player"<<std::endl;*/
1315 v3s16 pos = floatToInt(player->getPosition(), BS);
1317 std::set<u16> removed_objects;
1318 std::set<u16> added_objects;
1319 m_env->getRemovedActiveObjects(pos, radius,
1320 client->m_known_objects, removed_objects);
1321 m_env->getAddedActiveObjects(pos, radius,
1322 client->m_known_objects, added_objects);
1324 // Ignore if nothing happened
1325 if(removed_objects.size() == 0 && added_objects.size() == 0)
1327 //infostream<<"active objects: none changed"<<std::endl;
1331 std::string data_buffer;
1335 // Handle removed objects
1336 writeU16((u8*)buf, removed_objects.size());
1337 data_buffer.append(buf, 2);
1338 for(std::set<u16>::iterator
1339 i = removed_objects.begin();
1340 i != removed_objects.end(); ++i)
1344 ServerActiveObject* obj = m_env->getActiveObject(id);
1346 // Add to data buffer for sending
1347 writeU16((u8*)buf, id);
1348 data_buffer.append(buf, 2);
1350 // Remove from known objects
1351 client->m_known_objects.erase(id);
1353 if(obj && obj->m_known_by_count > 0)
1354 obj->m_known_by_count--;
1357 // Handle added objects
1358 writeU16((u8*)buf, added_objects.size());
1359 data_buffer.append(buf, 2);
1360 for(std::set<u16>::iterator
1361 i = added_objects.begin();
1362 i != added_objects.end(); ++i)
1366 ServerActiveObject* obj = m_env->getActiveObject(id);
1369 u8 type = ACTIVEOBJECT_TYPE_INVALID;
1371 infostream<<"WARNING: "<<__FUNCTION_NAME
1372 <<": NULL object"<<std::endl;
1374 type = obj->getSendType();
1376 // Add to data buffer for sending
1377 writeU16((u8*)buf, id);
1378 data_buffer.append(buf, 2);
1379 writeU8((u8*)buf, type);
1380 data_buffer.append(buf, 1);
1383 data_buffer.append(serializeLongString(
1384 obj->getClientInitializationData(client->net_proto_version)));
1386 data_buffer.append(serializeLongString(""));
1388 // Add to known objects
1389 client->m_known_objects.insert(id);
1392 obj->m_known_by_count++;
1396 SharedBuffer<u8> reply(2 + data_buffer.size());
1397 writeU16(&reply[0], TOCLIENT_ACTIVE_OBJECT_REMOVE_ADD);
1398 memcpy((char*)&reply[2], data_buffer.c_str(),
1399 data_buffer.size());
1401 m_con.Send(client->peer_id, 0, reply, true);
1403 verbosestream<<"Server: Sent object remove/add: "
1404 <<removed_objects.size()<<" removed, "
1405 <<added_objects.size()<<" added, "
1406 <<"packet size is "<<reply.getSize()<<std::endl;
1411 Collect a list of all the objects known by the clients
1412 and report it back to the environment.
1415 core::map<u16, bool> all_known_objects;
1417 for(core::map<u16, RemoteClient*>::Iterator
1418 i = m_clients.getIterator();
1419 i.atEnd() == false; i++)
1421 RemoteClient *client = i.getNode()->getValue();
1422 // Go through all known objects of client
1423 for(core::map<u16, bool>::Iterator
1424 i = client->m_known_objects.getIterator();
1425 i.atEnd()==false; i++)
1427 u16 id = i.getNode()->getKey();
1428 all_known_objects[id] = true;
1432 m_env->setKnownActiveObjects(whatever);
1438 Send object messages
1441 JMutexAutoLock envlock(m_env_mutex);
1442 JMutexAutoLock conlock(m_con_mutex);
1444 ScopeProfiler sp(g_profiler, "Server: sending object messages");
1447 // Value = data sent by object
1448 std::map<u16, std::list<ActiveObjectMessage>* > buffered_messages;
1450 // Get active object messages from environment
1453 ActiveObjectMessage aom = m_env->getActiveObjectMessage();
1457 std::list<ActiveObjectMessage>* message_list = NULL;
1458 std::map<u16, std::list<ActiveObjectMessage>* >::iterator n;
1459 n = buffered_messages.find(aom.id);
1460 if(n == buffered_messages.end())
1462 message_list = new std::list<ActiveObjectMessage>;
1463 buffered_messages[aom.id] = message_list;
1467 message_list = n->second;
1469 message_list->push_back(aom);
1472 // Route data to every client
1473 for(std::map<u16, RemoteClient*>::iterator
1474 i = m_clients.begin();
1475 i != m_clients.end(); ++i)
1477 RemoteClient *client = i->second;
1478 std::string reliable_data;
1479 std::string unreliable_data;
1480 // Go through all objects in message buffer
1481 for(std::map<u16, std::list<ActiveObjectMessage>* >::iterator
1482 j = buffered_messages.begin();
1483 j != buffered_messages.end(); ++j)
1485 // If object is not known by client, skip it
1487 if(client->m_known_objects.find(id) == client->m_known_objects.end())
1489 // Get message list of object
1490 std::list<ActiveObjectMessage>* list = j->second;
1491 // Go through every message
1492 for(std::list<ActiveObjectMessage>::iterator
1493 k = list->begin(); k != list->end(); ++k)
1495 // Compose the full new data with header
1496 ActiveObjectMessage aom = *k;
1497 std::string new_data;
1500 writeU16((u8*)&buf[0], aom.id);
1501 new_data.append(buf, 2);
1503 new_data += serializeString(aom.datastring);
1504 // Add data to buffer
1506 reliable_data += new_data;
1508 unreliable_data += new_data;
1512 reliable_data and unreliable_data are now ready.
1515 if(reliable_data.size() > 0)
1517 SharedBuffer<u8> reply(2 + reliable_data.size());
1518 writeU16(&reply[0], TOCLIENT_ACTIVE_OBJECT_MESSAGES);
1519 memcpy((char*)&reply[2], reliable_data.c_str(),
1520 reliable_data.size());
1522 m_con.Send(client->peer_id, 0, reply, true);
1524 if(unreliable_data.size() > 0)
1526 SharedBuffer<u8> reply(2 + unreliable_data.size());
1527 writeU16(&reply[0], TOCLIENT_ACTIVE_OBJECT_MESSAGES);
1528 memcpy((char*)&reply[2], unreliable_data.c_str(),
1529 unreliable_data.size());
1530 // Send as unreliable
1531 m_con.Send(client->peer_id, 0, reply, false);
1534 /*if(reliable_data.size() > 0 || unreliable_data.size() > 0)
1536 infostream<<"Server: Size of object message data: "
1537 <<"reliable: "<<reliable_data.size()
1538 <<", unreliable: "<<unreliable_data.size()
1543 // Clear buffered_messages
1544 for(std::map<u16, std::list<ActiveObjectMessage>* >::iterator
1545 i = buffered_messages.begin();
1546 i != buffered_messages.end(); ++i)
1552 } // enable_experimental
1555 Send queued-for-sending map edit events.
1558 // We will be accessing the environment and the connection
1559 JMutexAutoLock lock(m_env_mutex);
1560 JMutexAutoLock conlock(m_con_mutex);
1562 // Don't send too many at a time
1565 // Single change sending is disabled if queue size is not small
1566 bool disable_single_change_sending = false;
1567 if(m_unsent_map_edit_queue.size() >= 4)
1568 disable_single_change_sending = true;
1570 int event_count = m_unsent_map_edit_queue.size();
1572 // We'll log the amount of each
1575 while(m_unsent_map_edit_queue.size() != 0)
1577 MapEditEvent* event = m_unsent_map_edit_queue.pop_front();
1579 // Players far away from the change are stored here.
1580 // Instead of sending the changes, MapBlocks are set not sent
1582 std::list<u16> far_players;
1584 if(event->type == MEET_ADDNODE)
1586 //infostream<<"Server: MEET_ADDNODE"<<std::endl;
1587 prof.add("MEET_ADDNODE", 1);
1588 if(disable_single_change_sending)
1589 sendAddNode(event->p, event->n, event->already_known_by_peer,
1592 sendAddNode(event->p, event->n, event->already_known_by_peer,
1595 else if(event->type == MEET_REMOVENODE)
1597 //infostream<<"Server: MEET_REMOVENODE"<<std::endl;
1598 prof.add("MEET_REMOVENODE", 1);
1599 if(disable_single_change_sending)
1600 sendRemoveNode(event->p, event->already_known_by_peer,
1603 sendRemoveNode(event->p, event->already_known_by_peer,
1606 else if(event->type == MEET_BLOCK_NODE_METADATA_CHANGED)
1608 infostream<<"Server: MEET_BLOCK_NODE_METADATA_CHANGED"<<std::endl;
1609 prof.add("MEET_BLOCK_NODE_METADATA_CHANGED", 1);
1610 setBlockNotSent(event->p);
1612 else if(event->type == MEET_OTHER)
1614 infostream<<"Server: MEET_OTHER"<<std::endl;
1615 prof.add("MEET_OTHER", 1);
1616 for(std::set<v3s16>::iterator
1617 i = event->modified_blocks.begin();
1618 i != event->modified_blocks.end(); ++i)
1620 setBlockNotSent(*i);
1625 prof.add("unknown", 1);
1626 infostream<<"WARNING: Server: Unknown MapEditEvent "
1627 <<((u32)event->type)<<std::endl;
1631 Set blocks not sent to far players
1633 if(far_players.size() > 0)
1635 // Convert list format to that wanted by SetBlocksNotSent
1636 std::map<v3s16, MapBlock*> modified_blocks2;
1637 for(std::set<v3s16>::iterator
1638 i = event->modified_blocks.begin();
1639 i != event->modified_blocks.end(); ++i)
1641 modified_blocks2[*i] =
1642 m_env->getMap().getBlockNoCreateNoEx(*i);
1644 // Set blocks not sent
1645 for(std::list<u16>::iterator
1646 i = far_players.begin();
1647 i != far_players.end(); ++i)
1650 RemoteClient *client = getClient(peer_id);
1653 client->SetBlocksNotSent(modified_blocks2);
1659 /*// Don't send too many at a time
1661 if(count >= 1 && m_unsent_map_edit_queue.size() < 100)
1665 if(event_count >= 5){
1666 infostream<<"Server: MapEditEvents:"<<std::endl;
1667 prof.print(infostream);
1668 } else if(event_count != 0){
1669 verbosestream<<"Server: MapEditEvents:"<<std::endl;
1670 prof.print(verbosestream);
1676 Trigger emergethread (it somehow gets to a non-triggered but
1677 bysy state sometimes)
1680 float &counter = m_emergethread_trigger_timer;
1686 m_emerge->triggerAllThreads();
1688 // Update m_enable_rollback_recording here too
1689 m_enable_rollback_recording =
1690 g_settings->getBool("enable_rollback_recording");
1694 // Save map, players and auth stuff
1696 float &counter = m_savemap_timer;
1698 if(counter >= g_settings->getFloat("server_map_save_interval"))
1701 JMutexAutoLock lock(m_env_mutex);
1703 ScopeProfiler sp(g_profiler, "Server: saving stuff");
1706 if(m_banmanager->isModified())
1707 m_banmanager->save();
1709 // Save changed parts of map
1710 m_env->getMap().save(MOD_STATE_WRITE_NEEDED);
1713 m_env->serializePlayers(m_path_world);
1715 // Save environment metadata
1716 m_env->saveMeta(m_path_world);
1721 void Server::Receive()
1723 DSTACK(__FUNCTION_NAME);
1724 SharedBuffer<u8> data;
1729 JMutexAutoLock conlock(m_con_mutex);
1730 datasize = m_con.Receive(peer_id, data);
1733 // This has to be called so that the client list gets synced
1734 // with the peer list of the connection
1735 handlePeerChanges();
1737 ProcessData(*data, datasize, peer_id);
1739 catch(con::InvalidIncomingDataException &e)
1741 infostream<<"Server::Receive(): "
1742 "InvalidIncomingDataException: what()="
1743 <<e.what()<<std::endl;
1745 catch(con::PeerNotFoundException &e)
1747 //NOTE: This is not needed anymore
1749 // The peer has been disconnected.
1750 // Find the associated player and remove it.
1752 /*JMutexAutoLock envlock(m_env_mutex);
1754 infostream<<"ServerThread: peer_id="<<peer_id
1755 <<" has apparently closed connection. "
1756 <<"Removing player."<<std::endl;
1758 m_env->removePlayer(peer_id);*/
1762 void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
1764 DSTACK(__FUNCTION_NAME);
1765 // Environment is locked first.
1766 JMutexAutoLock envlock(m_env_mutex);
1767 JMutexAutoLock conlock(m_con_mutex);
1769 ScopeProfiler sp(g_profiler, "Server::ProcessData");
1773 Address address = m_con.GetPeerAddress(peer_id);
1774 addr_s = address.serializeString();
1776 // drop player if is ip is banned
1777 if(m_banmanager->isIpBanned(addr_s)){
1778 infostream<<"Server: A banned client tried to connect from "
1779 <<addr_s<<"; banned name was "
1780 <<m_banmanager->getBanName(addr_s)<<std::endl;
1781 // This actually doesn't seem to transfer to the client
1782 DenyAccess(peer_id, L"Your ip is banned. Banned name was "
1783 +narrow_to_wide(m_banmanager->getBanName(addr_s)));
1784 m_con.DeletePeer(peer_id);
1788 catch(con::PeerNotFoundException &e)
1790 infostream<<"Server::ProcessData(): Cancelling: peer "
1791 <<peer_id<<" not found"<<std::endl;
1795 u8 peer_ser_ver = getClient(peer_id)->serialization_version;
1803 ToServerCommand command = (ToServerCommand)readU16(&data[0]);
1805 if(command == TOSERVER_INIT)
1807 // [0] u16 TOSERVER_INIT
1808 // [2] u8 SER_FMT_VER_HIGHEST_READ
1809 // [3] u8[20] player_name
1810 // [23] u8[28] password <--- can be sent without this, from old versions
1812 if(datasize < 2+1+PLAYERNAME_SIZE)
1815 // If net_proto_version is set, this client has already been handled
1816 if(getClient(peer_id)->net_proto_version != 0){
1817 verbosestream<<"Server: Ignoring multiple TOSERVER_INITs from "
1818 <<addr_s<<" (peer_id="<<peer_id<<")"<<std::endl;
1822 verbosestream<<"Server: Got TOSERVER_INIT from "<<addr_s<<" (peer_id="
1823 <<peer_id<<")"<<std::endl;
1825 // Do not allow multiple players in simple singleplayer mode.
1826 // This isn't a perfect way to do it, but will suffice for now.
1827 if(m_simple_singleplayer_mode && m_clients.size() > 1){
1828 infostream<<"Server: Not allowing another client ("<<addr_s
1829 <<") to connect in simple singleplayer mode"<<std::endl;
1830 DenyAccess(peer_id, L"Running in simple singleplayer mode.");
1834 // First byte after command is maximum supported
1835 // serialization version
1836 u8 client_max = data[2];
1837 u8 our_max = SER_FMT_VER_HIGHEST_READ;
1838 // Use the highest version supported by both
1839 u8 deployed = std::min(client_max, our_max);
1840 // If it's lower than the lowest supported, give up.
1841 if(deployed < SER_FMT_VER_LOWEST)
1842 deployed = SER_FMT_VER_INVALID;
1844 //peer->serialization_version = deployed;
1845 getClient(peer_id)->pending_serialization_version = deployed;
1847 if(deployed == SER_FMT_VER_INVALID)
1849 actionstream<<"Server: A mismatched client tried to connect from "
1850 <<addr_s<<std::endl;
1851 infostream<<"Server: Cannot negotiate serialization version with "
1852 <<addr_s<<std::endl;
1853 DenyAccess(peer_id, std::wstring(
1854 L"Your client's version is not supported.\n"
1855 L"Server version is ")
1856 + narrow_to_wide(VERSION_STRING) + L"."
1862 Read and check network protocol version
1865 u16 min_net_proto_version = 0;
1866 if(datasize >= 2+1+PLAYERNAME_SIZE+PASSWORD_SIZE+2)
1867 min_net_proto_version = readU16(&data[2+1+PLAYERNAME_SIZE+PASSWORD_SIZE]);
1869 // Use same version as minimum and maximum if maximum version field
1870 // doesn't exist (backwards compatibility)
1871 u16 max_net_proto_version = min_net_proto_version;
1872 if(datasize >= 2+1+PLAYERNAME_SIZE+PASSWORD_SIZE+2+2)
1873 max_net_proto_version = readU16(&data[2+1+PLAYERNAME_SIZE+PASSWORD_SIZE+2]);
1875 // Start with client's maximum version
1876 u16 net_proto_version = max_net_proto_version;
1878 // Figure out a working version if it is possible at all
1879 if(max_net_proto_version >= SERVER_PROTOCOL_VERSION_MIN ||
1880 min_net_proto_version <= SERVER_PROTOCOL_VERSION_MAX)
1882 // If maximum is larger than our maximum, go with our maximum
1883 if(max_net_proto_version > SERVER_PROTOCOL_VERSION_MAX)
1884 net_proto_version = SERVER_PROTOCOL_VERSION_MAX;
1885 // Else go with client's maximum
1887 net_proto_version = max_net_proto_version;
1890 verbosestream<<"Server: "<<addr_s<<": Protocol version: min: "
1891 <<min_net_proto_version<<", max: "<<max_net_proto_version
1892 <<", chosen: "<<net_proto_version<<std::endl;
1894 getClient(peer_id)->net_proto_version = net_proto_version;
1896 if(net_proto_version < SERVER_PROTOCOL_VERSION_MIN ||
1897 net_proto_version > SERVER_PROTOCOL_VERSION_MAX)
1899 actionstream<<"Server: A mismatched client tried to connect from "
1900 <<addr_s<<std::endl;
1901 DenyAccess(peer_id, std::wstring(
1902 L"Your client's version is not supported.\n"
1903 L"Server version is ")
1904 + narrow_to_wide(VERSION_STRING) + L",\n"
1905 + L"server's PROTOCOL_VERSION is "
1906 + narrow_to_wide(itos(SERVER_PROTOCOL_VERSION_MIN))
1908 + narrow_to_wide(itos(SERVER_PROTOCOL_VERSION_MAX))
1909 + L", client's PROTOCOL_VERSION is "
1910 + narrow_to_wide(itos(min_net_proto_version))
1912 + narrow_to_wide(itos(max_net_proto_version))
1917 if(g_settings->getBool("strict_protocol_version_checking"))
1919 if(net_proto_version != LATEST_PROTOCOL_VERSION)
1921 actionstream<<"Server: A mismatched (strict) client tried to "
1922 <<"connect from "<<addr_s<<std::endl;
1923 DenyAccess(peer_id, std::wstring(
1924 L"Your client's version is not supported.\n"
1925 L"Server version is ")
1926 + narrow_to_wide(VERSION_STRING) + L",\n"
1927 + L"server's PROTOCOL_VERSION (strict) is "
1928 + narrow_to_wide(itos(LATEST_PROTOCOL_VERSION))
1929 + L", client's PROTOCOL_VERSION is "
1930 + narrow_to_wide(itos(min_net_proto_version))
1932 + narrow_to_wide(itos(max_net_proto_version))
1943 char playername[PLAYERNAME_SIZE];
1944 for(u32 i=0; i<PLAYERNAME_SIZE-1; i++)
1946 playername[i] = data[3+i];
1948 playername[PLAYERNAME_SIZE-1] = 0;
1950 if(playername[0]=='\0')
1952 actionstream<<"Server: Player with an empty name "
1953 <<"tried to connect from "<<addr_s<<std::endl;
1954 DenyAccess(peer_id, L"Empty name");
1958 if(string_allowed(playername, PLAYERNAME_ALLOWED_CHARS)==false)
1960 actionstream<<"Server: Player with an invalid name "
1961 <<"tried to connect from "<<addr_s<<std::endl;
1962 DenyAccess(peer_id, L"Name contains unallowed characters");
1966 if(!isSingleplayer() && strcasecmp(playername, "singleplayer") == 0)
1968 actionstream<<"Server: Player with the name \"singleplayer\" "
1969 <<"tried to connect from "<<addr_s<<std::endl;
1970 DenyAccess(peer_id, L"Name is not allowed");
1974 infostream<<"Server: New connection: \""<<playername<<"\" from "
1975 <<addr_s<<" (peer_id="<<peer_id<<")"<<std::endl;
1978 char given_password[PASSWORD_SIZE];
1979 if(datasize < 2+1+PLAYERNAME_SIZE+PASSWORD_SIZE)
1981 // old version - assume blank password
1982 given_password[0] = 0;
1986 for(u32 i=0; i<PASSWORD_SIZE-1; i++)
1988 given_password[i] = data[23+i];
1990 given_password[PASSWORD_SIZE-1] = 0;
1993 if(!base64_is_valid(given_password)){
1994 actionstream<<"Server: "<<playername
1995 <<" supplied invalid password hash"<<std::endl;
1996 DenyAccess(peer_id, L"Invalid password hash");
2000 // Enforce user limit.
2001 // Don't enforce for users that have some admin right
2002 if(m_clients.size() >= g_settings->getU16("max_users") &&
2003 !checkPriv(playername, "server") &&
2004 !checkPriv(playername, "ban") &&
2005 !checkPriv(playername, "privs") &&
2006 !checkPriv(playername, "password") &&
2007 playername != g_settings->get("name"))
2009 actionstream<<"Server: "<<playername<<" tried to join, but there"
2010 <<" are already max_users="
2011 <<g_settings->getU16("max_users")<<" players."<<std::endl;
2012 DenyAccess(peer_id, L"Too many users.");
2016 std::string checkpwd; // Password hash to check against
2017 bool has_auth = m_script->getAuth(playername, &checkpwd, NULL);
2019 // If no authentication info exists for user, create it
2021 if(!isSingleplayer() &&
2022 g_settings->getBool("disallow_empty_password") &&
2023 std::string(given_password) == ""){
2024 actionstream<<"Server: "<<playername
2025 <<" supplied empty password"<<std::endl;
2026 DenyAccess(peer_id, L"Empty passwords are "
2027 L"disallowed. Set a password and try again.");
2030 std::wstring raw_default_password =
2031 narrow_to_wide(g_settings->get("default_password"));
2032 std::string initial_password =
2033 translatePassword(playername, raw_default_password);
2035 // If default_password is empty, allow any initial password
2036 if (raw_default_password.length() == 0)
2037 initial_password = given_password;
2039 m_script->createAuth(playername, initial_password);
2042 has_auth = m_script->getAuth(playername, &checkpwd, NULL);
2045 actionstream<<"Server: "<<playername<<" cannot be authenticated"
2046 <<" (auth handler does not work?)"<<std::endl;
2047 DenyAccess(peer_id, L"Not allowed to login");
2051 if(given_password != checkpwd){
2052 actionstream<<"Server: "<<playername<<" supplied wrong password"
2054 DenyAccess(peer_id, L"Wrong password");
2059 PlayerSAO *playersao = emergePlayer(playername, peer_id);
2061 // If failed, cancel
2062 if(playersao == NULL)
2064 RemotePlayer *player =
2065 static_cast<RemotePlayer*>(m_env->getPlayer(playername));
2066 if(player && player->peer_id != 0){
2067 errorstream<<"Server: "<<playername<<": Failed to emerge player"
2068 <<" (player allocated to an another client)"<<std::endl;
2069 DenyAccess(peer_id, L"Another client is connected with this "
2070 L"name. If your client closed unexpectedly, try again in "
2073 errorstream<<"Server: "<<playername<<": Failed to emerge player"
2075 DenyAccess(peer_id, L"Could not allocate player.");
2081 Answer with a TOCLIENT_INIT
2084 SharedBuffer<u8> reply(2+1+6+8+4);
2085 writeU16(&reply[0], TOCLIENT_INIT);
2086 writeU8(&reply[2], deployed);
2087 writeV3S16(&reply[2+1], floatToInt(playersao->getPlayer()->getPosition()+v3f(0,BS/2,0), BS));
2088 writeU64(&reply[2+1+6], m_env->getServerMap().getSeed());
2089 writeF1000(&reply[2+1+6+8], g_settings->getFloat("dedicated_server_step"));
2092 m_con.Send(peer_id, 0, reply, true);
2096 Send complete position information
2098 SendMovePlayer(peer_id);
2103 if(command == TOSERVER_INIT2)
2105 verbosestream<<"Server: Got TOSERVER_INIT2 from "
2106 <<peer_id<<std::endl;
2108 Player *player = m_env->getPlayer(peer_id);
2110 verbosestream<<"Server: TOSERVER_INIT2: "
2111 <<"Player not found; ignoring."<<std::endl;
2115 RemoteClient *client = getClient(peer_id);
2116 client->serialization_version =
2117 getClient(peer_id)->pending_serialization_version;
2120 Send some initialization data
2123 infostream<<"Server: Sending content to "
2124 <<getPlayerName(peer_id)<<std::endl;
2126 // Send player movement settings
2127 SendMovement(m_con, peer_id);
2129 // Send item definitions
2130 SendItemDef(m_con, peer_id, m_itemdef, client->net_proto_version);
2132 // Send node definitions
2133 SendNodeDef(m_con, peer_id, m_nodedef, client->net_proto_version);
2135 // Send media announcement
2136 sendMediaAnnouncement(peer_id);
2139 SendPlayerPrivileges(peer_id);
2141 // Send inventory formspec
2142 SendPlayerInventoryFormspec(peer_id);
2145 UpdateCrafting(peer_id);
2146 SendInventory(peer_id);
2149 if(g_settings->getBool("enable_damage"))
2150 SendPlayerHP(peer_id);
2153 SendPlayerBreath(peer_id);
2155 // Send detached inventories
2156 sendDetachedInventories(peer_id);
2158 // Show death screen if necessary
2160 SendDeathscreen(m_con, peer_id, false, v3f(0,0,0));
2164 u16 time = m_env->getTimeOfDay();
2165 float time_speed = g_settings->getFloat("time_speed");
2166 SendTimeOfDay(peer_id, time, time_speed);
2169 // Note things in chat if not in simple singleplayer mode
2170 if(!m_simple_singleplayer_mode)
2172 // Send information about server to player in chat
2173 SendChatMessage(peer_id, getStatusString());
2175 // Send information about joining in chat
2177 std::wstring name = L"unknown";
2178 Player *player = m_env->getPlayer(peer_id);
2180 name = narrow_to_wide(player->getName());
2182 std::wstring message;
2185 message += L" joined the game.";
2186 BroadcastChatMessage(message);
2190 // Warnings about protocol version can be issued here
2191 if(getClient(peer_id)->net_proto_version < LATEST_PROTOCOL_VERSION)
2193 SendChatMessage(peer_id, L"# Server: WARNING: YOUR CLIENT'S "
2194 L"VERSION MAY NOT BE FULLY COMPATIBLE WITH THIS SERVER!");
2201 std::ostringstream os(std::ios_base::binary);
2202 for(std::map<u16, RemoteClient*>::iterator
2203 i = m_clients.begin();
2204 i != m_clients.end(); ++i)
2206 RemoteClient *client = i->second;
2207 assert(client->peer_id == i->first);
2208 if(client->serialization_version == SER_FMT_VER_INVALID)
2211 Player *player = m_env->getPlayer(client->peer_id);
2214 // Get name of player
2215 os<<player->getName()<<" ";
2218 actionstream<<player->getName()<<" ["<<addr_s<<"] "<<"joins game. List of players: "
2219 <<os.str()<<std::endl;
2225 if(peer_ser_ver == SER_FMT_VER_INVALID)
2227 infostream<<"Server::ProcessData(): Cancelling: Peer"
2228 " serialization format invalid or not initialized."
2229 " Skipping incoming command="<<command<<std::endl;
2233 Player *player = m_env->getPlayer(peer_id);
2235 infostream<<"Server::ProcessData(): Cancelling: "
2236 "No player for peer_id="<<peer_id
2241 PlayerSAO *playersao = player->getPlayerSAO();
2242 if(playersao == NULL){
2243 infostream<<"Server::ProcessData(): Cancelling: "
2244 "No player object for peer_id="<<peer_id
2249 if(command == TOSERVER_PLAYERPOS)
2251 if(datasize < 2+12+12+4+4)
2255 v3s32 ps = readV3S32(&data[start+2]);
2256 v3s32 ss = readV3S32(&data[start+2+12]);
2257 f32 pitch = (f32)readS32(&data[2+12+12]) / 100.0;
2258 f32 yaw = (f32)readS32(&data[2+12+12+4]) / 100.0;
2260 if(datasize >= 2+12+12+4+4+4)
2261 keyPressed = (u32)readU32(&data[2+12+12+4+4]);
2262 v3f position((f32)ps.X/100., (f32)ps.Y/100., (f32)ps.Z/100.);
2263 v3f speed((f32)ss.X/100., (f32)ss.Y/100., (f32)ss.Z/100.);
2264 pitch = wrapDegrees(pitch);
2265 yaw = wrapDegrees(yaw);
2267 player->setPosition(position);
2268 player->setSpeed(speed);
2269 player->setPitch(pitch);
2270 player->setYaw(yaw);
2271 player->keyPressed=keyPressed;
2272 player->control.up = (bool)(keyPressed&1);
2273 player->control.down = (bool)(keyPressed&2);
2274 player->control.left = (bool)(keyPressed&4);
2275 player->control.right = (bool)(keyPressed&8);
2276 player->control.jump = (bool)(keyPressed&16);
2277 player->control.aux1 = (bool)(keyPressed&32);
2278 player->control.sneak = (bool)(keyPressed&64);
2279 player->control.LMB = (bool)(keyPressed&128);
2280 player->control.RMB = (bool)(keyPressed&256);
2282 bool cheated = playersao->checkMovementCheat();
2285 m_script->on_cheat(playersao, "moved_too_fast");
2288 /*infostream<<"Server::ProcessData(): Moved player "<<peer_id<<" to "
2289 <<"("<<position.X<<","<<position.Y<<","<<position.Z<<")"
2290 <<" pitch="<<pitch<<" yaw="<<yaw<<std::endl;*/
2292 else if(command == TOSERVER_GOTBLOCKS)
2305 u16 count = data[2];
2306 for(u16 i=0; i<count; i++)
2308 if((s16)datasize < 2+1+(i+1)*6)
2309 throw con::InvalidIncomingDataException
2310 ("GOTBLOCKS length is too short");
2311 v3s16 p = readV3S16(&data[2+1+i*6]);
2312 /*infostream<<"Server: GOTBLOCKS ("
2313 <<p.X<<","<<p.Y<<","<<p.Z<<")"<<std::endl;*/
2314 RemoteClient *client = getClient(peer_id);
2315 client->GotBlock(p);
2318 else if(command == TOSERVER_DELETEDBLOCKS)
2331 u16 count = data[2];
2332 for(u16 i=0; i<count; i++)
2334 if((s16)datasize < 2+1+(i+1)*6)
2335 throw con::InvalidIncomingDataException
2336 ("DELETEDBLOCKS length is too short");
2337 v3s16 p = readV3S16(&data[2+1+i*6]);
2338 /*infostream<<"Server: DELETEDBLOCKS ("
2339 <<p.X<<","<<p.Y<<","<<p.Z<<")"<<std::endl;*/
2340 RemoteClient *client = getClient(peer_id);
2341 client->SetBlockNotSent(p);
2344 else if(command == TOSERVER_CLICK_OBJECT)
2346 infostream<<"Server: CLICK_OBJECT not supported anymore"<<std::endl;
2349 else if(command == TOSERVER_CLICK_ACTIVEOBJECT)
2351 infostream<<"Server: CLICK_ACTIVEOBJECT not supported anymore"<<std::endl;
2354 else if(command == TOSERVER_GROUND_ACTION)
2356 infostream<<"Server: GROUND_ACTION not supported anymore"<<std::endl;
2360 else if(command == TOSERVER_RELEASE)
2362 infostream<<"Server: RELEASE not supported anymore"<<std::endl;
2365 else if(command == TOSERVER_SIGNTEXT)
2367 infostream<<"Server: SIGNTEXT not supported anymore"
2371 else if(command == TOSERVER_SIGNNODETEXT)
2373 infostream<<"Server: SIGNNODETEXT not supported anymore"
2377 else if(command == TOSERVER_INVENTORY_ACTION)
2379 // Strip command and create a stream
2380 std::string datastring((char*)&data[2], datasize-2);
2381 verbosestream<<"TOSERVER_INVENTORY_ACTION: data="<<datastring<<std::endl;
2382 std::istringstream is(datastring, std::ios_base::binary);
2384 InventoryAction *a = InventoryAction::deSerialize(is);
2387 infostream<<"TOSERVER_INVENTORY_ACTION: "
2388 <<"InventoryAction::deSerialize() returned NULL"
2393 // If something goes wrong, this player is to blame
2394 RollbackScopeActor rollback_scope(m_rollback,
2395 std::string("player:")+player->getName());
2398 Note: Always set inventory not sent, to repair cases
2399 where the client made a bad prediction.
2403 Handle restrictions and special cases of the move action
2405 if(a->getType() == IACTION_MOVE)
2407 IMoveAction *ma = (IMoveAction*)a;
2409 ma->from_inv.applyCurrentPlayer(player->getName());
2410 ma->to_inv.applyCurrentPlayer(player->getName());
2412 setInventoryModified(ma->from_inv);
2413 setInventoryModified(ma->to_inv);
2415 bool from_inv_is_current_player =
2416 (ma->from_inv.type == InventoryLocation::PLAYER) &&
2417 (ma->from_inv.name == player->getName());
2419 bool to_inv_is_current_player =
2420 (ma->to_inv.type == InventoryLocation::PLAYER) &&
2421 (ma->to_inv.name == player->getName());
2424 Disable moving items out of craftpreview
2426 if(ma->from_list == "craftpreview")
2428 infostream<<"Ignoring IMoveAction from "
2429 <<(ma->from_inv.dump())<<":"<<ma->from_list
2430 <<" to "<<(ma->to_inv.dump())<<":"<<ma->to_list
2431 <<" because src is "<<ma->from_list<<std::endl;
2437 Disable moving items into craftresult and craftpreview
2439 if(ma->to_list == "craftpreview" || ma->to_list == "craftresult")
2441 infostream<<"Ignoring IMoveAction from "
2442 <<(ma->from_inv.dump())<<":"<<ma->from_list
2443 <<" to "<<(ma->to_inv.dump())<<":"<<ma->to_list
2444 <<" because dst is "<<ma->to_list<<std::endl;
2449 // Disallow moving items in elsewhere than player's inventory
2450 // if not allowed to interact
2451 if(!checkPriv(player->getName(), "interact") &&
2452 (!from_inv_is_current_player ||
2453 !to_inv_is_current_player))
2455 infostream<<"Cannot move outside of player's inventory: "
2456 <<"No interact privilege"<<std::endl;
2462 Handle restrictions and special cases of the drop action
2464 else if(a->getType() == IACTION_DROP)
2466 IDropAction *da = (IDropAction*)a;
2468 da->from_inv.applyCurrentPlayer(player->getName());
2470 setInventoryModified(da->from_inv);
2473 Disable dropping items out of craftpreview
2475 if(da->from_list == "craftpreview")
2477 infostream<<"Ignoring IDropAction from "
2478 <<(da->from_inv.dump())<<":"<<da->from_list
2479 <<" because src is "<<da->from_list<<std::endl;
2484 // Disallow dropping items if not allowed to interact
2485 if(!checkPriv(player->getName(), "interact"))
2492 Handle restrictions and special cases of the craft action
2494 else if(a->getType() == IACTION_CRAFT)
2496 ICraftAction *ca = (ICraftAction*)a;
2498 ca->craft_inv.applyCurrentPlayer(player->getName());
2500 setInventoryModified(ca->craft_inv);
2502 //bool craft_inv_is_current_player =
2503 // (ca->craft_inv.type == InventoryLocation::PLAYER) &&
2504 // (ca->craft_inv.name == player->getName());
2506 // Disallow crafting if not allowed to interact
2507 if(!checkPriv(player->getName(), "interact"))
2509 infostream<<"Cannot craft: "
2510 <<"No interact privilege"<<std::endl;
2517 a->apply(this, playersao, this);
2521 else if(command == TOSERVER_CHAT_MESSAGE)
2529 std::string datastring((char*)&data[2], datasize-2);
2530 std::istringstream is(datastring, std::ios_base::binary);
2533 is.read((char*)buf, 2);
2534 u16 len = readU16(buf);
2536 std::wstring message;
2537 for(u16 i=0; i<len; i++)
2539 is.read((char*)buf, 2);
2540 message += (wchar_t)readU16(buf);
2543 // If something goes wrong, this player is to blame
2544 RollbackScopeActor rollback_scope(m_rollback,
2545 std::string("player:")+player->getName());
2547 // Get player name of this client
2548 std::wstring name = narrow_to_wide(player->getName());
2551 bool ate = m_script->on_chat_message(player->getName(),
2552 wide_to_narrow(message));
2553 // If script ate the message, don't proceed
2557 // Line to send to players
2559 // Whether to send to the player that sent the line
2560 bool send_to_sender = false;
2561 // Whether to send to other players
2562 bool send_to_others = false;
2564 // Commands are implemented in Lua, so only catch invalid
2565 // commands that were not "eaten" and send an error back
2566 if(message[0] == L'/')
2568 message = message.substr(1);
2569 send_to_sender = true;
2570 if(message.length() == 0)
2571 line += L"-!- Empty command";
2573 line += L"-!- Invalid command: " + str_split(message, L' ')[0];
2577 if(checkPriv(player->getName(), "shout")){
2582 send_to_others = true;
2584 line += L"-!- You don't have permission to shout.";
2585 send_to_sender = true;
2592 actionstream<<"CHAT: "<<wide_to_narrow(line)<<std::endl;
2595 Send the message to clients
2597 for(std::map<u16, RemoteClient*>::iterator
2598 i = m_clients.begin();
2599 i != m_clients.end(); ++i)
2601 // Get client and check that it is valid
2602 RemoteClient *client = i->second;
2603 assert(client->peer_id == i->first);
2604 if(client->serialization_version == SER_FMT_VER_INVALID)
2608 bool sender_selected = (peer_id == client->peer_id);
2609 if(sender_selected == true && send_to_sender == false)
2611 if(sender_selected == false && send_to_others == false)
2614 SendChatMessage(client->peer_id, line);
2618 else if(command == TOSERVER_DAMAGE)
2620 std::string datastring((char*)&data[2], datasize-2);
2621 std::istringstream is(datastring, std::ios_base::binary);
2622 u8 damage = readU8(is);
2624 if(g_settings->getBool("enable_damage"))
2626 actionstream<<player->getName()<<" damaged by "
2627 <<(int)damage<<" hp at "<<PP(player->getPosition()/BS)
2630 playersao->setHP(playersao->getHP() - damage);
2632 if(playersao->getHP() == 0 && playersao->m_hp_not_sent)
2635 if(playersao->m_hp_not_sent)
2636 SendPlayerHP(peer_id);
2639 else if(command == TOSERVER_BREATH)
2641 std::string datastring((char*)&data[2], datasize-2);
2642 std::istringstream is(datastring, std::ios_base::binary);
2643 u16 breath = readU16(is);
2644 playersao->setBreath(breath);
2646 else if(command == TOSERVER_PASSWORD)
2649 [0] u16 TOSERVER_PASSWORD
2650 [2] u8[28] old password
2651 [30] u8[28] new password
2654 if(datasize != 2+PASSWORD_SIZE*2)
2656 /*char password[PASSWORD_SIZE];
2657 for(u32 i=0; i<PASSWORD_SIZE-1; i++)
2658 password[i] = data[2+i];
2659 password[PASSWORD_SIZE-1] = 0;*/
2661 for(u32 i=0; i<PASSWORD_SIZE-1; i++)
2669 for(u32 i=0; i<PASSWORD_SIZE-1; i++)
2671 char c = data[2+PASSWORD_SIZE+i];
2677 if(!base64_is_valid(newpwd)){
2678 infostream<<"Server: "<<player->getName()<<" supplied invalid password hash"<<std::endl;
2679 // Wrong old password supplied!!
2680 SendChatMessage(peer_id, L"Invalid new password hash supplied. Password NOT changed.");
2684 infostream<<"Server: Client requests a password change from "
2685 <<"'"<<oldpwd<<"' to '"<<newpwd<<"'"<<std::endl;
2687 std::string playername = player->getName();
2689 std::string checkpwd;
2690 m_script->getAuth(playername, &checkpwd, NULL);
2692 if(oldpwd != checkpwd)
2694 infostream<<"Server: invalid old password"<<std::endl;
2695 // Wrong old password supplied!!
2696 SendChatMessage(peer_id, L"Invalid old password supplied. Password NOT changed.");
2700 bool success = m_script->setPassword(playername, newpwd);
2702 actionstream<<player->getName()<<" changes password"<<std::endl;
2703 SendChatMessage(peer_id, L"Password change successful.");
2705 actionstream<<player->getName()<<" tries to change password but "
2706 <<"it fails"<<std::endl;
2707 SendChatMessage(peer_id, L"Password change failed or inavailable.");
2710 else if(command == TOSERVER_PLAYERITEM)
2715 u16 item = readU16(&data[2]);
2716 playersao->setWieldIndex(item);
2718 else if(command == TOSERVER_RESPAWN)
2720 if(player->hp != 0 || !g_settings->getBool("enable_damage"))
2723 RespawnPlayer(peer_id);
2725 actionstream<<player->getName()<<" respawns at "
2726 <<PP(player->getPosition()/BS)<<std::endl;
2728 // ActiveObject is added to environment in AsyncRunStep after
2729 // the previous addition has been succesfully removed
2731 else if(command == TOSERVER_REQUEST_MEDIA) {
2732 std::string datastring((char*)&data[2], datasize-2);
2733 std::istringstream is(datastring, std::ios_base::binary);
2735 std::list<MediaRequest> tosend;
2736 u16 numfiles = readU16(is);
2738 infostream<<"Sending "<<numfiles<<" files to "
2739 <<getPlayerName(peer_id)<<std::endl;
2740 verbosestream<<"TOSERVER_REQUEST_MEDIA: "<<std::endl;
2742 for(int i = 0; i < numfiles; i++) {
2743 std::string name = deSerializeString(is);
2744 tosend.push_back(MediaRequest(name));
2745 verbosestream<<"TOSERVER_REQUEST_MEDIA: requested file "
2749 sendRequestedMedia(peer_id, tosend);
2751 // Now the client should know about everything
2752 // (definitions and files)
2753 getClient(peer_id)->definitions_sent = true;
2755 else if(command == TOSERVER_RECEIVED_MEDIA) {
2756 getClient(peer_id)->definitions_sent = true;
2758 else if(command == TOSERVER_INTERACT)
2760 std::string datastring((char*)&data[2], datasize-2);
2761 std::istringstream is(datastring, std::ios_base::binary);
2767 [5] u32 length of the next item
2768 [9] serialized PointedThing
2770 0: start digging (from undersurface) or use
2771 1: stop digging (all parameters ignored)
2772 2: digging completed
2773 3: place block or item (to abovesurface)
2776 u8 action = readU8(is);
2777 u16 item_i = readU16(is);
2778 std::istringstream tmp_is(deSerializeLongString(is), std::ios::binary);
2779 PointedThing pointed;
2780 pointed.deSerialize(tmp_is);
2782 verbosestream<<"TOSERVER_INTERACT: action="<<(int)action<<", item="
2783 <<item_i<<", pointed="<<pointed.dump()<<std::endl;
2787 verbosestream<<"TOSERVER_INTERACT: "<<player->getName()
2788 <<" tried to interact, but is dead!"<<std::endl;
2792 v3f player_pos = playersao->getLastGoodPosition();
2794 // Update wielded item
2795 playersao->setWieldIndex(item_i);
2797 // Get pointed to node (undefined if not POINTEDTYPE_NODE)
2798 v3s16 p_under = pointed.node_undersurface;
2799 v3s16 p_above = pointed.node_abovesurface;
2801 // Get pointed to object (NULL if not POINTEDTYPE_OBJECT)
2802 ServerActiveObject *pointed_object = NULL;
2803 if(pointed.type == POINTEDTHING_OBJECT)
2805 pointed_object = m_env->getActiveObject(pointed.object_id);
2806 if(pointed_object == NULL)
2808 verbosestream<<"TOSERVER_INTERACT: "
2809 "pointed object is NULL"<<std::endl;
2815 v3f pointed_pos_under = player_pos;
2816 v3f pointed_pos_above = player_pos;
2817 if(pointed.type == POINTEDTHING_NODE)
2819 pointed_pos_under = intToFloat(p_under, BS);
2820 pointed_pos_above = intToFloat(p_above, BS);
2822 else if(pointed.type == POINTEDTHING_OBJECT)
2824 pointed_pos_under = pointed_object->getBasePosition();
2825 pointed_pos_above = pointed_pos_under;
2829 Check that target is reasonably close
2830 (only when digging or placing things)
2832 if(action == 0 || action == 2 || action == 3)
2834 float d = player_pos.getDistanceFrom(pointed_pos_under);
2835 float max_d = BS * 14; // Just some large enough value
2837 actionstream<<"Player "<<player->getName()
2838 <<" tried to access "<<pointed.dump()
2840 <<"d="<<d<<", max_d="<<max_d
2841 <<". ignoring."<<std::endl;
2842 // Re-send block to revert change on client-side
2843 RemoteClient *client = getClient(peer_id);
2844 v3s16 blockpos = getNodeBlockPos(floatToInt(pointed_pos_under, BS));
2845 client->SetBlockNotSent(blockpos);
2847 m_script->on_cheat(playersao, "interacted_too_far");
2854 Make sure the player is allowed to do it
2856 if(!checkPriv(player->getName(), "interact"))
2858 actionstream<<player->getName()<<" attempted to interact with "
2859 <<pointed.dump()<<" without 'interact' privilege"
2861 // Re-send block to revert change on client-side
2862 RemoteClient *client = getClient(peer_id);
2863 // Digging completed -> under
2865 v3s16 blockpos = getNodeBlockPos(floatToInt(pointed_pos_under, BS));
2866 client->SetBlockNotSent(blockpos);
2868 // Placement -> above
2870 v3s16 blockpos = getNodeBlockPos(floatToInt(pointed_pos_above, BS));
2871 client->SetBlockNotSent(blockpos);
2877 If something goes wrong, this player is to blame
2879 RollbackScopeActor rollback_scope(m_rollback,
2880 std::string("player:")+player->getName());
2883 0: start digging or punch object
2887 if(pointed.type == POINTEDTHING_NODE)
2890 NOTE: This can be used in the future to check if
2891 somebody is cheating, by checking the timing.
2893 MapNode n(CONTENT_IGNORE);
2896 n = m_env->getMap().getNode(p_under);
2898 catch(InvalidPositionException &e)
2900 infostream<<"Server: Not punching: Node not found."
2901 <<" Adding block to emerge queue."
2903 m_emerge->enqueueBlockEmerge(peer_id, getNodeBlockPos(p_above), false);
2905 if(n.getContent() != CONTENT_IGNORE)
2906 m_script->node_on_punch(p_under, n, playersao);
2908 playersao->noCheatDigStart(p_under);
2910 else if(pointed.type == POINTEDTHING_OBJECT)
2912 // Skip if object has been removed
2913 if(pointed_object->m_removed)
2916 actionstream<<player->getName()<<" punches object "
2917 <<pointed.object_id<<": "
2918 <<pointed_object->getDescription()<<std::endl;
2920 ItemStack punchitem = playersao->getWieldedItem();
2921 ToolCapabilities toolcap =
2922 punchitem.getToolCapabilities(m_itemdef);
2923 v3f dir = (pointed_object->getBasePosition() -
2924 (player->getPosition() + player->getEyeOffset())
2926 float time_from_last_punch =
2927 playersao->resetTimeFromLastPunch();
2928 pointed_object->punch(dir, &toolcap, playersao,
2929 time_from_last_punch);
2937 else if(action == 1)
2942 2: Digging completed
2944 else if(action == 2)
2946 // Only digging of nodes
2947 if(pointed.type == POINTEDTHING_NODE)
2949 MapNode n(CONTENT_IGNORE);
2952 n = m_env->getMap().getNode(p_under);
2954 catch(InvalidPositionException &e)
2956 infostream<<"Server: Not finishing digging: Node not found."
2957 <<" Adding block to emerge queue."
2959 m_emerge->enqueueBlockEmerge(peer_id, getNodeBlockPos(p_above), false);
2962 /* Cheat prevention */
2963 bool is_valid_dig = true;
2964 if(!isSingleplayer() && !g_settings->getBool("disable_anticheat"))
2966 v3s16 nocheat_p = playersao->getNoCheatDigPos();
2967 float nocheat_t = playersao->getNoCheatDigTime();
2968 playersao->noCheatDigEnd();
2969 // If player didn't start digging this, ignore dig
2970 if(nocheat_p != p_under){
2971 infostream<<"Server: NoCheat: "<<player->getName()
2972 <<" started digging "
2973 <<PP(nocheat_p)<<" and completed digging "
2974 <<PP(p_under)<<"; not digging."<<std::endl;
2975 is_valid_dig = false;
2977 m_script->on_cheat(playersao, "finished_unknown_dig");
2979 // Get player's wielded item
2980 ItemStack playeritem;
2981 InventoryList *mlist = playersao->getInventory()->getList("main");
2983 playeritem = mlist->getItem(playersao->getWieldIndex());
2984 ToolCapabilities playeritem_toolcap =
2985 playeritem.getToolCapabilities(m_itemdef);
2986 // Get diggability and expected digging time
2987 DigParams params = getDigParams(m_nodedef->get(n).groups,
2988 &playeritem_toolcap);
2989 // If can't dig, try hand
2990 if(!params.diggable){
2991 const ItemDefinition &hand = m_itemdef->get("");
2992 const ToolCapabilities *tp = hand.tool_capabilities;
2994 params = getDigParams(m_nodedef->get(n).groups, tp);
2996 // If can't dig, ignore dig
2997 if(!params.diggable){
2998 infostream<<"Server: NoCheat: "<<player->getName()
2999 <<" completed digging "<<PP(p_under)
3000 <<", which is not diggable with tool. not digging."
3002 is_valid_dig = false;
3004 m_script->on_cheat(playersao, "dug_unbreakable");
3006 // Check digging time
3007 // If already invalidated, we don't have to
3009 // Well not our problem then
3011 // Clean and long dig
3012 else if(params.time > 2.0 && nocheat_t * 1.2 > params.time){
3013 // All is good, but grab time from pool; don't care if
3014 // it's actually available
3015 playersao->getDigPool().grab(params.time);
3017 // Short or laggy dig
3018 // Try getting the time from pool
3019 else if(playersao->getDigPool().grab(params.time)){
3024 infostream<<"Server: NoCheat: "<<player->getName()
3025 <<" completed digging "<<PP(p_under)
3026 <<"too fast; not digging."<<std::endl;
3027 is_valid_dig = false;
3029 m_script->on_cheat(playersao, "dug_too_fast");
3033 /* Actually dig node */
3035 if(is_valid_dig && n.getContent() != CONTENT_IGNORE)
3036 m_script->node_on_dig(p_under, n, playersao);
3038 // Send unusual result (that is, node not being removed)
3039 if(m_env->getMap().getNodeNoEx(p_under).getContent() != CONTENT_AIR)
3041 // Re-send block to revert change on client-side
3042 RemoteClient *client = getClient(peer_id);
3043 v3s16 blockpos = getNodeBlockPos(floatToInt(pointed_pos_under, BS));
3044 client->SetBlockNotSent(blockpos);
3050 3: place block or right-click object
3052 else if(action == 3)
3054 ItemStack item = playersao->getWieldedItem();
3056 // Reset build time counter
3057 if(pointed.type == POINTEDTHING_NODE &&
3058 item.getDefinition(m_itemdef).type == ITEM_NODE)
3059 getClient(peer_id)->m_time_from_building = 0.0;
3061 if(pointed.type == POINTEDTHING_OBJECT)
3063 // Right click object
3065 // Skip if object has been removed
3066 if(pointed_object->m_removed)
3069 actionstream<<player->getName()<<" right-clicks object "
3070 <<pointed.object_id<<": "
3071 <<pointed_object->getDescription()<<std::endl;
3074 pointed_object->rightClick(playersao);
3076 else if(m_script->item_OnPlace(
3077 item, playersao, pointed))
3079 // Placement was handled in lua
3081 // Apply returned ItemStack
3082 playersao->setWieldedItem(item);
3085 // If item has node placement prediction, always send the
3086 // blocks to make sure the client knows what exactly happened
3087 if(item.getDefinition(m_itemdef).node_placement_prediction != ""){
3088 RemoteClient *client = getClient(peer_id);
3089 v3s16 blockpos = getNodeBlockPos(floatToInt(pointed_pos_above, BS));
3090 client->SetBlockNotSent(blockpos);
3091 v3s16 blockpos2 = getNodeBlockPos(floatToInt(pointed_pos_under, BS));
3092 if(blockpos2 != blockpos){
3093 client->SetBlockNotSent(blockpos2);
3101 else if(action == 4)
3103 ItemStack item = playersao->getWieldedItem();
3105 actionstream<<player->getName()<<" uses "<<item.name
3106 <<", pointing at "<<pointed.dump()<<std::endl;
3108 if(m_script->item_OnUse(
3109 item, playersao, pointed))
3111 // Apply returned ItemStack
3112 playersao->setWieldedItem(item);
3119 Catch invalid actions
3123 infostream<<"WARNING: Server: Invalid action "
3124 <<action<<std::endl;
3127 else if(command == TOSERVER_REMOVED_SOUNDS)
3129 std::string datastring((char*)&data[2], datasize-2);
3130 std::istringstream is(datastring, std::ios_base::binary);
3132 int num = readU16(is);
3133 for(int k=0; k<num; k++){
3134 s32 id = readS32(is);
3135 std::map<s32, ServerPlayingSound>::iterator i =
3136 m_playing_sounds.find(id);
3137 if(i == m_playing_sounds.end())
3139 ServerPlayingSound &psound = i->second;
3140 psound.clients.erase(peer_id);
3141 if(psound.clients.size() == 0)
3142 m_playing_sounds.erase(i++);
3145 else if(command == TOSERVER_NODEMETA_FIELDS)
3147 std::string datastring((char*)&data[2], datasize-2);
3148 std::istringstream is(datastring, std::ios_base::binary);
3150 v3s16 p = readV3S16(is);
3151 std::string formname = deSerializeString(is);
3152 int num = readU16(is);
3153 std::map<std::string, std::string> fields;
3154 for(int k=0; k<num; k++){
3155 std::string fieldname = deSerializeString(is);
3156 std::string fieldvalue = deSerializeLongString(is);
3157 fields[fieldname] = fieldvalue;
3160 // If something goes wrong, this player is to blame
3161 RollbackScopeActor rollback_scope(m_rollback,
3162 std::string("player:")+player->getName());
3164 // Check the target node for rollback data; leave others unnoticed
3165 RollbackNode rn_old(&m_env->getMap(), p, this);
3167 m_script->node_on_receive_fields(p, formname, fields,playersao);
3169 // Report rollback data
3170 RollbackNode rn_new(&m_env->getMap(), p, this);
3171 if(rollback() && rn_new != rn_old){
3172 RollbackAction action;
3173 action.setSetNode(p, rn_old, rn_new);
3174 rollback()->reportAction(action);
3177 else if(command == TOSERVER_INVENTORY_FIELDS)
3179 std::string datastring((char*)&data[2], datasize-2);
3180 std::istringstream is(datastring, std::ios_base::binary);
3182 std::string formname = deSerializeString(is);
3183 int num = readU16(is);
3184 std::map<std::string, std::string> fields;
3185 for(int k=0; k<num; k++){
3186 std::string fieldname = deSerializeString(is);
3187 std::string fieldvalue = deSerializeLongString(is);
3188 fields[fieldname] = fieldvalue;
3191 m_script->on_playerReceiveFields(playersao, formname, fields);
3195 infostream<<"Server::ProcessData(): Ignoring "
3196 "unknown command "<<command<<std::endl;
3200 catch(SendFailedException &e)
3202 errorstream<<"Server::ProcessData(): SendFailedException: "
3208 void Server::setTimeOfDay(u32 time)
3210 m_env->setTimeOfDay(time);
3211 m_time_of_day_send_timer = 0;
3214 void Server::onMapEditEvent(MapEditEvent *event)
3216 //infostream<<"Server::onMapEditEvent()"<<std::endl;
3217 if(m_ignore_map_edit_events)
3219 if(m_ignore_map_edit_events_area.contains(event->getArea()))
3221 MapEditEvent *e = event->clone();
3222 m_unsent_map_edit_queue.push_back(e);
3225 Inventory* Server::getInventory(const InventoryLocation &loc)
3228 case InventoryLocation::UNDEFINED:
3231 case InventoryLocation::CURRENT_PLAYER:
3234 case InventoryLocation::PLAYER:
3236 Player *player = m_env->getPlayer(loc.name.c_str());
3239 PlayerSAO *playersao = player->getPlayerSAO();
3242 return playersao->getInventory();
3245 case InventoryLocation::NODEMETA:
3247 NodeMetadata *meta = m_env->getMap().getNodeMetadata(loc.p);
3250 return meta->getInventory();
3253 case InventoryLocation::DETACHED:
3255 if(m_detached_inventories.count(loc.name) == 0)
3257 return m_detached_inventories[loc.name];
3265 void Server::setInventoryModified(const InventoryLocation &loc)
3268 case InventoryLocation::UNDEFINED:
3271 case InventoryLocation::PLAYER:
3273 Player *player = m_env->getPlayer(loc.name.c_str());
3276 PlayerSAO *playersao = player->getPlayerSAO();
3279 playersao->m_inventory_not_sent = true;
3280 playersao->m_wielded_item_not_sent = true;
3283 case InventoryLocation::NODEMETA:
3285 v3s16 blockpos = getNodeBlockPos(loc.p);
3287 MapBlock *block = m_env->getMap().getBlockNoCreateNoEx(blockpos);
3289 block->raiseModified(MOD_STATE_WRITE_NEEDED);
3291 setBlockNotSent(blockpos);
3294 case InventoryLocation::DETACHED:
3296 sendDetachedInventoryToAll(loc.name);
3304 void Server::peerAdded(con::Peer *peer)
3306 DSTACK(__FUNCTION_NAME);
3307 verbosestream<<"Server::peerAdded(): peer->id="
3308 <<peer->id<<std::endl;
3311 c.type = PEER_ADDED;
3312 c.peer_id = peer->id;
3314 m_peer_change_queue.push_back(c);
3317 void Server::deletingPeer(con::Peer *peer, bool timeout)
3319 DSTACK(__FUNCTION_NAME);
3320 verbosestream<<"Server::deletingPeer(): peer->id="
3321 <<peer->id<<", timeout="<<timeout<<std::endl;
3324 c.type = PEER_REMOVED;
3325 c.peer_id = peer->id;
3326 c.timeout = timeout;
3327 m_peer_change_queue.push_back(c);
3334 void Server::SendMovement(con::Connection &con, u16 peer_id)
3336 DSTACK(__FUNCTION_NAME);
3337 std::ostringstream os(std::ios_base::binary);
3339 writeU16(os, TOCLIENT_MOVEMENT);
3340 writeF1000(os, g_settings->getFloat("movement_acceleration_default"));
3341 writeF1000(os, g_settings->getFloat("movement_acceleration_air"));
3342 writeF1000(os, g_settings->getFloat("movement_acceleration_fast"));
3343 writeF1000(os, g_settings->getFloat("movement_speed_walk"));
3344 writeF1000(os, g_settings->getFloat("movement_speed_crouch"));
3345 writeF1000(os, g_settings->getFloat("movement_speed_fast"));
3346 writeF1000(os, g_settings->getFloat("movement_speed_climb"));
3347 writeF1000(os, g_settings->getFloat("movement_speed_jump"));
3348 writeF1000(os, g_settings->getFloat("movement_liquid_fluidity"));
3349 writeF1000(os, g_settings->getFloat("movement_liquid_fluidity_smooth"));
3350 writeF1000(os, g_settings->getFloat("movement_liquid_sink"));
3351 writeF1000(os, g_settings->getFloat("movement_gravity"));
3354 std::string s = os.str();
3355 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3357 con.Send(peer_id, 0, data, true);
3360 void Server::SendHP(con::Connection &con, u16 peer_id, u8 hp)
3362 DSTACK(__FUNCTION_NAME);
3363 std::ostringstream os(std::ios_base::binary);
3365 writeU16(os, TOCLIENT_HP);
3369 std::string s = os.str();
3370 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3372 con.Send(peer_id, 0, data, true);
3375 void Server::SendBreath(con::Connection &con, u16 peer_id, u16 breath)
3377 DSTACK(__FUNCTION_NAME);
3378 std::ostringstream os(std::ios_base::binary);
3380 writeU16(os, TOCLIENT_BREATH);
3381 writeU16(os, breath);
3384 std::string s = os.str();
3385 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3387 con.Send(peer_id, 0, data, true);
3390 void Server::SendAccessDenied(con::Connection &con, u16 peer_id,
3391 const std::wstring &reason)
3393 DSTACK(__FUNCTION_NAME);
3394 std::ostringstream os(std::ios_base::binary);
3396 writeU16(os, TOCLIENT_ACCESS_DENIED);
3397 os<<serializeWideString(reason);
3400 std::string s = os.str();
3401 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3403 con.Send(peer_id, 0, data, true);
3406 void Server::SendDeathscreen(con::Connection &con, u16 peer_id,
3407 bool set_camera_point_target, v3f camera_point_target)
3409 DSTACK(__FUNCTION_NAME);
3410 std::ostringstream os(std::ios_base::binary);
3412 writeU16(os, TOCLIENT_DEATHSCREEN);
3413 writeU8(os, set_camera_point_target);
3414 writeV3F1000(os, camera_point_target);
3417 std::string s = os.str();
3418 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3420 con.Send(peer_id, 0, data, true);
3423 void Server::SendItemDef(con::Connection &con, u16 peer_id,
3424 IItemDefManager *itemdef, u16 protocol_version)
3426 DSTACK(__FUNCTION_NAME);
3427 std::ostringstream os(std::ios_base::binary);
3431 u32 length of the next item
3432 zlib-compressed serialized ItemDefManager
3434 writeU16(os, TOCLIENT_ITEMDEF);
3435 std::ostringstream tmp_os(std::ios::binary);
3436 itemdef->serialize(tmp_os, protocol_version);
3437 std::ostringstream tmp_os2(std::ios::binary);
3438 compressZlib(tmp_os.str(), tmp_os2);
3439 os<<serializeLongString(tmp_os2.str());
3442 std::string s = os.str();
3443 verbosestream<<"Server: Sending item definitions to id("<<peer_id
3444 <<"): size="<<s.size()<<std::endl;
3445 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3447 con.Send(peer_id, 0, data, true);
3450 void Server::SendNodeDef(con::Connection &con, u16 peer_id,
3451 INodeDefManager *nodedef, u16 protocol_version)
3453 DSTACK(__FUNCTION_NAME);
3454 std::ostringstream os(std::ios_base::binary);
3458 u32 length of the next item
3459 zlib-compressed serialized NodeDefManager
3461 writeU16(os, TOCLIENT_NODEDEF);
3462 std::ostringstream tmp_os(std::ios::binary);
3463 nodedef->serialize(tmp_os, protocol_version);
3464 std::ostringstream tmp_os2(std::ios::binary);
3465 compressZlib(tmp_os.str(), tmp_os2);
3466 os<<serializeLongString(tmp_os2.str());
3469 std::string s = os.str();
3470 verbosestream<<"Server: Sending node definitions to id("<<peer_id
3471 <<"): size="<<s.size()<<std::endl;
3472 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3474 con.Send(peer_id, 0, data, true);
3478 Non-static send methods
3481 void Server::SendInventory(u16 peer_id)
3483 DSTACK(__FUNCTION_NAME);
3485 PlayerSAO *playersao = getPlayerSAO(peer_id);
3488 playersao->m_inventory_not_sent = false;
3494 std::ostringstream os;
3495 playersao->getInventory()->serialize(os);
3497 std::string s = os.str();
3499 SharedBuffer<u8> data(s.size()+2);
3500 writeU16(&data[0], TOCLIENT_INVENTORY);
3501 memcpy(&data[2], s.c_str(), s.size());
3504 m_con.Send(peer_id, 0, data, true);
3507 void Server::SendChatMessage(u16 peer_id, const std::wstring &message)
3509 DSTACK(__FUNCTION_NAME);
3511 std::ostringstream os(std::ios_base::binary);
3515 writeU16(buf, TOCLIENT_CHAT_MESSAGE);
3516 os.write((char*)buf, 2);
3519 writeU16(buf, message.size());
3520 os.write((char*)buf, 2);
3523 for(u32 i=0; i<message.size(); i++)
3527 os.write((char*)buf, 2);
3531 std::string s = os.str();
3532 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3534 m_con.Send(peer_id, 0, data, true);
3537 void Server::SendShowFormspecMessage(u16 peer_id, const std::string formspec,
3538 const std::string formname)
3540 DSTACK(__FUNCTION_NAME);
3542 std::ostringstream os(std::ios_base::binary);
3546 writeU16(buf, TOCLIENT_SHOW_FORMSPEC);
3547 os.write((char*)buf, 2);
3548 os<<serializeLongString(formspec);
3549 os<<serializeString(formname);
3552 std::string s = os.str();
3553 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3555 m_con.Send(peer_id, 0, data, true);
3558 // Spawns a particle on peer with peer_id
3559 void Server::SendSpawnParticle(u16 peer_id, v3f pos, v3f velocity, v3f acceleration,
3560 float expirationtime, float size, bool collisiondetection,
3561 std::string texture)
3563 DSTACK(__FUNCTION_NAME);
3565 std::ostringstream os(std::ios_base::binary);
3566 writeU16(os, TOCLIENT_SPAWN_PARTICLE);
3567 writeV3F1000(os, pos);
3568 writeV3F1000(os, velocity);
3569 writeV3F1000(os, acceleration);
3570 writeF1000(os, expirationtime);
3571 writeF1000(os, size);
3572 writeU8(os, collisiondetection);
3573 os<<serializeLongString(texture);
3576 std::string s = os.str();
3577 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3579 m_con.Send(peer_id, 0, data, true);
3582 // Spawns a particle on all peers
3583 void Server::SendSpawnParticleAll(v3f pos, v3f velocity, v3f acceleration,
3584 float expirationtime, float size, bool collisiondetection,
3585 std::string texture)
3587 for(std::map<u16, RemoteClient*>::iterator
3588 i = m_clients.begin();
3589 i != m_clients.end(); i++)
3591 // Get client and check that it is valid
3592 RemoteClient *client = i->second;
3593 assert(client->peer_id == i->first);
3594 if(client->serialization_version == SER_FMT_VER_INVALID)
3597 SendSpawnParticle(client->peer_id, pos, velocity, acceleration,
3598 expirationtime, size, collisiondetection, texture);
3602 // Adds a ParticleSpawner on peer with peer_id
3603 void Server::SendAddParticleSpawner(u16 peer_id, u16 amount, float spawntime, v3f minpos, v3f maxpos,
3604 v3f minvel, v3f maxvel, v3f minacc, v3f maxacc, float minexptime, float maxexptime,
3605 float minsize, float maxsize, bool collisiondetection, std::string texture, u32 id)
3607 DSTACK(__FUNCTION_NAME);
3609 std::ostringstream os(std::ios_base::binary);
3610 writeU16(os, TOCLIENT_ADD_PARTICLESPAWNER);
3612 writeU16(os, amount);
3613 writeF1000(os, spawntime);
3614 writeV3F1000(os, minpos);
3615 writeV3F1000(os, maxpos);
3616 writeV3F1000(os, minvel);
3617 writeV3F1000(os, maxvel);
3618 writeV3F1000(os, minacc);
3619 writeV3F1000(os, maxacc);
3620 writeF1000(os, minexptime);
3621 writeF1000(os, maxexptime);
3622 writeF1000(os, minsize);
3623 writeF1000(os, maxsize);
3624 writeU8(os, collisiondetection);
3625 os<<serializeLongString(texture);
3629 std::string s = os.str();
3630 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3632 m_con.Send(peer_id, 0, data, true);
3635 // Adds a ParticleSpawner on all peers
3636 void Server::SendAddParticleSpawnerAll(u16 amount, float spawntime, v3f minpos, v3f maxpos,
3637 v3f minvel, v3f maxvel, v3f minacc, v3f maxacc, float minexptime, float maxexptime,
3638 float minsize, float maxsize, bool collisiondetection, std::string texture, u32 id)
3640 for(std::map<u16, RemoteClient*>::iterator
3641 i = m_clients.begin();
3642 i != m_clients.end(); i++)
3644 // Get client and check that it is valid
3645 RemoteClient *client = i->second;
3646 assert(client->peer_id == i->first);
3647 if(client->serialization_version == SER_FMT_VER_INVALID)
3650 SendAddParticleSpawner(client->peer_id, amount, spawntime,
3651 minpos, maxpos, minvel, maxvel, minacc, maxacc,
3652 minexptime, maxexptime, minsize, maxsize, collisiondetection, texture, id);
3656 void Server::SendDeleteParticleSpawner(u16 peer_id, u32 id)
3658 DSTACK(__FUNCTION_NAME);
3660 std::ostringstream os(std::ios_base::binary);
3661 writeU16(os, TOCLIENT_DELETE_PARTICLESPAWNER);
3666 std::string s = os.str();
3667 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3669 m_con.Send(peer_id, 0, data, true);
3672 void Server::SendDeleteParticleSpawnerAll(u32 id)
3674 for(std::map<u16, RemoteClient*>::iterator
3675 i = m_clients.begin();
3676 i != m_clients.end(); i++)
3678 // Get client and check that it is valid
3679 RemoteClient *client = i->second;
3680 assert(client->peer_id == i->first);
3681 if(client->serialization_version == SER_FMT_VER_INVALID)
3684 SendDeleteParticleSpawner(client->peer_id, id);
3688 void Server::SendHUDAdd(u16 peer_id, u32 id, HudElement *form)
3690 std::ostringstream os(std::ios_base::binary);
3693 writeU16(os, TOCLIENT_HUDADD);
3695 writeU8(os, (u8)form->type);
3696 writeV2F1000(os, form->pos);
3697 os << serializeString(form->name);
3698 writeV2F1000(os, form->scale);
3699 os << serializeString(form->text);
3700 writeU32(os, form->number);
3701 writeU32(os, form->item);
3702 writeU32(os, form->dir);
3703 writeV2F1000(os, form->align);
3704 writeV2F1000(os, form->offset);
3707 std::string s = os.str();
3708 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3710 m_con.Send(peer_id, 0, data, true);
3713 void Server::SendHUDRemove(u16 peer_id, u32 id)
3715 std::ostringstream os(std::ios_base::binary);
3718 writeU16(os, TOCLIENT_HUDRM);
3722 std::string s = os.str();
3723 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3725 m_con.Send(peer_id, 0, data, true);
3728 void Server::SendHUDChange(u16 peer_id, u32 id, HudElementStat stat, void *value)
3730 std::ostringstream os(std::ios_base::binary);
3733 writeU16(os, TOCLIENT_HUDCHANGE);
3735 writeU8(os, (u8)stat);
3738 case HUD_STAT_SCALE:
3739 case HUD_STAT_ALIGN:
3740 case HUD_STAT_OFFSET:
3741 writeV2F1000(os, *(v2f *)value);
3745 os << serializeString(*(std::string *)value);
3747 case HUD_STAT_NUMBER:
3751 writeU32(os, *(u32 *)value);
3756 std::string s = os.str();
3757 SharedBuffer<u8> data((u8 *)s.c_str(), s.size());
3759 m_con.Send(peer_id, 0, data, true);
3762 void Server::SendHUDSetFlags(u16 peer_id, u32 flags, u32 mask)
3764 std::ostringstream os(std::ios_base::binary);
3767 writeU16(os, TOCLIENT_HUD_SET_FLAGS);
3768 writeU32(os, flags);
3772 std::string s = os.str();
3773 SharedBuffer<u8> data((u8 *)s.c_str(), s.size());
3775 m_con.Send(peer_id, 0, data, true);
3778 void Server::SendHUDSetParam(u16 peer_id, u16 param, const std::string &value)
3780 std::ostringstream os(std::ios_base::binary);
3783 writeU16(os, TOCLIENT_HUD_SET_PARAM);
3784 writeU16(os, param);
3785 os<<serializeString(value);
3788 std::string s = os.str();
3789 SharedBuffer<u8> data((u8 *)s.c_str(), s.size());
3791 m_con.Send(peer_id, 0, data, true);
3794 void Server::BroadcastChatMessage(const std::wstring &message)
3796 for(std::map<u16, RemoteClient*>::iterator
3797 i = m_clients.begin();
3798 i != m_clients.end(); ++i)
3800 // Get client and check that it is valid
3801 RemoteClient *client = i->second;
3802 assert(client->peer_id == i->first);
3803 if(client->serialization_version == SER_FMT_VER_INVALID)
3806 SendChatMessage(client->peer_id, message);
3810 void Server::SendTimeOfDay(u16 peer_id, u16 time, f32 time_speed)
3812 DSTACK(__FUNCTION_NAME);
3815 SharedBuffer<u8> data(2+2+4);
3816 writeU16(&data[0], TOCLIENT_TIME_OF_DAY);
3817 writeU16(&data[2], time);
3818 writeF1000(&data[4], time_speed);
3821 m_con.Send(peer_id, 0, data, true);
3824 void Server::SendPlayerHP(u16 peer_id)
3826 DSTACK(__FUNCTION_NAME);
3827 PlayerSAO *playersao = getPlayerSAO(peer_id);
3829 playersao->m_hp_not_sent = false;
3830 SendHP(m_con, peer_id, playersao->getHP());
3833 void Server::SendPlayerBreath(u16 peer_id)
3835 DSTACK(__FUNCTION_NAME);
3836 PlayerSAO *playersao = getPlayerSAO(peer_id);
3838 playersao->m_breath_not_sent = false;
3839 SendBreath(m_con, peer_id, playersao->getBreath());
3842 void Server::SendMovePlayer(u16 peer_id)
3844 DSTACK(__FUNCTION_NAME);
3845 Player *player = m_env->getPlayer(peer_id);
3848 std::ostringstream os(std::ios_base::binary);
3849 writeU16(os, TOCLIENT_MOVE_PLAYER);
3850 writeV3F1000(os, player->getPosition());
3851 writeF1000(os, player->getPitch());
3852 writeF1000(os, player->getYaw());
3855 v3f pos = player->getPosition();
3856 f32 pitch = player->getPitch();
3857 f32 yaw = player->getYaw();
3858 verbosestream<<"Server: Sending TOCLIENT_MOVE_PLAYER"
3859 <<" pos=("<<pos.X<<","<<pos.Y<<","<<pos.Z<<")"
3866 std::string s = os.str();
3867 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3869 m_con.Send(peer_id, 0, data, true);
3872 void Server::SendPlayerPrivileges(u16 peer_id)
3874 Player *player = m_env->getPlayer(peer_id);
3876 if(player->peer_id == PEER_ID_INEXISTENT)
3879 std::set<std::string> privs;
3880 m_script->getAuth(player->getName(), NULL, &privs);
3882 std::ostringstream os(std::ios_base::binary);
3883 writeU16(os, TOCLIENT_PRIVILEGES);
3884 writeU16(os, privs.size());
3885 for(std::set<std::string>::const_iterator i = privs.begin();
3886 i != privs.end(); i++){
3887 os<<serializeString(*i);
3891 std::string s = os.str();
3892 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3894 m_con.Send(peer_id, 0, data, true);
3897 void Server::SendPlayerInventoryFormspec(u16 peer_id)
3899 Player *player = m_env->getPlayer(peer_id);
3901 if(player->peer_id == PEER_ID_INEXISTENT)
3904 std::ostringstream os(std::ios_base::binary);
3905 writeU16(os, TOCLIENT_INVENTORY_FORMSPEC);
3906 os<<serializeLongString(player->inventory_formspec);
3909 std::string s = os.str();
3910 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3912 m_con.Send(peer_id, 0, data, true);
3915 s32 Server::playSound(const SimpleSoundSpec &spec,
3916 const ServerSoundParams ¶ms)
3918 // Find out initial position of sound
3919 bool pos_exists = false;
3920 v3f pos = params.getPos(m_env, &pos_exists);
3921 // If position is not found while it should be, cancel sound
3922 if(pos_exists != (params.type != ServerSoundParams::SSP_LOCAL))
3924 // Filter destination clients
3925 std::set<RemoteClient*> dst_clients;
3926 if(params.to_player != "")
3928 Player *player = m_env->getPlayer(params.to_player.c_str());
3930 infostream<<"Server::playSound: Player \""<<params.to_player
3931 <<"\" not found"<<std::endl;
3934 if(player->peer_id == PEER_ID_INEXISTENT){
3935 infostream<<"Server::playSound: Player \""<<params.to_player
3936 <<"\" not connected"<<std::endl;
3939 RemoteClient *client = getClient(player->peer_id);
3940 dst_clients.insert(client);
3944 for(std::map<u16, RemoteClient*>::iterator
3945 i = m_clients.begin(); i != m_clients.end(); ++i)
3947 RemoteClient *client = i->second;
3948 Player *player = m_env->getPlayer(client->peer_id);
3952 if(player->getPosition().getDistanceFrom(pos) >
3953 params.max_hear_distance)
3956 dst_clients.insert(client);
3959 if(dst_clients.size() == 0)
3962 s32 id = m_next_sound_id++;
3963 // The sound will exist as a reference in m_playing_sounds
3964 m_playing_sounds[id] = ServerPlayingSound();
3965 ServerPlayingSound &psound = m_playing_sounds[id];
3966 psound.params = params;
3967 for(std::set<RemoteClient*>::iterator i = dst_clients.begin();
3968 i != dst_clients.end(); i++)
3969 psound.clients.insert((*i)->peer_id);
3971 std::ostringstream os(std::ios_base::binary);
3972 writeU16(os, TOCLIENT_PLAY_SOUND);
3974 os<<serializeString(spec.name);
3975 writeF1000(os, spec.gain * params.gain);
3976 writeU8(os, params.type);
3977 writeV3F1000(os, pos);
3978 writeU16(os, params.object);
3979 writeU8(os, params.loop);
3981 std::string s = os.str();
3982 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3984 for(std::set<RemoteClient*>::iterator i = dst_clients.begin();
3985 i != dst_clients.end(); i++){
3987 m_con.Send((*i)->peer_id, 0, data, true);
3991 void Server::stopSound(s32 handle)
3993 // Get sound reference
3994 std::map<s32, ServerPlayingSound>::iterator i =
3995 m_playing_sounds.find(handle);
3996 if(i == m_playing_sounds.end())
3998 ServerPlayingSound &psound = i->second;
4000 std::ostringstream os(std::ios_base::binary);
4001 writeU16(os, TOCLIENT_STOP_SOUND);
4002 writeS32(os, handle);
4004 std::string s = os.str();
4005 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
4007 for(std::set<u16>::iterator i = psound.clients.begin();
4008 i != psound.clients.end(); i++){
4010 m_con.Send(*i, 0, data, true);
4012 // Remove sound reference
4013 m_playing_sounds.erase(i);
4016 void Server::sendRemoveNode(v3s16 p, u16 ignore_id,
4017 std::list<u16> *far_players, float far_d_nodes)
4019 float maxd = far_d_nodes*BS;
4020 v3f p_f = intToFloat(p, BS);
4024 SharedBuffer<u8> reply(replysize);
4025 writeU16(&reply[0], TOCLIENT_REMOVENODE);
4026 writeS16(&reply[2], p.X);
4027 writeS16(&reply[4], p.Y);
4028 writeS16(&reply[6], p.Z);
4030 for(std::map<u16, RemoteClient*>::iterator
4031 i = m_clients.begin();
4032 i != m_clients.end(); ++i)
4034 // Get client and check that it is valid
4035 RemoteClient *client = i->second;
4036 assert(client->peer_id == i->first);
4037 if(client->serialization_version == SER_FMT_VER_INVALID)
4040 // Don't send if it's the same one
4041 if(client->peer_id == ignore_id)
4047 Player *player = m_env->getPlayer(client->peer_id);
4050 // If player is far away, only set modified blocks not sent
4051 v3f player_pos = player->getPosition();
4052 if(player_pos.getDistanceFrom(p_f) > maxd)
4054 far_players->push_back(client->peer_id);
4061 m_con.Send(client->peer_id, 0, reply, true);
4065 void Server::sendAddNode(v3s16 p, MapNode n, u16 ignore_id,
4066 std::list<u16> *far_players, float far_d_nodes)
4068 float maxd = far_d_nodes*BS;
4069 v3f p_f = intToFloat(p, BS);
4071 for(std::map<u16, RemoteClient*>::iterator
4072 i = m_clients.begin();
4073 i != m_clients.end(); ++i)
4075 // Get client and check that it is valid
4076 RemoteClient *client = i->second;
4077 assert(client->peer_id == i->first);
4078 if(client->serialization_version == SER_FMT_VER_INVALID)
4081 // Don't send if it's the same one
4082 if(client->peer_id == ignore_id)
4088 Player *player = m_env->getPlayer(client->peer_id);
4091 // If player is far away, only set modified blocks not sent
4092 v3f player_pos = player->getPosition();
4093 if(player_pos.getDistanceFrom(p_f) > maxd)
4095 far_players->push_back(client->peer_id);
4102 u32 replysize = 8 + MapNode::serializedLength(client->serialization_version);
4103 SharedBuffer<u8> reply(replysize);
4104 writeU16(&reply[0], TOCLIENT_ADDNODE);
4105 writeS16(&reply[2], p.X);
4106 writeS16(&reply[4], p.Y);
4107 writeS16(&reply[6], p.Z);
4108 n.serialize(&reply[8], client->serialization_version);
4111 m_con.Send(client->peer_id, 0, reply, true);
4115 void Server::setBlockNotSent(v3s16 p)
4117 for(std::map<u16, RemoteClient*>::iterator
4118 i = m_clients.begin();
4119 i != m_clients.end(); ++i)
4121 RemoteClient *client = i->second;
4122 client->SetBlockNotSent(p);
4126 void Server::SendBlockNoLock(u16 peer_id, MapBlock *block, u8 ver, u16 net_proto_version)
4128 DSTACK(__FUNCTION_NAME);
4130 v3s16 p = block->getPos();
4134 bool completely_air = true;
4135 for(s16 z0=0; z0<MAP_BLOCKSIZE; z0++)
4136 for(s16 x0=0; x0<MAP_BLOCKSIZE; x0++)
4137 for(s16 y0=0; y0<MAP_BLOCKSIZE; y0++)
4139 if(block->getNodeNoEx(v3s16(x0,y0,z0)).d != CONTENT_AIR)
4141 completely_air = false;
4142 x0 = y0 = z0 = MAP_BLOCKSIZE; // Break out
4147 infostream<<"Server: Sending block ("<<p.X<<","<<p.Y<<","<<p.Z<<"): ";
4149 infostream<<"[completely air] ";
4150 infostream<<std::endl;
4154 Create a packet with the block in the right format
4157 std::ostringstream os(std::ios_base::binary);
4158 block->serialize(os, ver, false);
4159 block->serializeNetworkSpecific(os, net_proto_version);
4160 std::string s = os.str();
4161 SharedBuffer<u8> blockdata((u8*)s.c_str(), s.size());
4163 u32 replysize = 8 + blockdata.getSize();
4164 SharedBuffer<u8> reply(replysize);
4165 writeU16(&reply[0], TOCLIENT_BLOCKDATA);
4166 writeS16(&reply[2], p.X);
4167 writeS16(&reply[4], p.Y);
4168 writeS16(&reply[6], p.Z);
4169 memcpy(&reply[8], *blockdata, blockdata.getSize());
4171 /*infostream<<"Server: Sending block ("<<p.X<<","<<p.Y<<","<<p.Z<<")"
4172 <<": \tpacket size: "<<replysize<<std::endl;*/
4177 m_con.Send(peer_id, 1, reply, true);
4180 void Server::SendBlocks(float dtime)
4182 DSTACK(__FUNCTION_NAME);
4184 JMutexAutoLock envlock(m_env_mutex);
4185 JMutexAutoLock conlock(m_con_mutex);
4187 ScopeProfiler sp(g_profiler, "Server: sel and send blocks to clients");
4189 std::vector<PrioritySortedBlockTransfer> queue;
4191 s32 total_sending = 0;
4194 ScopeProfiler sp(g_profiler, "Server: selecting blocks for sending");
4196 for(std::map<u16, RemoteClient*>::iterator
4197 i = m_clients.begin();
4198 i != m_clients.end(); ++i)
4200 RemoteClient *client = i->second;
4201 assert(client->peer_id == i->first);
4203 // If definitions and textures have not been sent, don't
4204 // send MapBlocks either
4205 if(!client->definitions_sent)
4208 total_sending += client->SendingCount();
4210 if(client->serialization_version == SER_FMT_VER_INVALID)
4213 client->GetNextBlocks(this, dtime, queue);
4218 // Lowest priority number comes first.
4219 // Lowest is most important.
4220 std::sort(queue.begin(), queue.end());
4222 for(u32 i=0; i<queue.size(); i++)
4224 //TODO: Calculate limit dynamically
4225 if(total_sending >= g_settings->getS32
4226 ("max_simultaneous_block_sends_server_total"))
4229 PrioritySortedBlockTransfer q = queue[i];
4231 MapBlock *block = NULL;
4234 block = m_env->getMap().getBlockNoCreate(q.pos);
4236 catch(InvalidPositionException &e)
4241 RemoteClient *client = getClientNoEx(q.peer_id);
4247 SendBlockNoLock(q.peer_id, block, client->serialization_version, client->net_proto_version);
4249 client->SentBlock(q.pos);
4255 void Server::fillMediaCache()
4257 DSTACK(__FUNCTION_NAME);
4259 infostream<<"Server: Calculating media file checksums"<<std::endl;
4261 // Collect all media file paths
4262 std::list<std::string> paths;
4263 for(std::vector<ModSpec>::iterator i = m_mods.begin();
4264 i != m_mods.end(); i++){
4265 const ModSpec &mod = *i;
4266 paths.push_back(mod.path + DIR_DELIM + "textures");
4267 paths.push_back(mod.path + DIR_DELIM + "sounds");
4268 paths.push_back(mod.path + DIR_DELIM + "media");
4269 paths.push_back(mod.path + DIR_DELIM + "models");
4271 paths.push_back(porting::path_user + DIR_DELIM + "textures" + DIR_DELIM + "server");
4273 // Collect media file information from paths into cache
4274 for(std::list<std::string>::iterator i = paths.begin();
4275 i != paths.end(); i++)
4277 std::string mediapath = *i;
4278 std::vector<fs::DirListNode> dirlist = fs::GetDirListing(mediapath);
4279 for(u32 j=0; j<dirlist.size(); j++){
4280 if(dirlist[j].dir) // Ignode dirs
4282 std::string filename = dirlist[j].name;
4283 // If name contains illegal characters, ignore the file
4284 if(!string_allowed(filename, TEXTURENAME_ALLOWED_CHARS)){
4285 infostream<<"Server: ignoring illegal file name: \""
4286 <<filename<<"\""<<std::endl;
4289 // If name is not in a supported format, ignore it
4290 const char *supported_ext[] = {
4291 ".png", ".jpg", ".bmp", ".tga",
4292 ".pcx", ".ppm", ".psd", ".wal", ".rgb",
4294 ".x", ".b3d", ".md2", ".obj",
4297 if(removeStringEnd(filename, supported_ext) == ""){
4298 infostream<<"Server: ignoring unsupported file extension: \""
4299 <<filename<<"\""<<std::endl;
4302 // Ok, attempt to load the file and add to cache
4303 std::string filepath = mediapath + DIR_DELIM + filename;
4305 std::ifstream fis(filepath.c_str(), std::ios_base::binary);
4306 if(fis.good() == false){
4307 errorstream<<"Server::fillMediaCache(): Could not open \""
4308 <<filename<<"\" for reading"<<std::endl;
4311 std::ostringstream tmp_os(std::ios_base::binary);
4315 fis.read(buf, 1024);
4316 std::streamsize len = fis.gcount();
4317 tmp_os.write(buf, len);
4326 errorstream<<"Server::fillMediaCache(): Failed to read \""
4327 <<filename<<"\""<<std::endl;
4330 if(tmp_os.str().length() == 0){
4331 errorstream<<"Server::fillMediaCache(): Empty file \""
4332 <<filepath<<"\""<<std::endl;
4337 sha1.addBytes(tmp_os.str().c_str(), tmp_os.str().length());
4339 unsigned char *digest = sha1.getDigest();
4340 std::string sha1_base64 = base64_encode(digest, 20);
4341 std::string sha1_hex = hex_encode((char*)digest, 20);
4345 this->m_media[filename] = MediaInfo(filepath, sha1_base64);
4346 verbosestream<<"Server: "<<sha1_hex<<" is "<<filename<<std::endl;
4351 struct SendableMediaAnnouncement
4354 std::string sha1_digest;
4356 SendableMediaAnnouncement(const std::string name_="",
4357 const std::string sha1_digest_=""):
4359 sha1_digest(sha1_digest_)
4363 void Server::sendMediaAnnouncement(u16 peer_id)
4365 DSTACK(__FUNCTION_NAME);
4367 verbosestream<<"Server: Announcing files to id("<<peer_id<<")"
4370 std::list<SendableMediaAnnouncement> file_announcements;
4372 for(std::map<std::string, MediaInfo>::iterator i = m_media.begin();
4373 i != m_media.end(); i++){
4375 file_announcements.push_back(
4376 SendableMediaAnnouncement(i->first, i->second.sha1_digest));
4380 std::ostringstream os(std::ios_base::binary);
4388 u16 length of sha1_digest
4393 writeU16(os, TOCLIENT_ANNOUNCE_MEDIA);
4394 writeU16(os, file_announcements.size());
4396 for(std::list<SendableMediaAnnouncement>::iterator
4397 j = file_announcements.begin();
4398 j != file_announcements.end(); ++j){
4399 os<<serializeString(j->name);
4400 os<<serializeString(j->sha1_digest);
4402 os<<serializeString(g_settings->get("remote_media"));
4405 std::string s = os.str();
4406 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
4409 m_con.Send(peer_id, 0, data, true);
4412 struct SendableMedia
4418 SendableMedia(const std::string &name_="", const std::string path_="",
4419 const std::string &data_=""):
4426 void Server::sendRequestedMedia(u16 peer_id,
4427 const std::list<MediaRequest> &tosend)
4429 DSTACK(__FUNCTION_NAME);
4431 verbosestream<<"Server::sendRequestedMedia(): "
4432 <<"Sending files to client"<<std::endl;
4436 // Put 5kB in one bunch (this is not accurate)
4437 u32 bytes_per_bunch = 5000;
4439 std::vector< std::list<SendableMedia> > file_bunches;
4440 file_bunches.push_back(std::list<SendableMedia>());
4442 u32 file_size_bunch_total = 0;
4444 for(std::list<MediaRequest>::const_iterator i = tosend.begin();
4445 i != tosend.end(); ++i)
4447 if(m_media.find(i->name) == m_media.end()){
4448 errorstream<<"Server::sendRequestedMedia(): Client asked for "
4449 <<"unknown file \""<<(i->name)<<"\""<<std::endl;
4453 //TODO get path + name
4454 std::string tpath = m_media[(*i).name].path;
4457 std::ifstream fis(tpath.c_str(), std::ios_base::binary);
4458 if(fis.good() == false){
4459 errorstream<<"Server::sendRequestedMedia(): Could not open \""
4460 <<tpath<<"\" for reading"<<std::endl;
4463 std::ostringstream tmp_os(std::ios_base::binary);
4467 fis.read(buf, 1024);
4468 std::streamsize len = fis.gcount();
4469 tmp_os.write(buf, len);
4470 file_size_bunch_total += len;
4479 errorstream<<"Server::sendRequestedMedia(): Failed to read \""
4480 <<(*i).name<<"\""<<std::endl;
4483 /*infostream<<"Server::sendRequestedMedia(): Loaded \""
4484 <<tname<<"\""<<std::endl;*/
4486 file_bunches[file_bunches.size()-1].push_back(
4487 SendableMedia((*i).name, tpath, tmp_os.str()));
4489 // Start next bunch if got enough data
4490 if(file_size_bunch_total >= bytes_per_bunch){
4491 file_bunches.push_back(std::list<SendableMedia>());
4492 file_size_bunch_total = 0;
4497 /* Create and send packets */
4499 u32 num_bunches = file_bunches.size();
4500 for(u32 i=0; i<num_bunches; i++)
4502 std::ostringstream os(std::ios_base::binary);
4506 u16 total number of texture bunches
4507 u16 index of this bunch
4508 u32 number of files in this bunch
4517 writeU16(os, TOCLIENT_MEDIA);
4518 writeU16(os, num_bunches);
4520 writeU32(os, file_bunches[i].size());
4522 for(std::list<SendableMedia>::iterator
4523 j = file_bunches[i].begin();
4524 j != file_bunches[i].end(); ++j){
4525 os<<serializeString(j->name);
4526 os<<serializeLongString(j->data);
4530 std::string s = os.str();
4531 verbosestream<<"Server::sendRequestedMedia(): bunch "
4532 <<i<<"/"<<num_bunches
4533 <<" files="<<file_bunches[i].size()
4534 <<" size=" <<s.size()<<std::endl;
4535 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
4537 m_con.Send(peer_id, 0, data, true);
4541 void Server::sendDetachedInventory(const std::string &name, u16 peer_id)
4543 if(m_detached_inventories.count(name) == 0){
4544 errorstream<<__FUNCTION_NAME<<": \""<<name<<"\" not found"<<std::endl;
4547 Inventory *inv = m_detached_inventories[name];
4549 std::ostringstream os(std::ios_base::binary);
4550 writeU16(os, TOCLIENT_DETACHED_INVENTORY);
4551 os<<serializeString(name);
4555 std::string s = os.str();
4556 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
4558 m_con.Send(peer_id, 0, data, true);
4561 void Server::sendDetachedInventoryToAll(const std::string &name)
4563 DSTACK(__FUNCTION_NAME);
4565 for(std::map<u16, RemoteClient*>::iterator
4566 i = m_clients.begin();
4567 i != m_clients.end(); ++i){
4568 RemoteClient *client = i->second;
4569 sendDetachedInventory(name, client->peer_id);
4573 void Server::sendDetachedInventories(u16 peer_id)
4575 DSTACK(__FUNCTION_NAME);
4577 for(std::map<std::string, Inventory*>::iterator
4578 i = m_detached_inventories.begin();
4579 i != m_detached_inventories.end(); i++){
4580 const std::string &name = i->first;
4581 //Inventory *inv = i->second;
4582 sendDetachedInventory(name, peer_id);
4590 void Server::DiePlayer(u16 peer_id)
4592 DSTACK(__FUNCTION_NAME);
4594 PlayerSAO *playersao = getPlayerSAO(peer_id);
4597 infostream<<"Server::DiePlayer(): Player "
4598 <<playersao->getPlayer()->getName()
4599 <<" dies"<<std::endl;
4601 playersao->setHP(0);
4603 // Trigger scripted stuff
4604 m_script->on_dieplayer(playersao);
4606 SendPlayerHP(peer_id);
4607 SendDeathscreen(m_con, peer_id, false, v3f(0,0,0));
4610 void Server::RespawnPlayer(u16 peer_id)
4612 DSTACK(__FUNCTION_NAME);
4614 PlayerSAO *playersao = getPlayerSAO(peer_id);
4617 infostream<<"Server::RespawnPlayer(): Player "
4618 <<playersao->getPlayer()->getName()
4619 <<" respawns"<<std::endl;
4621 playersao->setHP(PLAYER_MAX_HP);
4623 bool repositioned = m_script->on_respawnplayer(playersao);
4625 v3f pos = findSpawnPos(m_env->getServerMap());
4626 playersao->setPos(pos);
4630 void Server::DenyAccess(u16 peer_id, const std::wstring &reason)
4632 DSTACK(__FUNCTION_NAME);
4634 SendAccessDenied(m_con, peer_id, reason);
4636 RemoteClient *client = getClientNoEx(peer_id);
4638 client->denied = true;
4640 // If there are way too many clients, get rid of denied new ones immediately
4641 if(m_clients.size() > 2 * g_settings->getU16("max_users")){
4642 verbosestream<<"Server: DenyAccess: Too many clients; getting rid of "
4643 <<"peer_id="<<peer_id<<" immediately"<<std::endl;
4644 // Delete peer to stop sending it data
4645 m_con.DeletePeer(peer_id);
4646 // Delete client also to stop block sends and other stuff
4647 DeleteClient(peer_id, CDR_DENY);
4651 void Server::DeleteClient(u16 peer_id, ClientDeletionReason reason)
4653 DSTACK(__FUNCTION_NAME);
4656 std::map<u16, RemoteClient*>::iterator n;
4657 n = m_clients.find(peer_id);
4658 // The client may not exist; clients are immediately removed if their
4659 // access is denied, and this event occurs later then.
4660 if(n == m_clients.end())
4664 Mark objects to be not known by the client
4666 RemoteClient *client = n->second;
4668 for(std::set<u16>::iterator
4669 i = client->m_known_objects.begin();
4670 i != client->m_known_objects.end(); ++i)
4674 ServerActiveObject* obj = m_env->getActiveObject(id);
4676 if(obj && obj->m_known_by_count > 0)
4677 obj->m_known_by_count--;
4681 Clear references to playing sounds
4683 for(std::map<s32, ServerPlayingSound>::iterator
4684 i = m_playing_sounds.begin();
4685 i != m_playing_sounds.end();)
4687 ServerPlayingSound &psound = i->second;
4688 psound.clients.erase(peer_id);
4689 if(psound.clients.size() == 0)
4690 m_playing_sounds.erase(i++);
4695 Player *player = m_env->getPlayer(peer_id);
4697 // Collect information about leaving in chat
4698 std::wstring message;
4700 if(player != NULL && reason != CDR_DENY)
4702 std::wstring name = narrow_to_wide(player->getName());
4705 message += L" left the game.";
4706 if(reason == CDR_TIMEOUT)
4707 message += L" (timed out)";
4711 /* Run scripts and remove from environment */
4715 PlayerSAO *playersao = player->getPlayerSAO();
4718 m_script->on_leaveplayer(playersao);
4720 playersao->disconnected();
4728 if(player != NULL && reason != CDR_DENY)
4730 std::ostringstream os(std::ios_base::binary);
4731 for(std::map<u16, RemoteClient*>::iterator
4732 i = m_clients.begin();
4733 i != m_clients.end(); ++i)
4735 RemoteClient *client = i->second;
4736 assert(client->peer_id == i->first);
4737 if(client->serialization_version == SER_FMT_VER_INVALID)
4740 Player *player = m_env->getPlayer(client->peer_id);
4743 // Get name of player
4744 os<<player->getName()<<" ";
4747 actionstream<<player->getName()<<" "
4748 <<(reason==CDR_TIMEOUT?"times out.":"leaves game.")
4749 <<" List of players: "<<os.str()<<std::endl;
4754 delete m_clients[peer_id];
4755 m_clients.erase(peer_id);
4757 // Send leave chat message to all remaining clients
4758 if(message.length() != 0)
4759 BroadcastChatMessage(message);
4762 void Server::UpdateCrafting(u16 peer_id)
4764 DSTACK(__FUNCTION_NAME);
4766 Player* player = m_env->getPlayer(peer_id);
4769 // Get a preview for crafting
4771 getCraftingResult(&player->inventory, preview, false, this);
4773 // Put the new preview in
4774 InventoryList *plist = player->inventory.getList("craftpreview");
4776 assert(plist->getSize() >= 1);
4777 plist->changeItem(0, preview);
4780 RemoteClient* Server::getClient(u16 peer_id)
4782 RemoteClient *client = getClientNoEx(peer_id);
4784 throw ClientNotFoundException("Client not found");
4787 RemoteClient* Server::getClientNoEx(u16 peer_id)
4789 std::map<u16, RemoteClient*>::iterator n;
4790 n = m_clients.find(peer_id);
4791 // The client may not exist; clients are immediately removed if their
4792 // access is denied, and this event occurs later then.
4793 if(n == m_clients.end())
4798 std::string Server::getPlayerName(u16 peer_id)
4800 Player *player = m_env->getPlayer(peer_id);
4802 return "[id="+itos(peer_id)+"]";
4803 return player->getName();
4806 PlayerSAO* Server::getPlayerSAO(u16 peer_id)
4808 Player *player = m_env->getPlayer(peer_id);
4811 return player->getPlayerSAO();
4814 std::wstring Server::getStatusString()
4816 std::wostringstream os(std::ios_base::binary);
4819 os<<L"version="<<narrow_to_wide(VERSION_STRING);
4821 os<<L", uptime="<<m_uptime.get();
4823 os<<L", max_lag="<<m_env->getMaxLagEstimate();
4824 // Information about clients
4825 std::map<u16, RemoteClient*>::iterator i;
4828 for(i = m_clients.begin(), first = true;
4829 i != m_clients.end(); ++i)
4831 // Get client and check that it is valid
4832 RemoteClient *client = i->second;
4833 assert(client->peer_id == i->first);
4834 if(client->serialization_version == SER_FMT_VER_INVALID)
4837 Player *player = m_env->getPlayer(client->peer_id);
4838 // Get name of player
4839 std::wstring name = L"unknown";
4841 name = narrow_to_wide(player->getName());
4842 // Add name to information string
4850 if(((ServerMap*)(&m_env->getMap()))->isSavingEnabled() == false)
4851 os<<std::endl<<L"# Server: "<<" WARNING: Map saving is disabled.";
4852 if(g_settings->get("motd") != "")
4853 os<<std::endl<<L"# Server: "<<narrow_to_wide(g_settings->get("motd"));
4857 std::set<std::string> Server::getPlayerEffectivePrivs(const std::string &name)
4859 std::set<std::string> privs;
4860 m_script->getAuth(name, NULL, &privs);
4864 bool Server::checkPriv(const std::string &name, const std::string &priv)
4866 std::set<std::string> privs = getPlayerEffectivePrivs(name);
4867 return (privs.count(priv) != 0);
4870 void Server::reportPrivsModified(const std::string &name)
4873 for(std::map<u16, RemoteClient*>::iterator
4874 i = m_clients.begin();
4875 i != m_clients.end(); ++i){
4876 RemoteClient *client = i->second;
4877 Player *player = m_env->getPlayer(client->peer_id);
4878 reportPrivsModified(player->getName());
4881 Player *player = m_env->getPlayer(name.c_str());
4884 SendPlayerPrivileges(player->peer_id);
4885 PlayerSAO *sao = player->getPlayerSAO();
4888 sao->updatePrivileges(
4889 getPlayerEffectivePrivs(name),
4894 void Server::reportInventoryFormspecModified(const std::string &name)
4896 Player *player = m_env->getPlayer(name.c_str());
4899 SendPlayerInventoryFormspec(player->peer_id);
4902 void Server::setIpBanned(const std::string &ip, const std::string &name)
4904 m_banmanager->add(ip, name);
4907 void Server::unsetIpBanned(const std::string &ip_or_name)
4909 m_banmanager->remove(ip_or_name);
4912 std::string Server::getBanDescription(const std::string &ip_or_name)
4914 return m_banmanager->getBanDescription(ip_or_name);
4917 void Server::notifyPlayer(const char *name, const std::wstring msg, const bool prepend = true)
4919 Player *player = m_env->getPlayer(name);
4923 SendChatMessage(player->peer_id, std::wstring(L"Server -!- ")+msg);
4925 SendChatMessage(player->peer_id, msg);
4928 bool Server::showFormspec(const char *playername, const std::string &formspec, const std::string &formname)
4930 Player *player = m_env->getPlayer(playername);
4934 infostream<<"showFormspec: couldn't find player:"<<playername<<std::endl;
4938 SendShowFormspecMessage(player->peer_id, formspec, formname);
4942 u32 Server::hudAdd(Player *player, HudElement *form) {
4946 u32 id = player->getFreeHudID();
4947 if (id < player->hud.size())
4948 player->hud[id] = form;
4950 player->hud.push_back(form);
4952 SendHUDAdd(player->peer_id, id, form);
4956 bool Server::hudRemove(Player *player, u32 id) {
4957 if (!player || id >= player->hud.size() || !player->hud[id])
4960 delete player->hud[id];
4961 player->hud[id] = NULL;
4963 SendHUDRemove(player->peer_id, id);
4967 bool Server::hudChange(Player *player, u32 id, HudElementStat stat, void *data) {
4971 SendHUDChange(player->peer_id, id, stat, data);
4975 bool Server::hudSetFlags(Player *player, u32 flags, u32 mask) {
4979 SendHUDSetFlags(player->peer_id, flags, mask);
4983 bool Server::hudSetHotbarItemcount(Player *player, s32 hotbar_itemcount) {
4986 if (hotbar_itemcount <= 0 || hotbar_itemcount > HUD_HOTBAR_ITEMCOUNT_MAX)
4989 std::ostringstream os(std::ios::binary);
4990 writeS32(os, hotbar_itemcount);
4991 SendHUDSetParam(player->peer_id, HUD_PARAM_HOTBAR_ITEMCOUNT, os.str());
4995 void Server::notifyPlayers(const std::wstring msg)
4997 BroadcastChatMessage(msg);
5000 void Server::spawnParticle(const char *playername, v3f pos,
5001 v3f velocity, v3f acceleration,
5002 float expirationtime, float size, bool
5003 collisiondetection, std::string texture)
5005 Player *player = m_env->getPlayer(playername);
5008 SendSpawnParticle(player->peer_id, pos, velocity, acceleration,
5009 expirationtime, size, collisiondetection, texture);
5012 void Server::spawnParticleAll(v3f pos, v3f velocity, v3f acceleration,
5013 float expirationtime, float size,
5014 bool collisiondetection, std::string texture)
5016 SendSpawnParticleAll(pos, velocity, acceleration,
5017 expirationtime, size, collisiondetection, texture);
5020 u32 Server::addParticleSpawner(const char *playername,
5021 u16 amount, float spawntime,
5022 v3f minpos, v3f maxpos,
5023 v3f minvel, v3f maxvel,
5024 v3f minacc, v3f maxacc,
5025 float minexptime, float maxexptime,
5026 float minsize, float maxsize,
5027 bool collisiondetection, std::string texture)
5029 Player *player = m_env->getPlayer(playername);
5034 for(;;) // look for unused particlespawner id
5037 if (std::find(m_particlespawner_ids.begin(),
5038 m_particlespawner_ids.end(), id)
5039 == m_particlespawner_ids.end())
5041 m_particlespawner_ids.push_back(id);
5046 SendAddParticleSpawner(player->peer_id, amount, spawntime,
5047 minpos, maxpos, minvel, maxvel, minacc, maxacc,
5048 minexptime, maxexptime, minsize, maxsize,
5049 collisiondetection, texture, id);
5054 u32 Server::addParticleSpawnerAll(u16 amount, float spawntime,
5055 v3f minpos, v3f maxpos,
5056 v3f minvel, v3f maxvel,
5057 v3f minacc, v3f maxacc,
5058 float minexptime, float maxexptime,
5059 float minsize, float maxsize,
5060 bool collisiondetection, std::string texture)
5063 for(;;) // look for unused particlespawner id
5066 if (std::find(m_particlespawner_ids.begin(),
5067 m_particlespawner_ids.end(), id)
5068 == m_particlespawner_ids.end())
5070 m_particlespawner_ids.push_back(id);
5075 SendAddParticleSpawnerAll(amount, spawntime,
5076 minpos, maxpos, minvel, maxvel, minacc, maxacc,
5077 minexptime, maxexptime, minsize, maxsize,
5078 collisiondetection, texture, id);
5083 void Server::deleteParticleSpawner(const char *playername, u32 id)
5085 Player *player = m_env->getPlayer(playername);
5089 m_particlespawner_ids.erase(
5090 std::remove(m_particlespawner_ids.begin(),
5091 m_particlespawner_ids.end(), id),
5092 m_particlespawner_ids.end());
5093 SendDeleteParticleSpawner(player->peer_id, id);
5096 void Server::deleteParticleSpawnerAll(u32 id)
5098 m_particlespawner_ids.erase(
5099 std::remove(m_particlespawner_ids.begin(),
5100 m_particlespawner_ids.end(), id),
5101 m_particlespawner_ids.end());
5102 SendDeleteParticleSpawnerAll(id);
5105 Inventory* Server::createDetachedInventory(const std::string &name)
5107 if(m_detached_inventories.count(name) > 0){
5108 infostream<<"Server clearing detached inventory \""<<name<<"\""<<std::endl;
5109 delete m_detached_inventories[name];
5111 infostream<<"Server creating detached inventory \""<<name<<"\""<<std::endl;
5113 Inventory *inv = new Inventory(m_itemdef);
5115 m_detached_inventories[name] = inv;
5116 sendDetachedInventoryToAll(name);
5123 BoolScopeSet(bool *dst, bool val):
5126 m_orig_state = *m_dst;
5131 *m_dst = m_orig_state;
5138 // actions: time-reversed list
5139 // Return value: success/failure
5140 bool Server::rollbackRevertActions(const std::list<RollbackAction> &actions,
5141 std::list<std::string> *log)
5143 infostream<<"Server::rollbackRevertActions(len="<<actions.size()<<")"<<std::endl;
5144 ServerMap *map = (ServerMap*)(&m_env->getMap());
5145 // Disable rollback report sink while reverting
5146 BoolScopeSet rollback_scope_disable(&m_rollback_sink_enabled, false);
5148 // Fail if no actions to handle
5149 if(actions.empty()){
5150 log->push_back("Nothing to do.");
5157 for(std::list<RollbackAction>::const_iterator
5158 i = actions.begin();
5159 i != actions.end(); i++)
5161 const RollbackAction &action = *i;
5163 bool success = action.applyRevert(map, this, this);
5166 std::ostringstream os;
5167 os<<"Revert of step ("<<num_tried<<") "<<action.toString()<<" failed";
5168 infostream<<"Map::rollbackRevertActions(): "<<os.str()<<std::endl;
5170 log->push_back(os.str());
5172 std::ostringstream os;
5173 os<<"Successfully reverted step ("<<num_tried<<") "<<action.toString();
5174 infostream<<"Map::rollbackRevertActions(): "<<os.str()<<std::endl;
5176 log->push_back(os.str());
5180 infostream<<"Map::rollbackRevertActions(): "<<num_failed<<"/"<<num_tried
5181 <<" failed"<<std::endl;
5183 // Call it done if less than half failed
5184 return num_failed <= num_tried/2;
5187 // IGameDef interface
5189 IItemDefManager* Server::getItemDefManager()
5193 INodeDefManager* Server::getNodeDefManager()
5197 ICraftDefManager* Server::getCraftDefManager()
5201 ITextureSource* Server::getTextureSource()
5205 IShaderSource* Server::getShaderSource()
5209 u16 Server::allocateUnknownNodeId(const std::string &name)
5211 return m_nodedef->allocateDummy(name);
5213 ISoundManager* Server::getSoundManager()
5215 return &dummySoundManager;
5217 MtEventManager* Server::getEventManager()
5221 IRollbackReportSink* Server::getRollbackReportSink()
5223 if(!m_enable_rollback_recording)
5225 if(!m_rollback_sink_enabled)
5230 IWritableItemDefManager* Server::getWritableItemDefManager()
5234 IWritableNodeDefManager* Server::getWritableNodeDefManager()
5238 IWritableCraftDefManager* Server::getWritableCraftDefManager()
5243 const ModSpec* Server::getModSpec(const std::string &modname)
5245 for(std::vector<ModSpec>::iterator i = m_mods.begin();
5246 i != m_mods.end(); i++){
5247 const ModSpec &mod = *i;
5248 if(mod.name == modname)
5253 void Server::getModNames(std::list<std::string> &modlist)
5255 for(std::vector<ModSpec>::iterator i = m_mods.begin(); i != m_mods.end(); i++)
5257 modlist.push_back(i->name);
5260 std::string Server::getBuiltinLuaPath()
5262 return porting::path_share + DIR_DELIM + "builtin";
5265 v3f findSpawnPos(ServerMap &map)
5267 //return v3f(50,50,50)*BS;
5272 nodepos = v2s16(0,0);
5277 s16 water_level = map.m_mgparams->water_level;
5279 // Try to find a good place a few times
5280 for(s32 i=0; i<1000; i++)
5283 // We're going to try to throw the player to this position
5284 v2s16 nodepos2d = v2s16(
5285 -range + (myrand() % (range * 2)),
5286 -range + (myrand() % (range * 2)));
5288 // Get ground height at point
5289 s16 groundheight = map.findGroundLevel(nodepos2d);
5290 if (groundheight <= water_level) // Don't go underwater
5292 if (groundheight > water_level + 6) // Don't go to high places
5295 nodepos = v3s16(nodepos2d.X, groundheight, nodepos2d.Y);
5296 bool is_good = false;
5298 for (s32 i = 0; i < 10; i++) {
5299 v3s16 blockpos = getNodeBlockPos(nodepos);
5300 map.emergeBlock(blockpos, true);
5301 content_t c = map.getNodeNoEx(nodepos).getContent();
5302 if (c == CONTENT_AIR || c == CONTENT_IGNORE) {
5304 if (air_count >= 2){
5312 // Found a good place
5313 //infostream<<"Searched through "<<i<<" places."<<std::endl;
5319 return intToFloat(nodepos, BS);
5322 PlayerSAO* Server::emergePlayer(const char *name, u16 peer_id)
5324 RemotePlayer *player = NULL;
5325 bool newplayer = false;
5328 Try to get an existing player
5330 player = static_cast<RemotePlayer*>(m_env->getPlayer(name));
5332 // If player is already connected, cancel
5333 if(player != NULL && player->peer_id != 0)
5335 infostream<<"emergePlayer(): Player already connected"<<std::endl;
5340 If player with the wanted peer_id already exists, cancel.
5342 if(m_env->getPlayer(peer_id) != NULL)
5344 infostream<<"emergePlayer(): Player with wrong name but same"
5345 " peer_id already exists"<<std::endl;
5350 Create a new player if it doesn't exist yet
5355 player = new RemotePlayer(this);
5356 player->updateName(name);
5358 /* Set player position */
5359 infostream<<"Server: Finding spawn place for player \""
5360 <<name<<"\""<<std::endl;
5361 v3f pos = findSpawnPos(m_env->getServerMap());
5362 player->setPosition(pos);
5364 /* Add player to environment */
5365 m_env->addPlayer(player);
5369 Create a new player active object
5371 PlayerSAO *playersao = new PlayerSAO(m_env, player, peer_id,
5372 getPlayerEffectivePrivs(player->getName()),
5375 /* Clean up old HUD elements from previous sessions */
5376 player->hud.clear();
5378 /* Add object to environment */
5379 m_env->addActiveObject(playersao);
5383 m_script->on_newplayer(playersao);
5385 m_script->on_joinplayer(playersao);
5390 void Server::handlePeerChange(PeerChange &c)
5392 JMutexAutoLock envlock(m_env_mutex);
5393 JMutexAutoLock conlock(m_con_mutex);
5395 if(c.type == PEER_ADDED)
5402 std::map<u16, RemoteClient*>::iterator n;
5403 n = m_clients.find(c.peer_id);
5404 // The client shouldn't already exist
5405 assert(n == m_clients.end());
5408 RemoteClient *client = new RemoteClient();
5409 client->peer_id = c.peer_id;
5410 m_clients[client->peer_id] = client;
5413 else if(c.type == PEER_REMOVED)
5419 DeleteClient(c.peer_id, c.timeout?CDR_TIMEOUT:CDR_LEAVE);
5428 void Server::handlePeerChanges()
5430 while(m_peer_change_queue.size() > 0)
5432 PeerChange c = m_peer_change_queue.pop_front();
5434 verbosestream<<"Server: Handling peer change: "
5435 <<"id="<<c.peer_id<<", timeout="<<c.timeout
5438 handlePeerChange(c);
5442 void dedicated_server_loop(Server &server, bool &kill)
5444 DSTACK(__FUNCTION_NAME);
5446 verbosestream<<"dedicated_server_loop()"<<std::endl;
5448 IntervalLimiter m_profiler_interval;
5452 float steplen = g_settings->getFloat("dedicated_server_step");
5453 // This is kind of a hack but can be done like this
5454 // because server.step() is very light
5456 ScopeProfiler sp(g_profiler, "dedicated server sleep");
5457 sleep_ms((int)(steplen*1000.0));
5459 server.step(steplen);
5461 if(server.getShutdownRequested() || kill)
5463 infostream<<"Dedicated server quitting"<<std::endl;
5465 if(g_settings->getBool("server_announce") == true)
5466 ServerList::sendAnnounce("delete");
5474 float profiler_print_interval =
5475 g_settings->getFloat("profiler_print_interval");
5476 if(profiler_print_interval != 0)
5478 if(m_profiler_interval.step(steplen, profiler_print_interval))
5480 infostream<<"Profiler:"<<std::endl;
5481 g_profiler->print(infostream);
5482 g_profiler->clear();