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 "jmutexautolock.h"
28 #include "constants.h"
33 #include "serverobject.h"
37 #include "script/cpp_api/scriptapi.h"
44 #include "content_mapnode.h"
45 #include "content_nodemeta.h"
46 #include "content_abm.h"
47 #include "content_sao.h"
52 #include "sound.h" // dummySoundManager
53 #include "event_manager.h"
55 #include "serverlist.h"
56 #include "util/string.h"
57 #include "util/pointedthing.h"
58 #include "util/mathconstants.h"
60 #include "util/serialize.h"
61 #include "defaultsettings.h"
63 void * ServerThread::Thread()
67 log_register_thread("ServerThread");
69 DSTACK(__FUNCTION_NAME);
71 BEGIN_DEBUG_EXCEPTION_HANDLER
76 //TimeTaker timer("AsyncRunStep() + Receive()");
79 //TimeTaker timer("AsyncRunStep()");
80 m_server->AsyncRunStep();
83 //infostream<<"Running m_server->Receive()"<<std::endl;
86 catch(con::NoIncomingDataException &e)
89 catch(con::PeerNotFoundException &e)
91 infostream<<"Server: PeerNotFoundException"<<std::endl;
93 catch(con::ConnectionBindFailed &e)
95 m_server->setAsyncFatalError(e.what());
99 m_server->setAsyncFatalError(e.what());
103 END_DEBUG_EXCEPTION_HANDLER(errorstream)
108 v3f ServerSoundParams::getPos(ServerEnvironment *env, bool *pos_exists) const
110 if(pos_exists) *pos_exists = false;
115 if(pos_exists) *pos_exists = true;
120 ServerActiveObject *sao = env->getActiveObject(object);
123 if(pos_exists) *pos_exists = true;
124 return sao->getBasePosition(); }
129 void RemoteClient::GetNextBlocks(Server *server, float dtime,
130 std::vector<PrioritySortedBlockTransfer> &dest)
132 DSTACK(__FUNCTION_NAME);
135 TimeTaker timer("RemoteClient::GetNextBlocks", &timer_result);*/
138 m_nothing_to_send_pause_timer -= dtime;
139 m_nearest_unsent_reset_timer += dtime;
141 if(m_nothing_to_send_pause_timer >= 0)
144 Player *player = server->m_env->getPlayer(peer_id);
145 // This can happen sometimes; clients and players are not in perfect sync.
149 // Won't send anything if already sending
150 if(m_blocks_sending.size() >= g_settings->getU16
151 ("max_simultaneous_block_sends_per_client"))
153 //infostream<<"Not sending any blocks, Queue full."<<std::endl;
157 //TimeTaker timer("RemoteClient::GetNextBlocks");
159 v3f playerpos = player->getPosition();
160 v3f playerspeed = player->getSpeed();
161 v3f playerspeeddir(0,0,0);
162 if(playerspeed.getLength() > 1.0*BS)
163 playerspeeddir = playerspeed / playerspeed.getLength();
164 // Predict to next block
165 v3f playerpos_predicted = playerpos + playerspeeddir*MAP_BLOCKSIZE*BS;
167 v3s16 center_nodepos = floatToInt(playerpos_predicted, BS);
169 v3s16 center = getNodeBlockPos(center_nodepos);
171 // Camera position and direction
172 v3f camera_pos = player->getEyePosition();
173 v3f camera_dir = v3f(0,0,1);
174 camera_dir.rotateYZBy(player->getPitch());
175 camera_dir.rotateXZBy(player->getYaw());
177 /*infostream<<"camera_dir=("<<camera_dir.X<<","<<camera_dir.Y<<","
178 <<camera_dir.Z<<")"<<std::endl;*/
181 Get the starting value of the block finder radius.
184 if(m_last_center != center)
186 m_nearest_unsent_d = 0;
187 m_last_center = center;
190 /*infostream<<"m_nearest_unsent_reset_timer="
191 <<m_nearest_unsent_reset_timer<<std::endl;*/
193 // Reset periodically to workaround for some bugs or stuff
194 if(m_nearest_unsent_reset_timer > 20.0)
196 m_nearest_unsent_reset_timer = 0;
197 m_nearest_unsent_d = 0;
198 //infostream<<"Resetting m_nearest_unsent_d for "
199 // <<server->getPlayerName(peer_id)<<std::endl;
202 //s16 last_nearest_unsent_d = m_nearest_unsent_d;
203 s16 d_start = m_nearest_unsent_d;
205 //infostream<<"d_start="<<d_start<<std::endl;
207 u16 max_simul_sends_setting = g_settings->getU16
208 ("max_simultaneous_block_sends_per_client");
209 u16 max_simul_sends_usually = max_simul_sends_setting;
212 Check the time from last addNode/removeNode.
214 Decrease send rate if player is building stuff.
216 m_time_from_building += dtime;
217 if(m_time_from_building < g_settings->getFloat(
218 "full_block_send_enable_min_time_from_building"))
220 max_simul_sends_usually
221 = LIMITED_MAX_SIMULTANEOUS_BLOCK_SENDS;
225 Number of blocks sending + number of blocks selected for sending
227 u32 num_blocks_selected = m_blocks_sending.size();
230 next time d will be continued from the d from which the nearest
231 unsent block was found this time.
233 This is because not necessarily any of the blocks found this
234 time are actually sent.
236 s32 new_nearest_unsent_d = -1;
238 s16 d_max = g_settings->getS16("max_block_send_distance");
239 s16 d_max_gen = g_settings->getS16("max_block_generate_distance");
241 // Don't loop very much at a time
242 s16 max_d_increment_at_time = 2;
243 if(d_max > d_start + max_d_increment_at_time)
244 d_max = d_start + max_d_increment_at_time;
245 /*if(d_max_gen > d_start+2)
246 d_max_gen = d_start+2;*/
248 //infostream<<"Starting from "<<d_start<<std::endl;
250 s32 nearest_emerged_d = -1;
251 s32 nearest_emergefull_d = -1;
252 s32 nearest_sent_d = -1;
253 bool queue_is_full = false;
256 for(d = d_start; d <= d_max; d++)
258 /*errorstream<<"checking d="<<d<<" for "
259 <<server->getPlayerName(peer_id)<<std::endl;*/
260 //infostream<<"RemoteClient::SendBlocks(): d="<<d<<std::endl;
263 If m_nearest_unsent_d was changed by the EmergeThread
264 (it can change it to 0 through SetBlockNotSent),
266 Else update m_nearest_unsent_d
268 /*if(m_nearest_unsent_d != last_nearest_unsent_d)
270 d = m_nearest_unsent_d;
271 last_nearest_unsent_d = m_nearest_unsent_d;
275 Get the border/face dot coordinates of a "d-radiused"
278 std::list<v3s16> list;
279 getFacePositions(list, d);
281 std::list<v3s16>::iterator li;
282 for(li=list.begin(); li!=list.end(); ++li)
284 v3s16 p = *li + center;
288 - Don't allow too many simultaneous transfers
289 - EXCEPT when the blocks are very close
291 Also, don't send blocks that are already flying.
294 // Start with the usual maximum
295 u16 max_simul_dynamic = max_simul_sends_usually;
297 // If block is very close, allow full maximum
298 if(d <= BLOCK_SEND_DISABLE_LIMITS_MAX_D)
299 max_simul_dynamic = max_simul_sends_setting;
301 // Don't select too many blocks for sending
302 if(num_blocks_selected >= max_simul_dynamic)
304 queue_is_full = true;
305 goto queue_full_break;
308 // Don't send blocks that are currently being transferred
309 if(m_blocks_sending.find(p) != m_blocks_sending.end())
315 if(p.X < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
316 || p.X > MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
317 || p.Y < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
318 || p.Y > MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
319 || p.Z < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
320 || p.Z > MAP_GENERATION_LIMIT / MAP_BLOCKSIZE)
323 // If this is true, inexistent block will be made from scratch
324 bool generate = d <= d_max_gen;
327 /*// Limit the generating area vertically to 2/3
328 if(abs(p.Y - center.Y) > d_max_gen - d_max_gen / 3)
331 // Limit the send area vertically to 1/2
332 if(abs(p.Y - center.Y) > d_max / 2)
338 If block is far away, don't generate it unless it is
344 // Block center y in nodes
345 f32 y = (f32)(p.Y * MAP_BLOCKSIZE + MAP_BLOCKSIZE/2);
346 // Don't generate if it's very high or very low
347 if(y < -64 || y > 64)
351 v2s16 p2d_nodes_center(
355 // Get ground height in nodes
356 s16 gh = server->m_env->getServerMap().findGroundLevel(
359 // If differs a lot, don't generate
360 if(fabs(gh - y) > MAP_BLOCKSIZE*2)
362 // Actually, don't even send it
368 //infostream<<"d="<<d<<std::endl;
371 Don't generate or send if not in sight
372 FIXME This only works if the client uses a small enough
373 FOV setting. The default of 72 degrees is fine.
376 float camera_fov = (72.0*M_PI/180) * 4./3.;
377 if(isBlockInSight(p, camera_pos, camera_dir, camera_fov, 10000*BS) == false)
383 Don't send already sent blocks
386 if(m_blocks_sent.find(p) != m_blocks_sent.end())
393 Check if map has this block
395 MapBlock *block = server->m_env->getMap().getBlockNoCreateNoEx(p);
397 bool surely_not_found_on_disk = false;
398 bool block_is_invalid = false;
401 // Reset usage timer, this block will be of use in the future.
402 block->resetUsageTimer();
404 // Block is dummy if data doesn't exist.
405 // It means it has been not found from disk and not generated
408 surely_not_found_on_disk = true;
411 // Block is valid if lighting is up-to-date and data exists
412 if(block->isValid() == false)
414 block_is_invalid = true;
417 /*if(block->isFullyGenerated() == false)
419 block_is_invalid = true;
424 ServerMap *map = (ServerMap*)(&server->m_env->getMap());
425 v2s16 chunkpos = map->sector_to_chunk(p2d);
426 if(map->chunkNonVolatile(chunkpos) == false)
427 block_is_invalid = true;
429 if(block->isGenerated() == false)
430 block_is_invalid = true;
433 If block is not close, don't send it unless it is near
436 Block is near ground level if night-time mesh
437 differs from day-time mesh.
441 if(block->getDayNightDiff() == false)
448 If block has been marked to not exist on disk (dummy)
449 and generating new ones is not wanted, skip block.
451 if(generate == false && surely_not_found_on_disk == true)
458 Add inexistent block to emerge queue.
460 if(block == NULL || surely_not_found_on_disk || block_is_invalid)
462 /* //TODO: Get value from somewhere
463 // Allow only one block in emerge queue
464 //if(server->m_emerge_queue.peerItemCount(peer_id) < 1)
465 // Allow two blocks in queue per client
466 //if(server->m_emerge_queue.peerItemCount(peer_id) < 2)
468 // Make it more responsive when needing to generate stuff
469 if(surely_not_found_on_disk)
471 if(server->m_emerge_queue.peerItemCount(peer_id) < max_emerge)
473 //infostream<<"Adding block to emerge queue"<<std::endl;
475 // Add it to the emerge queue and trigger the thread
478 if(generate == false)
479 flags |= BLOCK_EMERGE_FLAG_FROMDISK;
481 server->m_emerge_queue.addBlock(peer_id, p, flags);
482 server->m_emergethread.trigger();
484 if(nearest_emerged_d == -1)
485 nearest_emerged_d = d;
487 if(nearest_emergefull_d == -1)
488 nearest_emergefull_d = d;
489 goto queue_full_break;
493 if (server->m_emerge->enqueueBlockEmerge(peer_id, p, generate)) {
494 if (nearest_emerged_d == -1)
495 nearest_emerged_d = d;
497 if (nearest_emergefull_d == -1)
498 nearest_emergefull_d = d;
499 goto queue_full_break;
506 if(nearest_sent_d == -1)
510 Add block to send queue
513 /*errorstream<<"sending from d="<<d<<" to "
514 <<server->getPlayerName(peer_id)<<std::endl;*/
516 PrioritySortedBlockTransfer q((float)d, p, peer_id);
520 num_blocks_selected += 1;
525 //infostream<<"Stopped at "<<d<<std::endl;
527 // If nothing was found for sending and nothing was queued for
528 // emerging, continue next time browsing from here
529 if(nearest_emerged_d != -1){
530 new_nearest_unsent_d = nearest_emerged_d;
531 } else if(nearest_emergefull_d != -1){
532 new_nearest_unsent_d = nearest_emergefull_d;
534 if(d > g_settings->getS16("max_block_send_distance")){
535 new_nearest_unsent_d = 0;
536 m_nothing_to_send_pause_timer = 2.0;
537 /*infostream<<"GetNextBlocks(): d wrapped around for "
538 <<server->getPlayerName(peer_id)
539 <<"; setting to 0 and pausing"<<std::endl;*/
541 if(nearest_sent_d != -1)
542 new_nearest_unsent_d = nearest_sent_d;
544 new_nearest_unsent_d = d;
548 if(new_nearest_unsent_d != -1)
549 m_nearest_unsent_d = new_nearest_unsent_d;
551 /*timer_result = timer.stop(true);
552 if(timer_result != 0)
553 infostream<<"GetNextBlocks timeout: "<<timer_result<<" (!=0)"<<std::endl;*/
556 void RemoteClient::GotBlock(v3s16 p)
558 if(m_blocks_sending.find(p) != m_blocks_sending.end())
559 m_blocks_sending.erase(p);
562 /*infostream<<"RemoteClient::GotBlock(): Didn't find in"
563 " m_blocks_sending"<<std::endl;*/
564 m_excess_gotblocks++;
566 m_blocks_sent.insert(p);
569 void RemoteClient::SentBlock(v3s16 p)
571 if(m_blocks_sending.find(p) == m_blocks_sending.end())
572 m_blocks_sending[p] = 0.0;
574 infostream<<"RemoteClient::SentBlock(): Sent block"
575 " already in m_blocks_sending"<<std::endl;
578 void RemoteClient::SetBlockNotSent(v3s16 p)
580 m_nearest_unsent_d = 0;
582 if(m_blocks_sending.find(p) != m_blocks_sending.end())
583 m_blocks_sending.erase(p);
584 if(m_blocks_sent.find(p) != m_blocks_sent.end())
585 m_blocks_sent.erase(p);
588 void RemoteClient::SetBlocksNotSent(std::map<v3s16, MapBlock*> &blocks)
590 m_nearest_unsent_d = 0;
592 for(std::map<v3s16, MapBlock*>::iterator
594 i != blocks.end(); ++i)
598 if(m_blocks_sending.find(p) != m_blocks_sending.end())
599 m_blocks_sending.erase(p);
600 if(m_blocks_sent.find(p) != m_blocks_sent.end())
601 m_blocks_sent.erase(p);
609 PlayerInfo::PlayerInfo()
615 void PlayerInfo::PrintLine(std::ostream *s)
618 (*s)<<"\""<<name<<"\" ("
619 <<(position.X/10)<<","<<(position.Y/10)
620 <<","<<(position.Z/10)<<") ";
622 (*s)<<" avg_rtt="<<avg_rtt;
631 const std::string &path_world,
632 const std::string &path_config,
633 const SubgameSpec &gamespec,
634 bool simple_singleplayer_mode
636 m_path_world(path_world),
637 m_path_config(path_config),
638 m_gamespec(gamespec),
639 m_simple_singleplayer_mode(simple_singleplayer_mode),
640 m_async_fatal_error(""),
642 m_con(PROTOCOL_ID, 512, CONNECTION_TIMEOUT,
643 g_settings->getBool("enable_ipv6") && g_settings->getBool("ipv6_server"), this),
644 m_banmanager(path_world+DIR_DELIM+"ipban.txt"),
646 m_rollback_sink_enabled(true),
647 m_enable_rollback_recording(false),
650 m_itemdef(createItemDefManager()),
651 m_nodedef(createNodeDefManager()),
652 m_craftdef(createCraftDefManager()),
653 m_event(new EventManager()),
655 m_time_of_day_send_timer(0),
657 m_shutdown_requested(false),
658 m_ignore_map_edit_events(false),
659 m_ignore_map_edit_events_peer_id(0)
661 m_liquid_transform_timer = 0.0;
662 m_liquid_transform_every = 1.0;
663 m_print_info_timer = 0.0;
664 m_masterserver_timer = 0.0;
665 m_objectdata_timer = 0.0;
666 m_emergethread_trigger_timer = 0.0;
667 m_savemap_timer = 0.0;
668 m_clients_number = 0;
672 m_step_dtime_mutex.Init();
676 throw ServerError("Supplied empty world path");
678 if(!gamespec.isValid())
679 throw ServerError("Supplied invalid gamespec");
681 infostream<<"Server created for gameid \""<<m_gamespec.id<<"\"";
682 if(m_simple_singleplayer_mode)
683 infostream<<" in simple singleplayer mode"<<std::endl;
685 infostream<<std::endl;
686 infostream<<"- world: "<<m_path_world<<std::endl;
687 infostream<<"- config: "<<m_path_config<<std::endl;
688 infostream<<"- game: "<<m_gamespec.path<<std::endl;
690 // Initialize default settings and override defaults with those provided
692 set_default_settings(g_settings);
693 Settings gamedefaults;
694 getGameMinetestConfig(gamespec.path, gamedefaults);
695 override_default_settings(g_settings, &gamedefaults);
697 // Create emerge manager
698 m_emerge = new EmergeManager(this);
700 // Create rollback manager
701 std::string rollback_path = m_path_world+DIR_DELIM+"rollback.txt";
702 m_rollback = createRollbackManager(rollback_path, this);
704 // Create world if it doesn't exist
705 if(!initializeWorld(m_path_world, m_gamespec.id))
706 throw ServerError("Failed to initialize world");
708 ModConfiguration modconf(m_path_world);
709 m_mods = modconf.getMods();
710 std::vector<ModSpec> unsatisfied_mods = modconf.getUnsatisfiedMods();
711 // complain about mods with unsatisfied dependencies
712 if(!modconf.isConsistent())
714 for(std::vector<ModSpec>::iterator it = unsatisfied_mods.begin();
715 it != unsatisfied_mods.end(); ++it)
718 errorstream << "mod \"" << mod.name << "\" has unsatisfied dependencies: ";
719 for(std::set<std::string>::iterator dep_it = mod.unsatisfied_depends.begin();
720 dep_it != mod.unsatisfied_depends.end(); ++dep_it)
721 errorstream << " \"" << *dep_it << "\"";
722 errorstream << std::endl;
726 Settings worldmt_settings;
727 std::string worldmt = m_path_world + DIR_DELIM + "world.mt";
728 worldmt_settings.readConfigFile(worldmt.c_str());
729 std::vector<std::string> names = worldmt_settings.getNames();
730 std::set<std::string> load_mod_names;
731 for(std::vector<std::string>::iterator it = names.begin();
732 it != names.end(); ++it)
734 std::string name = *it;
735 if(name.compare(0,9,"load_mod_")==0 && worldmt_settings.getBool(name))
736 load_mod_names.insert(name.substr(9));
738 // complain about mods declared to be loaded, but not found
739 for(std::vector<ModSpec>::iterator it = m_mods.begin();
740 it != m_mods.end(); ++it)
741 load_mod_names.erase((*it).name);
742 for(std::vector<ModSpec>::iterator it = unsatisfied_mods.begin();
743 it != unsatisfied_mods.end(); ++it)
744 load_mod_names.erase((*it).name);
745 if(!load_mod_names.empty())
747 errorstream << "The following mods could not be found:";
748 for(std::set<std::string>::iterator it = load_mod_names.begin();
749 it != load_mod_names.end(); ++it)
750 errorstream << " \"" << (*it) << "\"";
751 errorstream << std::endl;
754 // Path to builtin.lua
755 std::string builtinpath = getBuiltinLuaPath() + DIR_DELIM + "builtin.lua";
758 JMutexAutoLock envlock(m_env_mutex);
759 JMutexAutoLock conlock(m_con_mutex);
761 // Initialize scripting
763 infostream<<"Server: Initializing Lua"<<std::endl;
765 m_script = new ScriptApi(this);
768 // Load and run builtin.lua
769 infostream<<"Server: Loading builtin.lua [\""
770 <<builtinpath<<"\"]"<<std::endl;
771 bool success = m_script->loadMod(builtinpath, "__builtin");
773 errorstream<<"Server: Failed to load and run "
774 <<builtinpath<<std::endl;
775 throw ModError("Failed to load and run "+builtinpath);
778 infostream<<"Server: Loading mods: ";
779 for(std::vector<ModSpec>::iterator i = m_mods.begin();
780 i != m_mods.end(); i++){
781 const ModSpec &mod = *i;
782 infostream<<mod.name<<" ";
784 infostream<<std::endl;
785 // Load and run "mod" scripts
786 for(std::vector<ModSpec>::iterator i = m_mods.begin();
787 i != m_mods.end(); i++){
788 const ModSpec &mod = *i;
789 std::string scriptpath = mod.path + DIR_DELIM + "init.lua";
790 infostream<<" ["<<padStringRight(mod.name, 12)<<"] [\""
791 <<scriptpath<<"\"]"<<std::endl;
792 bool success = m_script->loadMod(scriptpath, mod.name);
794 errorstream<<"Server: Failed to load and run "
795 <<scriptpath<<std::endl;
796 throw ModError("Failed to load and run "+scriptpath);
800 // Read Textures and calculate sha1 sums
803 // Apply item aliases in the node definition manager
804 m_nodedef->updateAliases(m_itemdef);
806 // Initialize Environment
807 ServerMap *servermap = new ServerMap(path_world, this, m_emerge);
808 m_env = new ServerEnvironment(servermap, m_script, this, this);
810 // Run some callbacks after the MG params have been set up but before activation
811 MapgenParams *mgparams = servermap->getMapgenParams();
812 m_script->environment_OnMapgenInit(mgparams);
814 // Initialize mapgens
815 m_emerge->initMapgens(mgparams);
817 // Give environment reference to scripting api
818 m_script->initializeEnvironment(m_env);
820 // Register us to receive map edit events
821 servermap->addEventReceiver(this);
823 // If file exists, load environment metadata
824 if(fs::PathExists(m_path_world+DIR_DELIM+"env_meta.txt"))
826 infostream<<"Server: Loading environment metadata"<<std::endl;
827 m_env->loadMeta(m_path_world);
831 infostream<<"Server: Loading players"<<std::endl;
832 m_env->deSerializePlayers(m_path_world);
835 Add some test ActiveBlockModifiers to environment
837 add_legacy_abms(m_env, m_nodedef);
839 m_liquid_transform_every = g_settings->getFloat("liquid_update");
844 infostream<<"Server destructing"<<std::endl;
847 Send shutdown message
850 JMutexAutoLock conlock(m_con_mutex);
852 std::wstring line = L"*** Server shutting down";
855 Send the message to clients
857 for(std::map<u16, RemoteClient*>::iterator
858 i = m_clients.begin();
859 i != m_clients.end(); ++i)
861 // Get client and check that it is valid
862 RemoteClient *client = i->second;
863 assert(client->peer_id == i->first);
864 if(client->serialization_version == SER_FMT_VER_INVALID)
868 SendChatMessage(client->peer_id, line);
870 catch(con::PeerNotFoundException &e)
876 JMutexAutoLock envlock(m_env_mutex);
877 JMutexAutoLock conlock(m_con_mutex);
880 Execute script shutdown hooks
882 m_script->on_shutdown();
886 JMutexAutoLock envlock(m_env_mutex);
891 infostream<<"Server: Saving players"<<std::endl;
892 m_env->serializePlayers(m_path_world);
895 Save environment metadata
897 infostream<<"Server: Saving environment metadata"<<std::endl;
898 m_env->saveMeta(m_path_world);
906 //shutdown all emerge threads first!
913 JMutexAutoLock clientslock(m_con_mutex);
915 for(std::map<u16, RemoteClient*>::iterator
916 i = m_clients.begin();
917 i != m_clients.end(); ++i)
925 // Delete things in the reverse order of creation
933 // Deinitialize scripting
934 infostream<<"Server: Deinitializing scripting"<<std::endl;
937 // Delete detached inventories
939 for(std::map<std::string, Inventory*>::iterator
940 i = m_detached_inventories.begin();
941 i != m_detached_inventories.end(); i++){
947 void Server::start(unsigned short port)
949 DSTACK(__FUNCTION_NAME);
950 infostream<<"Starting server on port "<<port<<"..."<<std::endl;
952 // Stop thread if already running
955 // Initialize connection
956 m_con.SetTimeoutMs(30);
960 m_thread.setRun(true);
963 // ASCII art for the win!
965 <<" .__ __ __ "<<std::endl
966 <<" _____ |__| ____ _____/ |_ ____ _______/ |_ "<<std::endl
967 <<" / \\| |/ \\_/ __ \\ __\\/ __ \\ / ___/\\ __\\"<<std::endl
968 <<"| Y Y \\ | | \\ ___/| | \\ ___/ \\___ \\ | | "<<std::endl
969 <<"|__|_| /__|___| /\\___ >__| \\___ >____ > |__| "<<std::endl
970 <<" \\/ \\/ \\/ \\/ \\/ "<<std::endl;
971 actionstream<<"World at ["<<m_path_world<<"]"<<std::endl;
972 actionstream<<"Server for gameid=\""<<m_gamespec.id
973 <<"\" listening on port "<<port<<"."<<std::endl;
978 DSTACK(__FUNCTION_NAME);
980 infostream<<"Server: Stopping and waiting threads"<<std::endl;
982 // Stop threads (set run=false first so both start stopping)
983 m_thread.setRun(false);
984 //m_emergethread.setRun(false);
986 //m_emergethread.stop();
988 infostream<<"Server: Threads stopped"<<std::endl;
991 void Server::step(float dtime)
993 DSTACK(__FUNCTION_NAME);
998 JMutexAutoLock lock(m_step_dtime_mutex);
999 m_step_dtime += dtime;
1001 // Throw if fatal error occurred in thread
1002 std::string async_err = m_async_fatal_error.get();
1003 if(async_err != ""){
1004 throw ServerError(async_err);
1008 void Server::AsyncRunStep()
1010 DSTACK(__FUNCTION_NAME);
1012 g_profiler->add("Server::AsyncRunStep (num)", 1);
1016 JMutexAutoLock lock1(m_step_dtime_mutex);
1017 dtime = m_step_dtime;
1021 // Send blocks to clients
1028 g_profiler->add("Server::AsyncRunStep with dtime (num)", 1);
1030 //infostream<<"Server steps "<<dtime<<std::endl;
1031 //infostream<<"Server::AsyncRunStep(): dtime="<<dtime<<std::endl;
1034 JMutexAutoLock lock1(m_step_dtime_mutex);
1035 m_step_dtime -= dtime;
1042 m_uptime.set(m_uptime.get() + dtime);
1046 // Process connection's timeouts
1047 JMutexAutoLock lock2(m_con_mutex);
1048 ScopeProfiler sp(g_profiler, "Server: connection timeout processing");
1049 m_con.RunTimeouts(dtime);
1053 // This has to be called so that the client list gets synced
1054 // with the peer list of the connection
1055 handlePeerChanges();
1059 Update time of day and overall game time
1062 JMutexAutoLock envlock(m_env_mutex);
1064 m_env->setTimeOfDaySpeed(g_settings->getFloat("time_speed"));
1067 Send to clients at constant intervals
1070 m_time_of_day_send_timer -= dtime;
1071 if(m_time_of_day_send_timer < 0.0)
1073 m_time_of_day_send_timer = g_settings->getFloat("time_send_interval");
1075 //JMutexAutoLock envlock(m_env_mutex);
1076 JMutexAutoLock conlock(m_con_mutex);
1078 for(std::map<u16, RemoteClient*>::iterator
1079 i = m_clients.begin();
1080 i != m_clients.end(); ++i)
1082 RemoteClient *client = i->second;
1083 SharedBuffer<u8> data = makePacket_TOCLIENT_TIME_OF_DAY(
1084 m_env->getTimeOfDay(), g_settings->getFloat("time_speed"));
1086 m_con.Send(client->peer_id, 0, data, true);
1092 JMutexAutoLock lock(m_env_mutex);
1094 ScopeProfiler sp(g_profiler, "SEnv step");
1095 ScopeProfiler sp2(g_profiler, "SEnv step avg", SPT_AVG);
1099 const float map_timer_and_unload_dtime = 2.92;
1100 if(m_map_timer_and_unload_interval.step(dtime, map_timer_and_unload_dtime))
1102 JMutexAutoLock lock(m_env_mutex);
1103 // Run Map's timers and unload unused data
1104 ScopeProfiler sp(g_profiler, "Server: map timer and unload");
1105 m_env->getMap().timerUpdate(map_timer_and_unload_dtime,
1106 g_settings->getFloat("server_unload_unused_data_timeout"));
1117 JMutexAutoLock lock(m_env_mutex);
1118 JMutexAutoLock lock2(m_con_mutex);
1120 ScopeProfiler sp(g_profiler, "Server: handle players");
1122 for(std::map<u16, RemoteClient*>::iterator
1123 i = m_clients.begin();
1124 i != m_clients.end(); ++i)
1126 RemoteClient *client = i->second;
1127 PlayerSAO *playersao = getPlayerSAO(client->peer_id);
1128 if(playersao == NULL)
1132 Handle player HPs (die if hp=0)
1134 if(playersao->m_hp_not_sent && g_settings->getBool("enable_damage"))
1136 if(playersao->getHP() == 0)
1137 DiePlayer(client->peer_id);
1139 SendPlayerHP(client->peer_id);
1143 Send player breath if changed
1145 if(playersao->m_breath_not_sent){
1146 SendPlayerBreath(client->peer_id);
1150 Send player inventories if necessary
1152 if(playersao->m_moved){
1153 SendMovePlayer(client->peer_id);
1154 playersao->m_moved = false;
1156 if(playersao->m_inventory_not_sent){
1157 UpdateCrafting(client->peer_id);
1158 SendInventory(client->peer_id);
1163 /* Transform liquids */
1164 m_liquid_transform_timer += dtime;
1165 if(m_liquid_transform_timer >= m_liquid_transform_every)
1167 m_liquid_transform_timer -= m_liquid_transform_every;
1169 JMutexAutoLock lock(m_env_mutex);
1171 ScopeProfiler sp(g_profiler, "Server: liquid transform");
1173 std::map<v3s16, MapBlock*> modified_blocks;
1174 m_env->getMap().transformLiquids(modified_blocks);
1179 core::map<v3s16, MapBlock*> lighting_modified_blocks;
1180 ServerMap &map = ((ServerMap&)m_env->getMap());
1181 map.updateLighting(modified_blocks, lighting_modified_blocks);
1183 // Add blocks modified by lighting to modified_blocks
1184 for(core::map<v3s16, MapBlock*>::Iterator
1185 i = lighting_modified_blocks.getIterator();
1186 i.atEnd() == false; i++)
1188 MapBlock *block = i.getNode()->getValue();
1189 modified_blocks.insert(block->getPos(), block);
1193 Set the modified blocks unsent for all the clients
1196 JMutexAutoLock lock2(m_con_mutex);
1198 for(std::map<u16, RemoteClient*>::iterator
1199 i = m_clients.begin();
1200 i != m_clients.end(); ++i)
1202 RemoteClient *client = i->second;
1204 if(modified_blocks.size() > 0)
1206 // Remove block from sent history
1207 client->SetBlocksNotSent(modified_blocks);
1212 // Periodically print some info
1214 float &counter = m_print_info_timer;
1220 JMutexAutoLock lock2(m_con_mutex);
1221 m_clients_number = 0;
1222 if(m_clients.size() != 0)
1223 infostream<<"Players:"<<std::endl;
1224 for(std::map<u16, RemoteClient*>::iterator
1225 i = m_clients.begin();
1226 i != m_clients.end(); ++i)
1228 //u16 peer_id = i.getNode()->getKey();
1229 RemoteClient *client = i->second;
1230 Player *player = m_env->getPlayer(client->peer_id);
1233 infostream<<"* "<<player->getName()<<"\t";
1234 client->PrintInfo(infostream);
1242 // send masterserver announce
1244 float &counter = m_masterserver_timer;
1245 if((!counter || counter >= 300.0) && g_settings->getBool("server_announce") == true)
1247 ServerList::sendAnnounce(!counter ? "start" : "update", m_clients_number, m_uptime.get(), m_gamespec.id, m_mods);
1254 //if(g_settings->getBool("enable_experimental"))
1258 Check added and deleted active objects
1261 //infostream<<"Server: Checking added and deleted active objects"<<std::endl;
1262 JMutexAutoLock envlock(m_env_mutex);
1263 JMutexAutoLock conlock(m_con_mutex);
1265 ScopeProfiler sp(g_profiler, "Server: checking added and deleted objs");
1267 // Radius inside which objects are active
1268 s16 radius = g_settings->getS16("active_object_send_range_blocks");
1269 radius *= MAP_BLOCKSIZE;
1271 for(std::map<u16, RemoteClient*>::iterator
1272 i = m_clients.begin();
1273 i != m_clients.end(); ++i)
1275 RemoteClient *client = i->second;
1277 // If definitions and textures have not been sent, don't
1278 // send objects either
1279 if(!client->definitions_sent)
1282 Player *player = m_env->getPlayer(client->peer_id);
1285 // This can happen if the client timeouts somehow
1286 /*infostream<<"WARNING: "<<__FUNCTION_NAME<<": Client "
1288 <<" has no associated player"<<std::endl;*/
1291 v3s16 pos = floatToInt(player->getPosition(), BS);
1293 std::set<u16> removed_objects;
1294 std::set<u16> added_objects;
1295 m_env->getRemovedActiveObjects(pos, radius,
1296 client->m_known_objects, removed_objects);
1297 m_env->getAddedActiveObjects(pos, radius,
1298 client->m_known_objects, added_objects);
1300 // Ignore if nothing happened
1301 if(removed_objects.size() == 0 && added_objects.size() == 0)
1303 //infostream<<"active objects: none changed"<<std::endl;
1307 std::string data_buffer;
1311 // Handle removed objects
1312 writeU16((u8*)buf, removed_objects.size());
1313 data_buffer.append(buf, 2);
1314 for(std::set<u16>::iterator
1315 i = removed_objects.begin();
1316 i != removed_objects.end(); ++i)
1320 ServerActiveObject* obj = m_env->getActiveObject(id);
1322 // Add to data buffer for sending
1323 writeU16((u8*)buf, id);
1324 data_buffer.append(buf, 2);
1326 // Remove from known objects
1327 client->m_known_objects.erase(id);
1329 if(obj && obj->m_known_by_count > 0)
1330 obj->m_known_by_count--;
1333 // Handle added objects
1334 writeU16((u8*)buf, added_objects.size());
1335 data_buffer.append(buf, 2);
1336 for(std::set<u16>::iterator
1337 i = added_objects.begin();
1338 i != added_objects.end(); ++i)
1342 ServerActiveObject* obj = m_env->getActiveObject(id);
1345 u8 type = ACTIVEOBJECT_TYPE_INVALID;
1347 infostream<<"WARNING: "<<__FUNCTION_NAME
1348 <<": NULL object"<<std::endl;
1350 type = obj->getSendType();
1352 // Add to data buffer for sending
1353 writeU16((u8*)buf, id);
1354 data_buffer.append(buf, 2);
1355 writeU8((u8*)buf, type);
1356 data_buffer.append(buf, 1);
1359 data_buffer.append(serializeLongString(
1360 obj->getClientInitializationData(client->net_proto_version)));
1362 data_buffer.append(serializeLongString(""));
1364 // Add to known objects
1365 client->m_known_objects.insert(id);
1368 obj->m_known_by_count++;
1372 SharedBuffer<u8> reply(2 + data_buffer.size());
1373 writeU16(&reply[0], TOCLIENT_ACTIVE_OBJECT_REMOVE_ADD);
1374 memcpy((char*)&reply[2], data_buffer.c_str(),
1375 data_buffer.size());
1377 m_con.Send(client->peer_id, 0, reply, true);
1379 verbosestream<<"Server: Sent object remove/add: "
1380 <<removed_objects.size()<<" removed, "
1381 <<added_objects.size()<<" added, "
1382 <<"packet size is "<<reply.getSize()<<std::endl;
1387 Collect a list of all the objects known by the clients
1388 and report it back to the environment.
1391 core::map<u16, bool> all_known_objects;
1393 for(core::map<u16, RemoteClient*>::Iterator
1394 i = m_clients.getIterator();
1395 i.atEnd() == false; i++)
1397 RemoteClient *client = i.getNode()->getValue();
1398 // Go through all known objects of client
1399 for(core::map<u16, bool>::Iterator
1400 i = client->m_known_objects.getIterator();
1401 i.atEnd()==false; i++)
1403 u16 id = i.getNode()->getKey();
1404 all_known_objects[id] = true;
1408 m_env->setKnownActiveObjects(whatever);
1414 Send object messages
1417 JMutexAutoLock envlock(m_env_mutex);
1418 JMutexAutoLock conlock(m_con_mutex);
1420 ScopeProfiler sp(g_profiler, "Server: sending object messages");
1423 // Value = data sent by object
1424 std::map<u16, std::list<ActiveObjectMessage>* > buffered_messages;
1426 // Get active object messages from environment
1429 ActiveObjectMessage aom = m_env->getActiveObjectMessage();
1433 std::list<ActiveObjectMessage>* message_list = NULL;
1434 std::map<u16, std::list<ActiveObjectMessage>* >::iterator n;
1435 n = buffered_messages.find(aom.id);
1436 if(n == buffered_messages.end())
1438 message_list = new std::list<ActiveObjectMessage>;
1439 buffered_messages[aom.id] = message_list;
1443 message_list = n->second;
1445 message_list->push_back(aom);
1448 // Route data to every client
1449 for(std::map<u16, RemoteClient*>::iterator
1450 i = m_clients.begin();
1451 i != m_clients.end(); ++i)
1453 RemoteClient *client = i->second;
1454 std::string reliable_data;
1455 std::string unreliable_data;
1456 // Go through all objects in message buffer
1457 for(std::map<u16, std::list<ActiveObjectMessage>* >::iterator
1458 j = buffered_messages.begin();
1459 j != buffered_messages.end(); ++j)
1461 // If object is not known by client, skip it
1463 if(client->m_known_objects.find(id) == client->m_known_objects.end())
1465 // Get message list of object
1466 std::list<ActiveObjectMessage>* list = j->second;
1467 // Go through every message
1468 for(std::list<ActiveObjectMessage>::iterator
1469 k = list->begin(); k != list->end(); ++k)
1471 // Compose the full new data with header
1472 ActiveObjectMessage aom = *k;
1473 std::string new_data;
1476 writeU16((u8*)&buf[0], aom.id);
1477 new_data.append(buf, 2);
1479 new_data += serializeString(aom.datastring);
1480 // Add data to buffer
1482 reliable_data += new_data;
1484 unreliable_data += new_data;
1488 reliable_data and unreliable_data are now ready.
1491 if(reliable_data.size() > 0)
1493 SharedBuffer<u8> reply(2 + reliable_data.size());
1494 writeU16(&reply[0], TOCLIENT_ACTIVE_OBJECT_MESSAGES);
1495 memcpy((char*)&reply[2], reliable_data.c_str(),
1496 reliable_data.size());
1498 m_con.Send(client->peer_id, 0, reply, true);
1500 if(unreliable_data.size() > 0)
1502 SharedBuffer<u8> reply(2 + unreliable_data.size());
1503 writeU16(&reply[0], TOCLIENT_ACTIVE_OBJECT_MESSAGES);
1504 memcpy((char*)&reply[2], unreliable_data.c_str(),
1505 unreliable_data.size());
1506 // Send as unreliable
1507 m_con.Send(client->peer_id, 0, reply, false);
1510 /*if(reliable_data.size() > 0 || unreliable_data.size() > 0)
1512 infostream<<"Server: Size of object message data: "
1513 <<"reliable: "<<reliable_data.size()
1514 <<", unreliable: "<<unreliable_data.size()
1519 // Clear buffered_messages
1520 for(std::map<u16, std::list<ActiveObjectMessage>* >::iterator
1521 i = buffered_messages.begin();
1522 i != buffered_messages.end(); ++i)
1528 } // enable_experimental
1531 Send queued-for-sending map edit events.
1534 // We will be accessing the environment and the connection
1535 JMutexAutoLock lock(m_env_mutex);
1536 JMutexAutoLock conlock(m_con_mutex);
1538 // Don't send too many at a time
1541 // Single change sending is disabled if queue size is not small
1542 bool disable_single_change_sending = false;
1543 if(m_unsent_map_edit_queue.size() >= 4)
1544 disable_single_change_sending = true;
1546 int event_count = m_unsent_map_edit_queue.size();
1548 // We'll log the amount of each
1551 while(m_unsent_map_edit_queue.size() != 0)
1553 MapEditEvent* event = m_unsent_map_edit_queue.pop_front();
1555 // Players far away from the change are stored here.
1556 // Instead of sending the changes, MapBlocks are set not sent
1558 std::list<u16> far_players;
1560 if(event->type == MEET_ADDNODE)
1562 //infostream<<"Server: MEET_ADDNODE"<<std::endl;
1563 prof.add("MEET_ADDNODE", 1);
1564 if(disable_single_change_sending)
1565 sendAddNode(event->p, event->n, event->already_known_by_peer,
1568 sendAddNode(event->p, event->n, event->already_known_by_peer,
1571 else if(event->type == MEET_REMOVENODE)
1573 //infostream<<"Server: MEET_REMOVENODE"<<std::endl;
1574 prof.add("MEET_REMOVENODE", 1);
1575 if(disable_single_change_sending)
1576 sendRemoveNode(event->p, event->already_known_by_peer,
1579 sendRemoveNode(event->p, event->already_known_by_peer,
1582 else if(event->type == MEET_BLOCK_NODE_METADATA_CHANGED)
1584 infostream<<"Server: MEET_BLOCK_NODE_METADATA_CHANGED"<<std::endl;
1585 prof.add("MEET_BLOCK_NODE_METADATA_CHANGED", 1);
1586 setBlockNotSent(event->p);
1588 else if(event->type == MEET_OTHER)
1590 infostream<<"Server: MEET_OTHER"<<std::endl;
1591 prof.add("MEET_OTHER", 1);
1592 for(std::set<v3s16>::iterator
1593 i = event->modified_blocks.begin();
1594 i != event->modified_blocks.end(); ++i)
1596 setBlockNotSent(*i);
1601 prof.add("unknown", 1);
1602 infostream<<"WARNING: Server: Unknown MapEditEvent "
1603 <<((u32)event->type)<<std::endl;
1607 Set blocks not sent to far players
1609 if(far_players.size() > 0)
1611 // Convert list format to that wanted by SetBlocksNotSent
1612 std::map<v3s16, MapBlock*> modified_blocks2;
1613 for(std::set<v3s16>::iterator
1614 i = event->modified_blocks.begin();
1615 i != event->modified_blocks.end(); ++i)
1617 modified_blocks2[*i] =
1618 m_env->getMap().getBlockNoCreateNoEx(*i);
1620 // Set blocks not sent
1621 for(std::list<u16>::iterator
1622 i = far_players.begin();
1623 i != far_players.end(); ++i)
1626 RemoteClient *client = getClient(peer_id);
1629 client->SetBlocksNotSent(modified_blocks2);
1635 /*// Don't send too many at a time
1637 if(count >= 1 && m_unsent_map_edit_queue.size() < 100)
1641 if(event_count >= 5){
1642 infostream<<"Server: MapEditEvents:"<<std::endl;
1643 prof.print(infostream);
1644 } else if(event_count != 0){
1645 verbosestream<<"Server: MapEditEvents:"<<std::endl;
1646 prof.print(verbosestream);
1652 Trigger emergethread (it somehow gets to a non-triggered but
1653 bysy state sometimes)
1656 float &counter = m_emergethread_trigger_timer;
1662 for (unsigned int i = 0; i != m_emerge->emergethread.size(); i++)
1663 m_emerge->emergethread[i]->trigger();
1665 // Update m_enable_rollback_recording here too
1666 m_enable_rollback_recording =
1667 g_settings->getBool("enable_rollback_recording");
1671 // Save map, players and auth stuff
1673 float &counter = m_savemap_timer;
1675 if(counter >= g_settings->getFloat("server_map_save_interval"))
1678 JMutexAutoLock lock(m_env_mutex);
1680 ScopeProfiler sp(g_profiler, "Server: saving stuff");
1683 if(m_banmanager.isModified())
1684 m_banmanager.save();
1686 // Save changed parts of map
1687 m_env->getMap().save(MOD_STATE_WRITE_NEEDED);
1690 m_env->serializePlayers(m_path_world);
1692 // Save environment metadata
1693 m_env->saveMeta(m_path_world);
1698 void Server::Receive()
1700 DSTACK(__FUNCTION_NAME);
1701 SharedBuffer<u8> data;
1706 JMutexAutoLock conlock(m_con_mutex);
1707 datasize = m_con.Receive(peer_id, data);
1710 // This has to be called so that the client list gets synced
1711 // with the peer list of the connection
1712 handlePeerChanges();
1714 ProcessData(*data, datasize, peer_id);
1716 catch(con::InvalidIncomingDataException &e)
1718 infostream<<"Server::Receive(): "
1719 "InvalidIncomingDataException: what()="
1720 <<e.what()<<std::endl;
1722 catch(con::PeerNotFoundException &e)
1724 //NOTE: This is not needed anymore
1726 // The peer has been disconnected.
1727 // Find the associated player and remove it.
1729 /*JMutexAutoLock envlock(m_env_mutex);
1731 infostream<<"ServerThread: peer_id="<<peer_id
1732 <<" has apparently closed connection. "
1733 <<"Removing player."<<std::endl;
1735 m_env->removePlayer(peer_id);*/
1739 void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
1741 DSTACK(__FUNCTION_NAME);
1742 // Environment is locked first.
1743 JMutexAutoLock envlock(m_env_mutex);
1744 JMutexAutoLock conlock(m_con_mutex);
1746 ScopeProfiler sp(g_profiler, "Server::ProcessData");
1749 Address address = m_con.GetPeerAddress(peer_id);
1750 std::string addr_s = address.serializeString();
1752 // drop player if is ip is banned
1753 if(m_banmanager.isIpBanned(addr_s)){
1754 infostream<<"Server: A banned client tried to connect from "
1755 <<addr_s<<"; banned name was "
1756 <<m_banmanager.getBanName(addr_s)<<std::endl;
1757 // This actually doesn't seem to transfer to the client
1758 SendAccessDenied(m_con, peer_id,
1759 L"Your ip is banned. Banned name was "
1760 +narrow_to_wide(m_banmanager.getBanName(addr_s)));
1761 m_con.DeletePeer(peer_id);
1765 catch(con::PeerNotFoundException &e)
1767 infostream<<"Server::ProcessData(): Cancelling: peer "
1768 <<peer_id<<" not found"<<std::endl;
1772 std::string addr_s = m_con.GetPeerAddress(peer_id).serializeString();
1774 u8 peer_ser_ver = getClient(peer_id)->serialization_version;
1782 ToServerCommand command = (ToServerCommand)readU16(&data[0]);
1784 if(command == TOSERVER_INIT)
1786 // [0] u16 TOSERVER_INIT
1787 // [2] u8 SER_FMT_VER_HIGHEST
1788 // [3] u8[20] player_name
1789 // [23] u8[28] password <--- can be sent without this, from old versions
1791 if(datasize < 2+1+PLAYERNAME_SIZE)
1794 verbosestream<<"Server: Got TOSERVER_INIT from "
1795 <<peer_id<<std::endl;
1797 // First byte after command is maximum supported
1798 // serialization version
1799 u8 client_max = data[2];
1800 u8 our_max = SER_FMT_VER_HIGHEST;
1801 // Use the highest version supported by both
1802 u8 deployed = std::min(client_max, our_max);
1803 // If it's lower than the lowest supported, give up.
1804 if(deployed < SER_FMT_VER_LOWEST)
1805 deployed = SER_FMT_VER_INVALID;
1807 //peer->serialization_version = deployed;
1808 getClient(peer_id)->pending_serialization_version = deployed;
1810 if(deployed == SER_FMT_VER_INVALID)
1812 actionstream<<"Server: A mismatched client tried to connect from "
1813 <<addr_s<<std::endl;
1814 infostream<<"Server: Cannot negotiate "
1815 "serialization version with peer "
1816 <<peer_id<<std::endl;
1817 SendAccessDenied(m_con, peer_id, std::wstring(
1818 L"Your client's version is not supported.\n"
1819 L"Server version is ")
1820 + narrow_to_wide(VERSION_STRING) + L"."
1826 Read and check network protocol version
1829 u16 min_net_proto_version = 0;
1830 if(datasize >= 2+1+PLAYERNAME_SIZE+PASSWORD_SIZE+2)
1831 min_net_proto_version = readU16(&data[2+1+PLAYERNAME_SIZE+PASSWORD_SIZE]);
1833 // Use same version as minimum and maximum if maximum version field
1834 // doesn't exist (backwards compatibility)
1835 u16 max_net_proto_version = min_net_proto_version;
1836 if(datasize >= 2+1+PLAYERNAME_SIZE+PASSWORD_SIZE+2+2)
1837 max_net_proto_version = readU16(&data[2+1+PLAYERNAME_SIZE+PASSWORD_SIZE+2]);
1839 // Start with client's maximum version
1840 u16 net_proto_version = max_net_proto_version;
1842 // Figure out a working version if it is possible at all
1843 if(max_net_proto_version >= SERVER_PROTOCOL_VERSION_MIN ||
1844 min_net_proto_version <= SERVER_PROTOCOL_VERSION_MAX)
1846 // If maximum is larger than our maximum, go with our maximum
1847 if(max_net_proto_version > SERVER_PROTOCOL_VERSION_MAX)
1848 net_proto_version = SERVER_PROTOCOL_VERSION_MAX;
1849 // Else go with client's maximum
1851 net_proto_version = max_net_proto_version;
1854 verbosestream<<"Server: "<<peer_id<<" Protocol version: min: "
1855 <<min_net_proto_version<<", max: "<<max_net_proto_version
1856 <<", chosen: "<<net_proto_version<<std::endl;
1858 getClient(peer_id)->net_proto_version = net_proto_version;
1860 if(net_proto_version < SERVER_PROTOCOL_VERSION_MIN ||
1861 net_proto_version > SERVER_PROTOCOL_VERSION_MAX)
1863 actionstream<<"Server: A mismatched client tried to connect from "<<addr_s
1865 SendAccessDenied(m_con, peer_id, std::wstring(
1866 L"Your client's version is not supported.\n"
1867 L"Server version is ")
1868 + narrow_to_wide(VERSION_STRING) + L",\n"
1869 + L"server's PROTOCOL_VERSION is "
1870 + narrow_to_wide(itos(SERVER_PROTOCOL_VERSION_MIN))
1872 + narrow_to_wide(itos(SERVER_PROTOCOL_VERSION_MAX))
1873 + L", client's PROTOCOL_VERSION is "
1874 + narrow_to_wide(itos(min_net_proto_version))
1876 + narrow_to_wide(itos(max_net_proto_version))
1881 if(g_settings->getBool("strict_protocol_version_checking"))
1883 if(net_proto_version != LATEST_PROTOCOL_VERSION)
1885 actionstream<<"Server: A mismatched (strict) client tried to "
1886 <<"connect from "<<addr_s<<std::endl;
1887 SendAccessDenied(m_con, peer_id, std::wstring(
1888 L"Your client's version is not supported.\n"
1889 L"Server version is ")
1890 + narrow_to_wide(VERSION_STRING) + L",\n"
1891 + L"server's PROTOCOL_VERSION (strict) is "
1892 + narrow_to_wide(itos(LATEST_PROTOCOL_VERSION))
1893 + L", client's PROTOCOL_VERSION is "
1894 + narrow_to_wide(itos(min_net_proto_version))
1896 + narrow_to_wide(itos(max_net_proto_version))
1907 char playername[PLAYERNAME_SIZE];
1908 for(u32 i=0; i<PLAYERNAME_SIZE-1; i++)
1910 playername[i] = data[3+i];
1912 playername[PLAYERNAME_SIZE-1] = 0;
1914 if(playername[0]=='\0')
1916 actionstream<<"Server: Player with an empty name "
1917 <<"tried to connect from "<<addr_s<<std::endl;
1918 SendAccessDenied(m_con, peer_id,
1923 if(string_allowed(playername, PLAYERNAME_ALLOWED_CHARS)==false)
1925 actionstream<<"Server: Player with an invalid name "
1926 <<"tried to connect from "<<addr_s<<std::endl;
1927 SendAccessDenied(m_con, peer_id,
1928 L"Name contains unallowed characters");
1932 if(!isSingleplayer() && strcasecmp(playername, "singleplayer") == 0)
1934 actionstream<<"Server: Player with an invalid name "
1935 <<"tried to connect from "<<addr_s<<std::endl;
1936 SendAccessDenied(m_con, peer_id,
1937 L"Name is not allowed");
1941 infostream<<"Server: New connection: \""<<playername<<"\" from "
1942 <<m_con.GetPeerAddress(peer_id).serializeString()<<std::endl;
1945 char given_password[PASSWORD_SIZE];
1946 if(datasize < 2+1+PLAYERNAME_SIZE+PASSWORD_SIZE)
1948 // old version - assume blank password
1949 given_password[0] = 0;
1953 for(u32 i=0; i<PASSWORD_SIZE-1; i++)
1955 given_password[i] = data[23+i];
1957 given_password[PASSWORD_SIZE-1] = 0;
1960 if(!base64_is_valid(given_password)){
1961 infostream<<"Server: "<<playername
1962 <<" supplied invalid password hash"<<std::endl;
1963 SendAccessDenied(m_con, peer_id, L"Invalid password hash");
1967 std::string checkpwd; // Password hash to check against
1968 bool has_auth = m_script->getAuth(playername, &checkpwd, NULL);
1970 // If no authentication info exists for user, create it
1972 if(!isSingleplayer() &&
1973 g_settings->getBool("disallow_empty_password") &&
1974 std::string(given_password) == ""){
1975 SendAccessDenied(m_con, peer_id, L"Empty passwords are "
1976 L"disallowed. Set a password and try again.");
1979 std::wstring raw_default_password =
1980 narrow_to_wide(g_settings->get("default_password"));
1981 std::string initial_password =
1982 translatePassword(playername, raw_default_password);
1984 // If default_password is empty, allow any initial password
1985 if (raw_default_password.length() == 0)
1986 initial_password = given_password;
1988 m_script->createAuth(playername, initial_password);
1991 has_auth = m_script->getAuth(playername, &checkpwd, NULL);
1994 SendAccessDenied(m_con, peer_id, L"Not allowed to login");
1998 if(given_password != checkpwd){
1999 infostream<<"Server: peer_id="<<peer_id
2000 <<": supplied invalid password for "
2001 <<playername<<std::endl;
2002 SendAccessDenied(m_con, peer_id, L"Invalid password");
2006 // Do not allow multiple players in simple singleplayer mode.
2007 // This isn't a perfect way to do it, but will suffice for now.
2008 if(m_simple_singleplayer_mode && m_clients.size() > 1){
2009 infostream<<"Server: Not allowing another client to connect in"
2010 <<" simple singleplayer mode"<<std::endl;
2011 SendAccessDenied(m_con, peer_id,
2012 L"Running in simple singleplayer mode.");
2016 // Enforce user limit.
2017 // Don't enforce for users that have some admin right
2018 if(m_clients.size() >= g_settings->getU16("max_users") &&
2019 !checkPriv(playername, "server") &&
2020 !checkPriv(playername, "ban") &&
2021 !checkPriv(playername, "privs") &&
2022 !checkPriv(playername, "password") &&
2023 playername != g_settings->get("name"))
2025 actionstream<<"Server: "<<playername<<" tried to join, but there"
2026 <<" are already max_users="
2027 <<g_settings->getU16("max_users")<<" players."<<std::endl;
2028 SendAccessDenied(m_con, peer_id, L"Too many users.");
2033 PlayerSAO *playersao = emergePlayer(playername, peer_id);
2035 // If failed, cancel
2036 if(playersao == NULL)
2038 errorstream<<"Server: peer_id="<<peer_id
2039 <<": failed to emerge player"<<std::endl;
2044 Answer with a TOCLIENT_INIT
2047 SharedBuffer<u8> reply(2+1+6+8+4);
2048 writeU16(&reply[0], TOCLIENT_INIT);
2049 writeU8(&reply[2], deployed);
2050 writeV3S16(&reply[2+1], floatToInt(playersao->getPlayer()->getPosition()+v3f(0,BS/2,0), BS));
2051 writeU64(&reply[2+1+6], m_env->getServerMap().getSeed());
2052 writeF1000(&reply[2+1+6+8], g_settings->getFloat("dedicated_server_step"));
2055 m_con.Send(peer_id, 0, reply, true);
2059 Send complete position information
2061 SendMovePlayer(peer_id);
2066 if(command == TOSERVER_INIT2)
2068 verbosestream<<"Server: Got TOSERVER_INIT2 from "
2069 <<peer_id<<std::endl;
2071 Player *player = m_env->getPlayer(peer_id);
2073 verbosestream<<"Server: TOSERVER_INIT2: "
2074 <<"Player not found; ignoring."<<std::endl;
2078 RemoteClient *client = getClient(peer_id);
2079 client->serialization_version =
2080 getClient(peer_id)->pending_serialization_version;
2083 Send some initialization data
2086 infostream<<"Server: Sending content to "
2087 <<getPlayerName(peer_id)<<std::endl;
2089 // Send player movement settings
2090 SendMovement(m_con, peer_id);
2092 // Send item definitions
2093 SendItemDef(m_con, peer_id, m_itemdef, client->net_proto_version);
2095 // Send node definitions
2096 SendNodeDef(m_con, peer_id, m_nodedef, client->net_proto_version);
2098 // Send media announcement
2099 sendMediaAnnouncement(peer_id);
2102 SendPlayerPrivileges(peer_id);
2104 // Send inventory formspec
2105 SendPlayerInventoryFormspec(peer_id);
2108 UpdateCrafting(peer_id);
2109 SendInventory(peer_id);
2112 if(g_settings->getBool("enable_damage"))
2113 SendPlayerHP(peer_id);
2116 SendPlayerBreath(peer_id);
2118 // Send detached inventories
2119 sendDetachedInventories(peer_id);
2121 // Show death screen if necessary
2123 SendDeathscreen(m_con, peer_id, false, v3f(0,0,0));
2127 SharedBuffer<u8> data = makePacket_TOCLIENT_TIME_OF_DAY(
2128 m_env->getTimeOfDay(), g_settings->getFloat("time_speed"));
2129 m_con.Send(peer_id, 0, data, true);
2132 // Note things in chat if not in simple singleplayer mode
2133 if(!m_simple_singleplayer_mode)
2135 // Send information about server to player in chat
2136 SendChatMessage(peer_id, getStatusString());
2138 // Send information about joining in chat
2140 std::wstring name = L"unknown";
2141 Player *player = m_env->getPlayer(peer_id);
2143 name = narrow_to_wide(player->getName());
2145 std::wstring message;
2148 message += L" joined the game.";
2149 BroadcastChatMessage(message);
2153 // Warnings about protocol version can be issued here
2154 if(getClient(peer_id)->net_proto_version < LATEST_PROTOCOL_VERSION)
2156 SendChatMessage(peer_id, L"# Server: WARNING: YOUR CLIENT'S "
2157 L"VERSION MAY NOT BE FULLY COMPATIBLE WITH THIS SERVER!");
2164 std::ostringstream os(std::ios_base::binary);
2165 for(std::map<u16, RemoteClient*>::iterator
2166 i = m_clients.begin();
2167 i != m_clients.end(); ++i)
2169 RemoteClient *client = i->second;
2170 assert(client->peer_id == i->first);
2171 if(client->serialization_version == SER_FMT_VER_INVALID)
2174 Player *player = m_env->getPlayer(client->peer_id);
2177 // Get name of player
2178 os<<player->getName()<<" ";
2181 actionstream<<player->getName()<<" ["<<addr_s<<"] "<<" joins game. List of players: "
2182 <<os.str()<<std::endl;
2188 if(peer_ser_ver == SER_FMT_VER_INVALID)
2190 infostream<<"Server::ProcessData(): Cancelling: Peer"
2191 " serialization format invalid or not initialized."
2192 " Skipping incoming command="<<command<<std::endl;
2196 Player *player = m_env->getPlayer(peer_id);
2198 infostream<<"Server::ProcessData(): Cancelling: "
2199 "No player for peer_id="<<peer_id
2204 PlayerSAO *playersao = player->getPlayerSAO();
2205 if(playersao == NULL){
2206 infostream<<"Server::ProcessData(): Cancelling: "
2207 "No player object for peer_id="<<peer_id
2212 if(command == TOSERVER_PLAYERPOS)
2214 if(datasize < 2+12+12+4+4)
2218 v3s32 ps = readV3S32(&data[start+2]);
2219 v3s32 ss = readV3S32(&data[start+2+12]);
2220 f32 pitch = (f32)readS32(&data[2+12+12]) / 100.0;
2221 f32 yaw = (f32)readS32(&data[2+12+12+4]) / 100.0;
2223 if(datasize >= 2+12+12+4+4+4)
2224 keyPressed = (u32)readU32(&data[2+12+12+4+4]);
2225 v3f position((f32)ps.X/100., (f32)ps.Y/100., (f32)ps.Z/100.);
2226 v3f speed((f32)ss.X/100., (f32)ss.Y/100., (f32)ss.Z/100.);
2227 pitch = wrapDegrees(pitch);
2228 yaw = wrapDegrees(yaw);
2230 player->setPosition(position);
2231 player->setSpeed(speed);
2232 player->setPitch(pitch);
2233 player->setYaw(yaw);
2234 player->keyPressed=keyPressed;
2235 player->control.up = (bool)(keyPressed&1);
2236 player->control.down = (bool)(keyPressed&2);
2237 player->control.left = (bool)(keyPressed&4);
2238 player->control.right = (bool)(keyPressed&8);
2239 player->control.jump = (bool)(keyPressed&16);
2240 player->control.aux1 = (bool)(keyPressed&32);
2241 player->control.sneak = (bool)(keyPressed&64);
2242 player->control.LMB = (bool)(keyPressed&128);
2243 player->control.RMB = (bool)(keyPressed&256);
2245 /*infostream<<"Server::ProcessData(): Moved player "<<peer_id<<" to "
2246 <<"("<<position.X<<","<<position.Y<<","<<position.Z<<")"
2247 <<" pitch="<<pitch<<" yaw="<<yaw<<std::endl;*/
2249 else if(command == TOSERVER_GOTBLOCKS)
2262 u16 count = data[2];
2263 for(u16 i=0; i<count; i++)
2265 if((s16)datasize < 2+1+(i+1)*6)
2266 throw con::InvalidIncomingDataException
2267 ("GOTBLOCKS length is too short");
2268 v3s16 p = readV3S16(&data[2+1+i*6]);
2269 /*infostream<<"Server: GOTBLOCKS ("
2270 <<p.X<<","<<p.Y<<","<<p.Z<<")"<<std::endl;*/
2271 RemoteClient *client = getClient(peer_id);
2272 client->GotBlock(p);
2275 else if(command == TOSERVER_DELETEDBLOCKS)
2288 u16 count = data[2];
2289 for(u16 i=0; i<count; i++)
2291 if((s16)datasize < 2+1+(i+1)*6)
2292 throw con::InvalidIncomingDataException
2293 ("DELETEDBLOCKS length is too short");
2294 v3s16 p = readV3S16(&data[2+1+i*6]);
2295 /*infostream<<"Server: DELETEDBLOCKS ("
2296 <<p.X<<","<<p.Y<<","<<p.Z<<")"<<std::endl;*/
2297 RemoteClient *client = getClient(peer_id);
2298 client->SetBlockNotSent(p);
2301 else if(command == TOSERVER_CLICK_OBJECT)
2303 infostream<<"Server: CLICK_OBJECT not supported anymore"<<std::endl;
2306 else if(command == TOSERVER_CLICK_ACTIVEOBJECT)
2308 infostream<<"Server: CLICK_ACTIVEOBJECT not supported anymore"<<std::endl;
2311 else if(command == TOSERVER_GROUND_ACTION)
2313 infostream<<"Server: GROUND_ACTION not supported anymore"<<std::endl;
2317 else if(command == TOSERVER_RELEASE)
2319 infostream<<"Server: RELEASE not supported anymore"<<std::endl;
2322 else if(command == TOSERVER_SIGNTEXT)
2324 infostream<<"Server: SIGNTEXT not supported anymore"
2328 else if(command == TOSERVER_SIGNNODETEXT)
2330 infostream<<"Server: SIGNNODETEXT not supported anymore"
2334 else if(command == TOSERVER_INVENTORY_ACTION)
2336 // Strip command and create a stream
2337 std::string datastring((char*)&data[2], datasize-2);
2338 verbosestream<<"TOSERVER_INVENTORY_ACTION: data="<<datastring<<std::endl;
2339 std::istringstream is(datastring, std::ios_base::binary);
2341 InventoryAction *a = InventoryAction::deSerialize(is);
2344 infostream<<"TOSERVER_INVENTORY_ACTION: "
2345 <<"InventoryAction::deSerialize() returned NULL"
2350 // If something goes wrong, this player is to blame
2351 RollbackScopeActor rollback_scope(m_rollback,
2352 std::string("player:")+player->getName());
2355 Note: Always set inventory not sent, to repair cases
2356 where the client made a bad prediction.
2360 Handle restrictions and special cases of the move action
2362 if(a->getType() == IACTION_MOVE)
2364 IMoveAction *ma = (IMoveAction*)a;
2366 ma->from_inv.applyCurrentPlayer(player->getName());
2367 ma->to_inv.applyCurrentPlayer(player->getName());
2369 setInventoryModified(ma->from_inv);
2370 setInventoryModified(ma->to_inv);
2372 bool from_inv_is_current_player =
2373 (ma->from_inv.type == InventoryLocation::PLAYER) &&
2374 (ma->from_inv.name == player->getName());
2376 bool to_inv_is_current_player =
2377 (ma->to_inv.type == InventoryLocation::PLAYER) &&
2378 (ma->to_inv.name == player->getName());
2381 Disable moving items out of craftpreview
2383 if(ma->from_list == "craftpreview")
2385 infostream<<"Ignoring IMoveAction from "
2386 <<(ma->from_inv.dump())<<":"<<ma->from_list
2387 <<" to "<<(ma->to_inv.dump())<<":"<<ma->to_list
2388 <<" because src is "<<ma->from_list<<std::endl;
2394 Disable moving items into craftresult and craftpreview
2396 if(ma->to_list == "craftpreview" || ma->to_list == "craftresult")
2398 infostream<<"Ignoring IMoveAction from "
2399 <<(ma->from_inv.dump())<<":"<<ma->from_list
2400 <<" to "<<(ma->to_inv.dump())<<":"<<ma->to_list
2401 <<" because dst is "<<ma->to_list<<std::endl;
2406 // Disallow moving items in elsewhere than player's inventory
2407 // if not allowed to interact
2408 if(!checkPriv(player->getName(), "interact") &&
2409 (!from_inv_is_current_player ||
2410 !to_inv_is_current_player))
2412 infostream<<"Cannot move outside of player's inventory: "
2413 <<"No interact privilege"<<std::endl;
2419 Handle restrictions and special cases of the drop action
2421 else if(a->getType() == IACTION_DROP)
2423 IDropAction *da = (IDropAction*)a;
2425 da->from_inv.applyCurrentPlayer(player->getName());
2427 setInventoryModified(da->from_inv);
2430 Disable dropping items out of craftpreview
2432 if(da->from_list == "craftpreview")
2434 infostream<<"Ignoring IDropAction from "
2435 <<(da->from_inv.dump())<<":"<<da->from_list
2436 <<" because src is "<<da->from_list<<std::endl;
2441 // Disallow dropping items if not allowed to interact
2442 if(!checkPriv(player->getName(), "interact"))
2449 Handle restrictions and special cases of the craft action
2451 else if(a->getType() == IACTION_CRAFT)
2453 ICraftAction *ca = (ICraftAction*)a;
2455 ca->craft_inv.applyCurrentPlayer(player->getName());
2457 setInventoryModified(ca->craft_inv);
2459 //bool craft_inv_is_current_player =
2460 // (ca->craft_inv.type == InventoryLocation::PLAYER) &&
2461 // (ca->craft_inv.name == player->getName());
2463 // Disallow crafting if not allowed to interact
2464 if(!checkPriv(player->getName(), "interact"))
2466 infostream<<"Cannot craft: "
2467 <<"No interact privilege"<<std::endl;
2474 a->apply(this, playersao, this);
2478 else if(command == TOSERVER_CHAT_MESSAGE)
2486 std::string datastring((char*)&data[2], datasize-2);
2487 std::istringstream is(datastring, std::ios_base::binary);
2490 is.read((char*)buf, 2);
2491 u16 len = readU16(buf);
2493 std::wstring message;
2494 for(u16 i=0; i<len; i++)
2496 is.read((char*)buf, 2);
2497 message += (wchar_t)readU16(buf);
2500 // If something goes wrong, this player is to blame
2501 RollbackScopeActor rollback_scope(m_rollback,
2502 std::string("player:")+player->getName());
2504 // Get player name of this client
2505 std::wstring name = narrow_to_wide(player->getName());
2508 bool ate = m_script->on_chat_message(player->getName(),
2509 wide_to_narrow(message));
2510 // If script ate the message, don't proceed
2514 // Line to send to players
2516 // Whether to send to the player that sent the line
2517 bool send_to_sender = false;
2518 // Whether to send to other players
2519 bool send_to_others = false;
2521 // Commands are implemented in Lua, so only catch invalid
2522 // commands that were not "eaten" and send an error back
2523 if(message[0] == L'/')
2525 message = message.substr(1);
2526 send_to_sender = true;
2527 if(message.length() == 0)
2528 line += L"-!- Empty command";
2530 line += L"-!- Invalid command: " + str_split(message, L' ')[0];
2534 if(checkPriv(player->getName(), "shout")){
2539 send_to_others = true;
2541 line += L"-!- You don't have permission to shout.";
2542 send_to_sender = true;
2549 actionstream<<"CHAT: "<<wide_to_narrow(line)<<std::endl;
2552 Send the message to clients
2554 for(std::map<u16, RemoteClient*>::iterator
2555 i = m_clients.begin();
2556 i != m_clients.end(); ++i)
2558 // Get client and check that it is valid
2559 RemoteClient *client = i->second;
2560 assert(client->peer_id == i->first);
2561 if(client->serialization_version == SER_FMT_VER_INVALID)
2565 bool sender_selected = (peer_id == client->peer_id);
2566 if(sender_selected == true && send_to_sender == false)
2568 if(sender_selected == false && send_to_others == false)
2571 SendChatMessage(client->peer_id, line);
2575 else if(command == TOSERVER_DAMAGE)
2577 std::string datastring((char*)&data[2], datasize-2);
2578 std::istringstream is(datastring, std::ios_base::binary);
2579 u8 damage = readU8(is);
2581 if(g_settings->getBool("enable_damage"))
2583 actionstream<<player->getName()<<" damaged by "
2584 <<(int)damage<<" hp at "<<PP(player->getPosition()/BS)
2587 playersao->setHP(playersao->getHP() - damage);
2589 if(playersao->getHP() == 0 && playersao->m_hp_not_sent)
2592 if(playersao->m_hp_not_sent)
2593 SendPlayerHP(peer_id);
2596 else if(command == TOSERVER_BREATH)
2598 std::string datastring((char*)&data[2], datasize-2);
2599 std::istringstream is(datastring, std::ios_base::binary);
2600 u16 breath = readU16(is);
2601 playersao->setBreath(breath);
2603 else if(command == TOSERVER_PASSWORD)
2606 [0] u16 TOSERVER_PASSWORD
2607 [2] u8[28] old password
2608 [30] u8[28] new password
2611 if(datasize != 2+PASSWORD_SIZE*2)
2613 /*char password[PASSWORD_SIZE];
2614 for(u32 i=0; i<PASSWORD_SIZE-1; i++)
2615 password[i] = data[2+i];
2616 password[PASSWORD_SIZE-1] = 0;*/
2618 for(u32 i=0; i<PASSWORD_SIZE-1; i++)
2626 for(u32 i=0; i<PASSWORD_SIZE-1; i++)
2628 char c = data[2+PASSWORD_SIZE+i];
2634 if(!base64_is_valid(newpwd)){
2635 infostream<<"Server: "<<player->getName()<<" supplied invalid password hash"<<std::endl;
2636 // Wrong old password supplied!!
2637 SendChatMessage(peer_id, L"Invalid new password hash supplied. Password NOT changed.");
2641 infostream<<"Server: Client requests a password change from "
2642 <<"'"<<oldpwd<<"' to '"<<newpwd<<"'"<<std::endl;
2644 std::string playername = player->getName();
2646 std::string checkpwd;
2647 m_script->getAuth(playername, &checkpwd, NULL);
2649 if(oldpwd != checkpwd)
2651 infostream<<"Server: invalid old password"<<std::endl;
2652 // Wrong old password supplied!!
2653 SendChatMessage(peer_id, L"Invalid old password supplied. Password NOT changed.");
2657 bool success = m_script->setPassword(playername, newpwd);
2659 actionstream<<player->getName()<<" changes password"<<std::endl;
2660 SendChatMessage(peer_id, L"Password change successful.");
2662 actionstream<<player->getName()<<" tries to change password but "
2663 <<"it fails"<<std::endl;
2664 SendChatMessage(peer_id, L"Password change failed or inavailable.");
2667 else if(command == TOSERVER_PLAYERITEM)
2672 u16 item = readU16(&data[2]);
2673 playersao->setWieldIndex(item);
2675 else if(command == TOSERVER_RESPAWN)
2677 if(player->hp != 0 || !g_settings->getBool("enable_damage"))
2680 RespawnPlayer(peer_id);
2682 actionstream<<player->getName()<<" respawns at "
2683 <<PP(player->getPosition()/BS)<<std::endl;
2685 // ActiveObject is added to environment in AsyncRunStep after
2686 // the previous addition has been succesfully removed
2688 else if(command == TOSERVER_REQUEST_MEDIA) {
2689 std::string datastring((char*)&data[2], datasize-2);
2690 std::istringstream is(datastring, std::ios_base::binary);
2692 std::list<MediaRequest> tosend;
2693 u16 numfiles = readU16(is);
2695 infostream<<"Sending "<<numfiles<<" files to "
2696 <<getPlayerName(peer_id)<<std::endl;
2697 verbosestream<<"TOSERVER_REQUEST_MEDIA: "<<std::endl;
2699 for(int i = 0; i < numfiles; i++) {
2700 std::string name = deSerializeString(is);
2701 tosend.push_back(MediaRequest(name));
2702 verbosestream<<"TOSERVER_REQUEST_MEDIA: requested file "
2706 sendRequestedMedia(peer_id, tosend);
2708 // Now the client should know about everything
2709 // (definitions and files)
2710 getClient(peer_id)->definitions_sent = true;
2712 else if(command == TOSERVER_RECEIVED_MEDIA) {
2713 getClient(peer_id)->definitions_sent = true;
2715 else if(command == TOSERVER_INTERACT)
2717 std::string datastring((char*)&data[2], datasize-2);
2718 std::istringstream is(datastring, std::ios_base::binary);
2724 [5] u32 length of the next item
2725 [9] serialized PointedThing
2727 0: start digging (from undersurface) or use
2728 1: stop digging (all parameters ignored)
2729 2: digging completed
2730 3: place block or item (to abovesurface)
2733 u8 action = readU8(is);
2734 u16 item_i = readU16(is);
2735 std::istringstream tmp_is(deSerializeLongString(is), std::ios::binary);
2736 PointedThing pointed;
2737 pointed.deSerialize(tmp_is);
2739 verbosestream<<"TOSERVER_INTERACT: action="<<(int)action<<", item="
2740 <<item_i<<", pointed="<<pointed.dump()<<std::endl;
2744 verbosestream<<"TOSERVER_INTERACT: "<<player->getName()
2745 <<" tried to interact, but is dead!"<<std::endl;
2749 v3f player_pos = playersao->getLastGoodPosition();
2751 // Update wielded item
2752 playersao->setWieldIndex(item_i);
2754 // Get pointed to node (undefined if not POINTEDTYPE_NODE)
2755 v3s16 p_under = pointed.node_undersurface;
2756 v3s16 p_above = pointed.node_abovesurface;
2758 // Get pointed to object (NULL if not POINTEDTYPE_OBJECT)
2759 ServerActiveObject *pointed_object = NULL;
2760 if(pointed.type == POINTEDTHING_OBJECT)
2762 pointed_object = m_env->getActiveObject(pointed.object_id);
2763 if(pointed_object == NULL)
2765 verbosestream<<"TOSERVER_INTERACT: "
2766 "pointed object is NULL"<<std::endl;
2772 v3f pointed_pos_under = player_pos;
2773 v3f pointed_pos_above = player_pos;
2774 if(pointed.type == POINTEDTHING_NODE)
2776 pointed_pos_under = intToFloat(p_under, BS);
2777 pointed_pos_above = intToFloat(p_above, BS);
2779 else if(pointed.type == POINTEDTHING_OBJECT)
2781 pointed_pos_under = pointed_object->getBasePosition();
2782 pointed_pos_above = pointed_pos_under;
2786 Check that target is reasonably close
2787 (only when digging or placing things)
2789 if(action == 0 || action == 2 || action == 3)
2791 float d = player_pos.getDistanceFrom(pointed_pos_under);
2792 float max_d = BS * 14; // Just some large enough value
2794 actionstream<<"Player "<<player->getName()
2795 <<" tried to access "<<pointed.dump()
2797 <<"d="<<d<<", max_d="<<max_d
2798 <<". ignoring."<<std::endl;
2799 // Re-send block to revert change on client-side
2800 RemoteClient *client = getClient(peer_id);
2801 v3s16 blockpos = getNodeBlockPos(floatToInt(pointed_pos_under, BS));
2802 client->SetBlockNotSent(blockpos);
2809 Make sure the player is allowed to do it
2811 if(!checkPriv(player->getName(), "interact"))
2813 actionstream<<player->getName()<<" attempted to interact with "
2814 <<pointed.dump()<<" without 'interact' privilege"
2816 // Re-send block to revert change on client-side
2817 RemoteClient *client = getClient(peer_id);
2818 // Digging completed -> under
2820 v3s16 blockpos = getNodeBlockPos(floatToInt(pointed_pos_under, BS));
2821 client->SetBlockNotSent(blockpos);
2823 // Placement -> above
2825 v3s16 blockpos = getNodeBlockPos(floatToInt(pointed_pos_above, BS));
2826 client->SetBlockNotSent(blockpos);
2832 If something goes wrong, this player is to blame
2834 RollbackScopeActor rollback_scope(m_rollback,
2835 std::string("player:")+player->getName());
2838 0: start digging or punch object
2842 if(pointed.type == POINTEDTHING_NODE)
2845 NOTE: This can be used in the future to check if
2846 somebody is cheating, by checking the timing.
2848 MapNode n(CONTENT_IGNORE);
2851 n = m_env->getMap().getNode(p_under);
2853 catch(InvalidPositionException &e)
2855 infostream<<"Server: Not punching: Node not found."
2856 <<" Adding block to emerge queue."
2858 m_emerge->enqueueBlockEmerge(peer_id, getNodeBlockPos(p_above), false);
2860 if(n.getContent() != CONTENT_IGNORE)
2861 m_script->node_on_punch(p_under, n, playersao);
2863 playersao->noCheatDigStart(p_under);
2865 else if(pointed.type == POINTEDTHING_OBJECT)
2867 // Skip if object has been removed
2868 if(pointed_object->m_removed)
2871 actionstream<<player->getName()<<" punches object "
2872 <<pointed.object_id<<": "
2873 <<pointed_object->getDescription()<<std::endl;
2875 ItemStack punchitem = playersao->getWieldedItem();
2876 ToolCapabilities toolcap =
2877 punchitem.getToolCapabilities(m_itemdef);
2878 v3f dir = (pointed_object->getBasePosition() -
2879 (player->getPosition() + player->getEyeOffset())
2881 float time_from_last_punch =
2882 playersao->resetTimeFromLastPunch();
2883 pointed_object->punch(dir, &toolcap, playersao,
2884 time_from_last_punch);
2892 else if(action == 1)
2897 2: Digging completed
2899 else if(action == 2)
2901 // Only digging of nodes
2902 if(pointed.type == POINTEDTHING_NODE)
2904 MapNode n(CONTENT_IGNORE);
2907 n = m_env->getMap().getNode(p_under);
2909 catch(InvalidPositionException &e)
2911 infostream<<"Server: Not finishing digging: Node not found."
2912 <<" Adding block to emerge queue."
2914 m_emerge->enqueueBlockEmerge(peer_id, getNodeBlockPos(p_above), false);
2917 /* Cheat prevention */
2918 bool is_valid_dig = true;
2919 if(!isSingleplayer() && !g_settings->getBool("disable_anticheat"))
2921 v3s16 nocheat_p = playersao->getNoCheatDigPos();
2922 float nocheat_t = playersao->getNoCheatDigTime();
2923 playersao->noCheatDigEnd();
2924 // If player didn't start digging this, ignore dig
2925 if(nocheat_p != p_under){
2926 infostream<<"Server: NoCheat: "<<player->getName()
2927 <<" started digging "
2928 <<PP(nocheat_p)<<" and completed digging "
2929 <<PP(p_under)<<"; not digging."<<std::endl;
2930 is_valid_dig = false;
2932 // Get player's wielded item
2933 ItemStack playeritem;
2934 InventoryList *mlist = playersao->getInventory()->getList("main");
2936 playeritem = mlist->getItem(playersao->getWieldIndex());
2937 ToolCapabilities playeritem_toolcap =
2938 playeritem.getToolCapabilities(m_itemdef);
2939 // Get diggability and expected digging time
2940 DigParams params = getDigParams(m_nodedef->get(n).groups,
2941 &playeritem_toolcap);
2942 // If can't dig, try hand
2943 if(!params.diggable){
2944 const ItemDefinition &hand = m_itemdef->get("");
2945 const ToolCapabilities *tp = hand.tool_capabilities;
2947 params = getDigParams(m_nodedef->get(n).groups, tp);
2949 // If can't dig, ignore dig
2950 if(!params.diggable){
2951 infostream<<"Server: NoCheat: "<<player->getName()
2952 <<" completed digging "<<PP(p_under)
2953 <<", which is not diggable with tool. not digging."
2955 is_valid_dig = false;
2957 // If time is considerably too short, ignore dig
2958 // Check time only for medium and slow timed digs
2959 if(params.diggable && params.time > 0.3 && nocheat_t < 0.5 * params.time){
2960 infostream<<"Server: NoCheat: "<<player->getName()
2961 <<" completed digging "
2962 <<PP(p_under)<<" in "<<nocheat_t<<"s; expected "
2963 <<params.time<<"s; not digging."<<std::endl;
2964 is_valid_dig = false;
2968 /* Actually dig node */
2970 if(is_valid_dig && n.getContent() != CONTENT_IGNORE)
2971 m_script->node_on_dig(p_under, n, playersao);
2973 // Send unusual result (that is, node not being removed)
2974 if(m_env->getMap().getNodeNoEx(p_under).getContent() != CONTENT_AIR)
2976 // Re-send block to revert change on client-side
2977 RemoteClient *client = getClient(peer_id);
2978 v3s16 blockpos = getNodeBlockPos(floatToInt(pointed_pos_under, BS));
2979 client->SetBlockNotSent(blockpos);
2985 3: place block or right-click object
2987 else if(action == 3)
2989 ItemStack item = playersao->getWieldedItem();
2991 // Reset build time counter
2992 if(pointed.type == POINTEDTHING_NODE &&
2993 item.getDefinition(m_itemdef).type == ITEM_NODE)
2994 getClient(peer_id)->m_time_from_building = 0.0;
2996 if(pointed.type == POINTEDTHING_OBJECT)
2998 // Right click object
3000 // Skip if object has been removed
3001 if(pointed_object->m_removed)
3004 actionstream<<player->getName()<<" right-clicks object "
3005 <<pointed.object_id<<": "
3006 <<pointed_object->getDescription()<<std::endl;
3009 pointed_object->rightClick(playersao);
3011 else if(m_script->item_OnPlace(
3012 item, playersao, pointed))
3014 // Placement was handled in lua
3016 // Apply returned ItemStack
3017 playersao->setWieldedItem(item);
3020 // If item has node placement prediction, always send the
3021 // blocks to make sure the client knows what exactly happened
3022 if(item.getDefinition(m_itemdef).node_placement_prediction != ""){
3023 RemoteClient *client = getClient(peer_id);
3024 v3s16 blockpos = getNodeBlockPos(floatToInt(pointed_pos_above, BS));
3025 client->SetBlockNotSent(blockpos);
3026 v3s16 blockpos2 = getNodeBlockPos(floatToInt(pointed_pos_under, BS));
3027 if(blockpos2 != blockpos){
3028 client->SetBlockNotSent(blockpos2);
3036 else if(action == 4)
3038 ItemStack item = playersao->getWieldedItem();
3040 actionstream<<player->getName()<<" uses "<<item.name
3041 <<", pointing at "<<pointed.dump()<<std::endl;
3043 if(m_script->item_OnUse(
3044 item, playersao, pointed))
3046 // Apply returned ItemStack
3047 playersao->setWieldedItem(item);
3054 Catch invalid actions
3058 infostream<<"WARNING: Server: Invalid action "
3059 <<action<<std::endl;
3062 else if(command == TOSERVER_REMOVED_SOUNDS)
3064 std::string datastring((char*)&data[2], datasize-2);
3065 std::istringstream is(datastring, std::ios_base::binary);
3067 int num = readU16(is);
3068 for(int k=0; k<num; k++){
3069 s32 id = readS32(is);
3070 std::map<s32, ServerPlayingSound>::iterator i =
3071 m_playing_sounds.find(id);
3072 if(i == m_playing_sounds.end())
3074 ServerPlayingSound &psound = i->second;
3075 psound.clients.erase(peer_id);
3076 if(psound.clients.size() == 0)
3077 m_playing_sounds.erase(i++);
3080 else if(command == TOSERVER_NODEMETA_FIELDS)
3082 std::string datastring((char*)&data[2], datasize-2);
3083 std::istringstream is(datastring, std::ios_base::binary);
3085 v3s16 p = readV3S16(is);
3086 std::string formname = deSerializeString(is);
3087 int num = readU16(is);
3088 std::map<std::string, std::string> fields;
3089 for(int k=0; k<num; k++){
3090 std::string fieldname = deSerializeString(is);
3091 std::string fieldvalue = deSerializeLongString(is);
3092 fields[fieldname] = fieldvalue;
3095 // If something goes wrong, this player is to blame
3096 RollbackScopeActor rollback_scope(m_rollback,
3097 std::string("player:")+player->getName());
3099 // Check the target node for rollback data; leave others unnoticed
3100 RollbackNode rn_old(&m_env->getMap(), p, this);
3102 m_script->node_on_receive_fields(p, formname, fields,playersao);
3104 // Report rollback data
3105 RollbackNode rn_new(&m_env->getMap(), p, this);
3106 if(rollback() && rn_new != rn_old){
3107 RollbackAction action;
3108 action.setSetNode(p, rn_old, rn_new);
3109 rollback()->reportAction(action);
3112 else if(command == TOSERVER_INVENTORY_FIELDS)
3114 std::string datastring((char*)&data[2], datasize-2);
3115 std::istringstream is(datastring, std::ios_base::binary);
3117 std::string formname = deSerializeString(is);
3118 int num = readU16(is);
3119 std::map<std::string, std::string> fields;
3120 for(int k=0; k<num; k++){
3121 std::string fieldname = deSerializeString(is);
3122 std::string fieldvalue = deSerializeLongString(is);
3123 fields[fieldname] = fieldvalue;
3126 m_script->on_playerReceiveFields(playersao, formname, fields);
3130 infostream<<"Server::ProcessData(): Ignoring "
3131 "unknown command "<<command<<std::endl;
3135 catch(SendFailedException &e)
3137 errorstream<<"Server::ProcessData(): SendFailedException: "
3143 void Server::onMapEditEvent(MapEditEvent *event)
3145 //infostream<<"Server::onMapEditEvent()"<<std::endl;
3146 if(m_ignore_map_edit_events)
3148 if(m_ignore_map_edit_events_area.contains(event->getArea()))
3150 MapEditEvent *e = event->clone();
3151 m_unsent_map_edit_queue.push_back(e);
3154 Inventory* Server::getInventory(const InventoryLocation &loc)
3157 case InventoryLocation::UNDEFINED:
3160 case InventoryLocation::CURRENT_PLAYER:
3163 case InventoryLocation::PLAYER:
3165 Player *player = m_env->getPlayer(loc.name.c_str());
3168 PlayerSAO *playersao = player->getPlayerSAO();
3171 return playersao->getInventory();
3174 case InventoryLocation::NODEMETA:
3176 NodeMetadata *meta = m_env->getMap().getNodeMetadata(loc.p);
3179 return meta->getInventory();
3182 case InventoryLocation::DETACHED:
3184 if(m_detached_inventories.count(loc.name) == 0)
3186 return m_detached_inventories[loc.name];
3194 void Server::setInventoryModified(const InventoryLocation &loc)
3197 case InventoryLocation::UNDEFINED:
3200 case InventoryLocation::PLAYER:
3202 Player *player = m_env->getPlayer(loc.name.c_str());
3205 PlayerSAO *playersao = player->getPlayerSAO();
3208 playersao->m_inventory_not_sent = true;
3209 playersao->m_wielded_item_not_sent = true;
3212 case InventoryLocation::NODEMETA:
3214 v3s16 blockpos = getNodeBlockPos(loc.p);
3216 MapBlock *block = m_env->getMap().getBlockNoCreateNoEx(blockpos);
3218 block->raiseModified(MOD_STATE_WRITE_NEEDED);
3220 setBlockNotSent(blockpos);
3223 case InventoryLocation::DETACHED:
3225 sendDetachedInventoryToAll(loc.name);
3233 //std::list<PlayerInfo> Server::getPlayerInfo()
3235 // DSTACK(__FUNCTION_NAME);
3236 // JMutexAutoLock envlock(m_env_mutex);
3237 // JMutexAutoLock conlock(m_con_mutex);
3239 // std::list<PlayerInfo> list;
3241 // std::list<Player*> players = m_env->getPlayers();
3243 // std::list<Player*>::iterator i;
3244 // for(i = players.begin();
3245 // i != players.end(); ++i)
3249 // Player *player = *i;
3252 // // Copy info from connection to info struct
3253 // info.id = player->peer_id;
3254 // info.address = m_con.GetPeerAddress(player->peer_id);
3255 // info.avg_rtt = m_con.GetPeerAvgRTT(player->peer_id);
3257 // catch(con::PeerNotFoundException &e)
3259 // // Set dummy peer info
3261 // info.address = Address(0,0,0,0,0);
3262 // info.avg_rtt = 0.0;
3265 // snprintf(info.name, PLAYERNAME_SIZE, "%s", player->getName());
3266 // info.position = player->getPosition();
3268 // list.push_back(info);
3275 void Server::peerAdded(con::Peer *peer)
3277 DSTACK(__FUNCTION_NAME);
3278 verbosestream<<"Server::peerAdded(): peer->id="
3279 <<peer->id<<std::endl;
3282 c.type = PEER_ADDED;
3283 c.peer_id = peer->id;
3285 m_peer_change_queue.push_back(c);
3288 void Server::deletingPeer(con::Peer *peer, bool timeout)
3290 DSTACK(__FUNCTION_NAME);
3291 verbosestream<<"Server::deletingPeer(): peer->id="
3292 <<peer->id<<", timeout="<<timeout<<std::endl;
3295 c.type = PEER_REMOVED;
3296 c.peer_id = peer->id;
3297 c.timeout = timeout;
3298 m_peer_change_queue.push_back(c);
3305 void Server::SendMovement(con::Connection &con, u16 peer_id)
3307 DSTACK(__FUNCTION_NAME);
3308 std::ostringstream os(std::ios_base::binary);
3310 writeU16(os, TOCLIENT_MOVEMENT);
3311 writeF1000(os, g_settings->getFloat("movement_acceleration_default"));
3312 writeF1000(os, g_settings->getFloat("movement_acceleration_air"));
3313 writeF1000(os, g_settings->getFloat("movement_acceleration_fast"));
3314 writeF1000(os, g_settings->getFloat("movement_speed_walk"));
3315 writeF1000(os, g_settings->getFloat("movement_speed_crouch"));
3316 writeF1000(os, g_settings->getFloat("movement_speed_fast"));
3317 writeF1000(os, g_settings->getFloat("movement_speed_climb"));
3318 writeF1000(os, g_settings->getFloat("movement_speed_jump"));
3319 writeF1000(os, g_settings->getFloat("movement_liquid_fluidity"));
3320 writeF1000(os, g_settings->getFloat("movement_liquid_fluidity_smooth"));
3321 writeF1000(os, g_settings->getFloat("movement_liquid_sink"));
3322 writeF1000(os, g_settings->getFloat("movement_gravity"));
3325 std::string s = os.str();
3326 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3328 con.Send(peer_id, 0, data, true);
3331 void Server::SendHP(con::Connection &con, u16 peer_id, u8 hp)
3333 DSTACK(__FUNCTION_NAME);
3334 std::ostringstream os(std::ios_base::binary);
3336 writeU16(os, TOCLIENT_HP);
3340 std::string s = os.str();
3341 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3343 con.Send(peer_id, 0, data, true);
3346 void Server::SendBreath(con::Connection &con, u16 peer_id, u16 breath)
3348 DSTACK(__FUNCTION_NAME);
3349 std::ostringstream os(std::ios_base::binary);
3351 writeU16(os, TOCLIENT_BREATH);
3352 writeU16(os, breath);
3355 std::string s = os.str();
3356 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3358 con.Send(peer_id, 0, data, true);
3361 void Server::SendAccessDenied(con::Connection &con, u16 peer_id,
3362 const std::wstring &reason)
3364 DSTACK(__FUNCTION_NAME);
3365 std::ostringstream os(std::ios_base::binary);
3367 writeU16(os, TOCLIENT_ACCESS_DENIED);
3368 os<<serializeWideString(reason);
3371 std::string s = os.str();
3372 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3374 con.Send(peer_id, 0, data, true);
3377 void Server::SendDeathscreen(con::Connection &con, u16 peer_id,
3378 bool set_camera_point_target, v3f camera_point_target)
3380 DSTACK(__FUNCTION_NAME);
3381 std::ostringstream os(std::ios_base::binary);
3383 writeU16(os, TOCLIENT_DEATHSCREEN);
3384 writeU8(os, set_camera_point_target);
3385 writeV3F1000(os, camera_point_target);
3388 std::string s = os.str();
3389 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3391 con.Send(peer_id, 0, data, true);
3394 void Server::SendItemDef(con::Connection &con, u16 peer_id,
3395 IItemDefManager *itemdef, u16 protocol_version)
3397 DSTACK(__FUNCTION_NAME);
3398 std::ostringstream os(std::ios_base::binary);
3402 u32 length of the next item
3403 zlib-compressed serialized ItemDefManager
3405 writeU16(os, TOCLIENT_ITEMDEF);
3406 std::ostringstream tmp_os(std::ios::binary);
3407 itemdef->serialize(tmp_os, protocol_version);
3408 std::ostringstream tmp_os2(std::ios::binary);
3409 compressZlib(tmp_os.str(), tmp_os2);
3410 os<<serializeLongString(tmp_os2.str());
3413 std::string s = os.str();
3414 verbosestream<<"Server: Sending item definitions to id("<<peer_id
3415 <<"): size="<<s.size()<<std::endl;
3416 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3418 con.Send(peer_id, 0, data, true);
3421 void Server::SendNodeDef(con::Connection &con, u16 peer_id,
3422 INodeDefManager *nodedef, u16 protocol_version)
3424 DSTACK(__FUNCTION_NAME);
3425 std::ostringstream os(std::ios_base::binary);
3429 u32 length of the next item
3430 zlib-compressed serialized NodeDefManager
3432 writeU16(os, TOCLIENT_NODEDEF);
3433 std::ostringstream tmp_os(std::ios::binary);
3434 nodedef->serialize(tmp_os, protocol_version);
3435 std::ostringstream tmp_os2(std::ios::binary);
3436 compressZlib(tmp_os.str(), tmp_os2);
3437 os<<serializeLongString(tmp_os2.str());
3440 std::string s = os.str();
3441 verbosestream<<"Server: Sending node definitions to id("<<peer_id
3442 <<"): size="<<s.size()<<std::endl;
3443 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3445 con.Send(peer_id, 0, data, true);
3449 Non-static send methods
3452 void Server::SendInventory(u16 peer_id)
3454 DSTACK(__FUNCTION_NAME);
3456 PlayerSAO *playersao = getPlayerSAO(peer_id);
3459 playersao->m_inventory_not_sent = false;
3465 std::ostringstream os;
3466 playersao->getInventory()->serialize(os);
3468 std::string s = os.str();
3470 SharedBuffer<u8> data(s.size()+2);
3471 writeU16(&data[0], TOCLIENT_INVENTORY);
3472 memcpy(&data[2], s.c_str(), s.size());
3475 m_con.Send(peer_id, 0, data, true);
3478 void Server::SendChatMessage(u16 peer_id, const std::wstring &message)
3480 DSTACK(__FUNCTION_NAME);
3482 std::ostringstream os(std::ios_base::binary);
3486 writeU16(buf, TOCLIENT_CHAT_MESSAGE);
3487 os.write((char*)buf, 2);
3490 writeU16(buf, message.size());
3491 os.write((char*)buf, 2);
3494 for(u32 i=0; i<message.size(); i++)
3498 os.write((char*)buf, 2);
3502 std::string s = os.str();
3503 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3505 m_con.Send(peer_id, 0, data, true);
3508 void Server::SendShowFormspecMessage(u16 peer_id, const std::string formspec,
3509 const std::string formname)
3511 DSTACK(__FUNCTION_NAME);
3513 std::ostringstream os(std::ios_base::binary);
3517 writeU16(buf, TOCLIENT_SHOW_FORMSPEC);
3518 os.write((char*)buf, 2);
3519 os<<serializeLongString(formspec);
3520 os<<serializeString(formname);
3523 std::string s = os.str();
3524 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3526 m_con.Send(peer_id, 0, data, true);
3529 // Spawns a particle on peer with peer_id
3530 void Server::SendSpawnParticle(u16 peer_id, v3f pos, v3f velocity, v3f acceleration,
3531 float expirationtime, float size, bool collisiondetection,
3532 std::string texture)
3534 DSTACK(__FUNCTION_NAME);
3536 std::ostringstream os(std::ios_base::binary);
3537 writeU16(os, TOCLIENT_SPAWN_PARTICLE);
3538 writeV3F1000(os, pos);
3539 writeV3F1000(os, velocity);
3540 writeV3F1000(os, acceleration);
3541 writeF1000(os, expirationtime);
3542 writeF1000(os, size);
3543 writeU8(os, collisiondetection);
3544 os<<serializeLongString(texture);
3547 std::string s = os.str();
3548 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3550 m_con.Send(peer_id, 0, data, true);
3553 // Spawns a particle on all peers
3554 void Server::SendSpawnParticleAll(v3f pos, v3f velocity, v3f acceleration,
3555 float expirationtime, float size, bool collisiondetection,
3556 std::string texture)
3558 for(std::map<u16, RemoteClient*>::iterator
3559 i = m_clients.begin();
3560 i != m_clients.end(); i++)
3562 // Get client and check that it is valid
3563 RemoteClient *client = i->second;
3564 assert(client->peer_id == i->first);
3565 if(client->serialization_version == SER_FMT_VER_INVALID)
3568 SendSpawnParticle(client->peer_id, pos, velocity, acceleration,
3569 expirationtime, size, collisiondetection, texture);
3573 // Adds a ParticleSpawner on peer with peer_id
3574 void Server::SendAddParticleSpawner(u16 peer_id, u16 amount, float spawntime, v3f minpos, v3f maxpos,
3575 v3f minvel, v3f maxvel, v3f minacc, v3f maxacc, float minexptime, float maxexptime,
3576 float minsize, float maxsize, bool collisiondetection, std::string texture, u32 id)
3578 DSTACK(__FUNCTION_NAME);
3580 std::ostringstream os(std::ios_base::binary);
3581 writeU16(os, TOCLIENT_ADD_PARTICLESPAWNER);
3583 writeU16(os, amount);
3584 writeF1000(os, spawntime);
3585 writeV3F1000(os, minpos);
3586 writeV3F1000(os, maxpos);
3587 writeV3F1000(os, minvel);
3588 writeV3F1000(os, maxvel);
3589 writeV3F1000(os, minacc);
3590 writeV3F1000(os, maxacc);
3591 writeF1000(os, minexptime);
3592 writeF1000(os, maxexptime);
3593 writeF1000(os, minsize);
3594 writeF1000(os, maxsize);
3595 writeU8(os, collisiondetection);
3596 os<<serializeLongString(texture);
3600 std::string s = os.str();
3601 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3603 m_con.Send(peer_id, 0, data, true);
3606 // Adds a ParticleSpawner on all peers
3607 void Server::SendAddParticleSpawnerAll(u16 amount, float spawntime, v3f minpos, v3f maxpos,
3608 v3f minvel, v3f maxvel, v3f minacc, v3f maxacc, float minexptime, float maxexptime,
3609 float minsize, float maxsize, bool collisiondetection, std::string texture, u32 id)
3611 for(std::map<u16, RemoteClient*>::iterator
3612 i = m_clients.begin();
3613 i != m_clients.end(); i++)
3615 // Get client and check that it is valid
3616 RemoteClient *client = i->second;
3617 assert(client->peer_id == i->first);
3618 if(client->serialization_version == SER_FMT_VER_INVALID)
3621 SendAddParticleSpawner(client->peer_id, amount, spawntime,
3622 minpos, maxpos, minvel, maxvel, minacc, maxacc,
3623 minexptime, maxexptime, minsize, maxsize, collisiondetection, texture, id);
3627 void Server::SendDeleteParticleSpawner(u16 peer_id, u32 id)
3629 DSTACK(__FUNCTION_NAME);
3631 std::ostringstream os(std::ios_base::binary);
3632 writeU16(os, TOCLIENT_DELETE_PARTICLESPAWNER);
3637 std::string s = os.str();
3638 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3640 m_con.Send(peer_id, 0, data, true);
3643 void Server::SendDeleteParticleSpawnerAll(u32 id)
3645 for(std::map<u16, RemoteClient*>::iterator
3646 i = m_clients.begin();
3647 i != m_clients.end(); i++)
3649 // Get client and check that it is valid
3650 RemoteClient *client = i->second;
3651 assert(client->peer_id == i->first);
3652 if(client->serialization_version == SER_FMT_VER_INVALID)
3655 SendDeleteParticleSpawner(client->peer_id, id);
3659 void Server::SendHUDAdd(u16 peer_id, u32 id, HudElement *form)
3661 std::ostringstream os(std::ios_base::binary);
3664 writeU16(os, TOCLIENT_HUDADD);
3666 writeU8(os, (u8)form->type);
3667 writeV2F1000(os, form->pos);
3668 os << serializeString(form->name);
3669 writeV2F1000(os, form->scale);
3670 os << serializeString(form->text);
3671 writeU32(os, form->number);
3672 writeU32(os, form->item);
3673 writeU32(os, form->dir);
3674 writeV2F1000(os, form->align);
3675 writeV2F1000(os, form->offset);
3678 std::string s = os.str();
3679 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3681 m_con.Send(peer_id, 0, data, true);
3684 void Server::SendHUDRemove(u16 peer_id, u32 id)
3686 std::ostringstream os(std::ios_base::binary);
3689 writeU16(os, TOCLIENT_HUDRM);
3693 std::string s = os.str();
3694 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3696 m_con.Send(peer_id, 0, data, true);
3699 void Server::SendHUDChange(u16 peer_id, u32 id, HudElementStat stat, void *value)
3701 std::ostringstream os(std::ios_base::binary);
3704 writeU16(os, TOCLIENT_HUDCHANGE);
3706 writeU8(os, (u8)stat);
3709 case HUD_STAT_SCALE:
3710 case HUD_STAT_ALIGN:
3711 case HUD_STAT_OFFSET:
3712 writeV2F1000(os, *(v2f *)value);
3716 os << serializeString(*(std::string *)value);
3718 case HUD_STAT_NUMBER:
3722 writeU32(os, *(u32 *)value);
3727 std::string s = os.str();
3728 SharedBuffer<u8> data((u8 *)s.c_str(), s.size());
3730 m_con.Send(peer_id, 0, data, true);
3733 void Server::SendHUDSetFlags(u16 peer_id, u32 flags, u32 mask)
3735 std::ostringstream os(std::ios_base::binary);
3738 writeU16(os, TOCLIENT_HUD_SET_FLAGS);
3739 writeU32(os, flags);
3743 std::string s = os.str();
3744 SharedBuffer<u8> data((u8 *)s.c_str(), s.size());
3746 m_con.Send(peer_id, 0, data, true);
3749 void Server::SendHUDSetParam(u16 peer_id, u16 param, const std::string &value)
3751 std::ostringstream os(std::ios_base::binary);
3754 writeU16(os, TOCLIENT_HUD_SET_PARAM);
3755 writeU16(os, param);
3756 os<<serializeString(value);
3759 std::string s = os.str();
3760 SharedBuffer<u8> data((u8 *)s.c_str(), s.size());
3762 m_con.Send(peer_id, 0, data, true);
3765 void Server::BroadcastChatMessage(const std::wstring &message)
3767 for(std::map<u16, RemoteClient*>::iterator
3768 i = m_clients.begin();
3769 i != m_clients.end(); ++i)
3771 // Get client and check that it is valid
3772 RemoteClient *client = i->second;
3773 assert(client->peer_id == i->first);
3774 if(client->serialization_version == SER_FMT_VER_INVALID)
3777 SendChatMessage(client->peer_id, message);
3781 void Server::SendPlayerHP(u16 peer_id)
3783 DSTACK(__FUNCTION_NAME);
3784 PlayerSAO *playersao = getPlayerSAO(peer_id);
3786 playersao->m_hp_not_sent = false;
3787 SendHP(m_con, peer_id, playersao->getHP());
3790 void Server::SendPlayerBreath(u16 peer_id)
3792 DSTACK(__FUNCTION_NAME);
3793 PlayerSAO *playersao = getPlayerSAO(peer_id);
3795 playersao->m_breath_not_sent = false;
3796 SendBreath(m_con, peer_id, playersao->getBreath());
3799 void Server::SendMovePlayer(u16 peer_id)
3801 DSTACK(__FUNCTION_NAME);
3802 Player *player = m_env->getPlayer(peer_id);
3805 std::ostringstream os(std::ios_base::binary);
3806 writeU16(os, TOCLIENT_MOVE_PLAYER);
3807 writeV3F1000(os, player->getPosition());
3808 writeF1000(os, player->getPitch());
3809 writeF1000(os, player->getYaw());
3812 v3f pos = player->getPosition();
3813 f32 pitch = player->getPitch();
3814 f32 yaw = player->getYaw();
3815 verbosestream<<"Server: Sending TOCLIENT_MOVE_PLAYER"
3816 <<" pos=("<<pos.X<<","<<pos.Y<<","<<pos.Z<<")"
3823 std::string s = os.str();
3824 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3826 m_con.Send(peer_id, 0, data, true);
3829 void Server::SendPlayerPrivileges(u16 peer_id)
3831 Player *player = m_env->getPlayer(peer_id);
3833 if(player->peer_id == PEER_ID_INEXISTENT)
3836 std::set<std::string> privs;
3837 m_script->getAuth(player->getName(), NULL, &privs);
3839 std::ostringstream os(std::ios_base::binary);
3840 writeU16(os, TOCLIENT_PRIVILEGES);
3841 writeU16(os, privs.size());
3842 for(std::set<std::string>::const_iterator i = privs.begin();
3843 i != privs.end(); i++){
3844 os<<serializeString(*i);
3848 std::string s = os.str();
3849 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3851 m_con.Send(peer_id, 0, data, true);
3854 void Server::SendPlayerInventoryFormspec(u16 peer_id)
3856 Player *player = m_env->getPlayer(peer_id);
3858 if(player->peer_id == PEER_ID_INEXISTENT)
3861 std::ostringstream os(std::ios_base::binary);
3862 writeU16(os, TOCLIENT_INVENTORY_FORMSPEC);
3863 os<<serializeLongString(player->inventory_formspec);
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 s32 Server::playSound(const SimpleSoundSpec &spec,
3873 const ServerSoundParams ¶ms)
3875 // Find out initial position of sound
3876 bool pos_exists = false;
3877 v3f pos = params.getPos(m_env, &pos_exists);
3878 // If position is not found while it should be, cancel sound
3879 if(pos_exists != (params.type != ServerSoundParams::SSP_LOCAL))
3881 // Filter destination clients
3882 std::set<RemoteClient*> dst_clients;
3883 if(params.to_player != "")
3885 Player *player = m_env->getPlayer(params.to_player.c_str());
3887 infostream<<"Server::playSound: Player \""<<params.to_player
3888 <<"\" not found"<<std::endl;
3891 if(player->peer_id == PEER_ID_INEXISTENT){
3892 infostream<<"Server::playSound: Player \""<<params.to_player
3893 <<"\" not connected"<<std::endl;
3896 RemoteClient *client = getClient(player->peer_id);
3897 dst_clients.insert(client);
3901 for(std::map<u16, RemoteClient*>::iterator
3902 i = m_clients.begin(); i != m_clients.end(); ++i)
3904 RemoteClient *client = i->second;
3905 Player *player = m_env->getPlayer(client->peer_id);
3909 if(player->getPosition().getDistanceFrom(pos) >
3910 params.max_hear_distance)
3913 dst_clients.insert(client);
3916 if(dst_clients.size() == 0)
3919 s32 id = m_next_sound_id++;
3920 // The sound will exist as a reference in m_playing_sounds
3921 m_playing_sounds[id] = ServerPlayingSound();
3922 ServerPlayingSound &psound = m_playing_sounds[id];
3923 psound.params = params;
3924 for(std::set<RemoteClient*>::iterator i = dst_clients.begin();
3925 i != dst_clients.end(); i++)
3926 psound.clients.insert((*i)->peer_id);
3928 std::ostringstream os(std::ios_base::binary);
3929 writeU16(os, TOCLIENT_PLAY_SOUND);
3931 os<<serializeString(spec.name);
3932 writeF1000(os, spec.gain * params.gain);
3933 writeU8(os, params.type);
3934 writeV3F1000(os, pos);
3935 writeU16(os, params.object);
3936 writeU8(os, params.loop);
3938 std::string s = os.str();
3939 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3941 for(std::set<RemoteClient*>::iterator i = dst_clients.begin();
3942 i != dst_clients.end(); i++){
3944 m_con.Send((*i)->peer_id, 0, data, true);
3948 void Server::stopSound(s32 handle)
3950 // Get sound reference
3951 std::map<s32, ServerPlayingSound>::iterator i =
3952 m_playing_sounds.find(handle);
3953 if(i == m_playing_sounds.end())
3955 ServerPlayingSound &psound = i->second;
3957 std::ostringstream os(std::ios_base::binary);
3958 writeU16(os, TOCLIENT_STOP_SOUND);
3959 writeS32(os, handle);
3961 std::string s = os.str();
3962 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3964 for(std::set<u16>::iterator i = psound.clients.begin();
3965 i != psound.clients.end(); i++){
3967 m_con.Send(*i, 0, data, true);
3969 // Remove sound reference
3970 m_playing_sounds.erase(i);
3973 void Server::sendRemoveNode(v3s16 p, u16 ignore_id,
3974 std::list<u16> *far_players, float far_d_nodes)
3976 float maxd = far_d_nodes*BS;
3977 v3f p_f = intToFloat(p, BS);
3981 SharedBuffer<u8> reply(replysize);
3982 writeU16(&reply[0], TOCLIENT_REMOVENODE);
3983 writeS16(&reply[2], p.X);
3984 writeS16(&reply[4], p.Y);
3985 writeS16(&reply[6], p.Z);
3987 for(std::map<u16, RemoteClient*>::iterator
3988 i = m_clients.begin();
3989 i != m_clients.end(); ++i)
3991 // Get client and check that it is valid
3992 RemoteClient *client = i->second;
3993 assert(client->peer_id == i->first);
3994 if(client->serialization_version == SER_FMT_VER_INVALID)
3997 // Don't send if it's the same one
3998 if(client->peer_id == ignore_id)
4004 Player *player = m_env->getPlayer(client->peer_id);
4007 // If player is far away, only set modified blocks not sent
4008 v3f player_pos = player->getPosition();
4009 if(player_pos.getDistanceFrom(p_f) > maxd)
4011 far_players->push_back(client->peer_id);
4018 m_con.Send(client->peer_id, 0, reply, true);
4022 void Server::sendAddNode(v3s16 p, MapNode n, u16 ignore_id,
4023 std::list<u16> *far_players, float far_d_nodes)
4025 float maxd = far_d_nodes*BS;
4026 v3f p_f = intToFloat(p, BS);
4028 for(std::map<u16, RemoteClient*>::iterator
4029 i = m_clients.begin();
4030 i != m_clients.end(); ++i)
4032 // Get client and check that it is valid
4033 RemoteClient *client = i->second;
4034 assert(client->peer_id == i->first);
4035 if(client->serialization_version == SER_FMT_VER_INVALID)
4038 // Don't send if it's the same one
4039 if(client->peer_id == ignore_id)
4045 Player *player = m_env->getPlayer(client->peer_id);
4048 // If player is far away, only set modified blocks not sent
4049 v3f player_pos = player->getPosition();
4050 if(player_pos.getDistanceFrom(p_f) > maxd)
4052 far_players->push_back(client->peer_id);
4059 u32 replysize = 8 + MapNode::serializedLength(client->serialization_version);
4060 SharedBuffer<u8> reply(replysize);
4061 writeU16(&reply[0], TOCLIENT_ADDNODE);
4062 writeS16(&reply[2], p.X);
4063 writeS16(&reply[4], p.Y);
4064 writeS16(&reply[6], p.Z);
4065 n.serialize(&reply[8], client->serialization_version);
4068 m_con.Send(client->peer_id, 0, reply, true);
4072 void Server::setBlockNotSent(v3s16 p)
4074 for(std::map<u16, RemoteClient*>::iterator
4075 i = m_clients.begin();
4076 i != m_clients.end(); ++i)
4078 RemoteClient *client = i->second;
4079 client->SetBlockNotSent(p);
4083 void Server::SendBlockNoLock(u16 peer_id, MapBlock *block, u8 ver)
4085 DSTACK(__FUNCTION_NAME);
4087 v3s16 p = block->getPos();
4091 bool completely_air = true;
4092 for(s16 z0=0; z0<MAP_BLOCKSIZE; z0++)
4093 for(s16 x0=0; x0<MAP_BLOCKSIZE; x0++)
4094 for(s16 y0=0; y0<MAP_BLOCKSIZE; y0++)
4096 if(block->getNodeNoEx(v3s16(x0,y0,z0)).d != CONTENT_AIR)
4098 completely_air = false;
4099 x0 = y0 = z0 = MAP_BLOCKSIZE; // Break out
4104 infostream<<"Server: Sending block ("<<p.X<<","<<p.Y<<","<<p.Z<<"): ";
4106 infostream<<"[completely air] ";
4107 infostream<<std::endl;
4111 Create a packet with the block in the right format
4114 std::ostringstream os(std::ios_base::binary);
4115 block->serialize(os, ver, false);
4116 std::string s = os.str();
4117 SharedBuffer<u8> blockdata((u8*)s.c_str(), s.size());
4119 u32 replysize = 8 + blockdata.getSize();
4120 SharedBuffer<u8> reply(replysize);
4121 writeU16(&reply[0], TOCLIENT_BLOCKDATA);
4122 writeS16(&reply[2], p.X);
4123 writeS16(&reply[4], p.Y);
4124 writeS16(&reply[6], p.Z);
4125 memcpy(&reply[8], *blockdata, blockdata.getSize());
4127 /*infostream<<"Server: Sending block ("<<p.X<<","<<p.Y<<","<<p.Z<<")"
4128 <<": \tpacket size: "<<replysize<<std::endl;*/
4133 m_con.Send(peer_id, 1, reply, true);
4136 void Server::SendBlocks(float dtime)
4138 DSTACK(__FUNCTION_NAME);
4140 JMutexAutoLock envlock(m_env_mutex);
4141 JMutexAutoLock conlock(m_con_mutex);
4143 ScopeProfiler sp(g_profiler, "Server: sel and send blocks to clients");
4145 std::vector<PrioritySortedBlockTransfer> queue;
4147 s32 total_sending = 0;
4150 ScopeProfiler sp(g_profiler, "Server: selecting blocks for sending");
4152 for(std::map<u16, RemoteClient*>::iterator
4153 i = m_clients.begin();
4154 i != m_clients.end(); ++i)
4156 RemoteClient *client = i->second;
4157 assert(client->peer_id == i->first);
4159 // If definitions and textures have not been sent, don't
4160 // send MapBlocks either
4161 if(!client->definitions_sent)
4164 total_sending += client->SendingCount();
4166 if(client->serialization_version == SER_FMT_VER_INVALID)
4169 client->GetNextBlocks(this, dtime, queue);
4174 // Lowest priority number comes first.
4175 // Lowest is most important.
4176 std::sort(queue.begin(), queue.end());
4178 for(u32 i=0; i<queue.size(); i++)
4180 //TODO: Calculate limit dynamically
4181 if(total_sending >= g_settings->getS32
4182 ("max_simultaneous_block_sends_server_total"))
4185 PrioritySortedBlockTransfer q = queue[i];
4187 MapBlock *block = NULL;
4190 block = m_env->getMap().getBlockNoCreate(q.pos);
4192 catch(InvalidPositionException &e)
4197 RemoteClient *client = getClient(q.peer_id);
4199 SendBlockNoLock(q.peer_id, block, client->serialization_version);
4201 client->SentBlock(q.pos);
4207 void Server::fillMediaCache()
4209 DSTACK(__FUNCTION_NAME);
4211 infostream<<"Server: Calculating media file checksums"<<std::endl;
4213 // Collect all media file paths
4214 std::list<std::string> paths;
4215 for(std::vector<ModSpec>::iterator i = m_mods.begin();
4216 i != m_mods.end(); i++){
4217 const ModSpec &mod = *i;
4218 paths.push_back(mod.path + DIR_DELIM + "textures");
4219 paths.push_back(mod.path + DIR_DELIM + "sounds");
4220 paths.push_back(mod.path + DIR_DELIM + "media");
4221 paths.push_back(mod.path + DIR_DELIM + "models");
4223 std::string path_all = "textures";
4224 paths.push_back(path_all + DIR_DELIM + "all");
4226 // Collect media file information from paths into cache
4227 for(std::list<std::string>::iterator i = paths.begin();
4228 i != paths.end(); i++)
4230 std::string mediapath = *i;
4231 std::vector<fs::DirListNode> dirlist = fs::GetDirListing(mediapath);
4232 for(u32 j=0; j<dirlist.size(); j++){
4233 if(dirlist[j].dir) // Ignode dirs
4235 std::string filename = dirlist[j].name;
4236 // If name contains illegal characters, ignore the file
4237 if(!string_allowed(filename, TEXTURENAME_ALLOWED_CHARS)){
4238 infostream<<"Server: ignoring illegal file name: \""
4239 <<filename<<"\""<<std::endl;
4242 // If name is not in a supported format, ignore it
4243 const char *supported_ext[] = {
4244 ".png", ".jpg", ".bmp", ".tga",
4245 ".pcx", ".ppm", ".psd", ".wal", ".rgb",
4247 ".x", ".b3d", ".md2", ".obj",
4250 if(removeStringEnd(filename, supported_ext) == ""){
4251 infostream<<"Server: ignoring unsupported file extension: \""
4252 <<filename<<"\""<<std::endl;
4255 // Ok, attempt to load the file and add to cache
4256 std::string filepath = mediapath + DIR_DELIM + filename;
4258 std::ifstream fis(filepath.c_str(), std::ios_base::binary);
4259 if(fis.good() == false){
4260 errorstream<<"Server::fillMediaCache(): Could not open \""
4261 <<filename<<"\" for reading"<<std::endl;
4264 std::ostringstream tmp_os(std::ios_base::binary);
4268 fis.read(buf, 1024);
4269 std::streamsize len = fis.gcount();
4270 tmp_os.write(buf, len);
4279 errorstream<<"Server::fillMediaCache(): Failed to read \""
4280 <<filename<<"\""<<std::endl;
4283 if(tmp_os.str().length() == 0){
4284 errorstream<<"Server::fillMediaCache(): Empty file \""
4285 <<filepath<<"\""<<std::endl;
4290 sha1.addBytes(tmp_os.str().c_str(), tmp_os.str().length());
4292 unsigned char *digest = sha1.getDigest();
4293 std::string sha1_base64 = base64_encode(digest, 20);
4294 std::string sha1_hex = hex_encode((char*)digest, 20);
4298 this->m_media[filename] = MediaInfo(filepath, sha1_base64);
4299 verbosestream<<"Server: "<<sha1_hex<<" is "<<filename<<std::endl;
4304 struct SendableMediaAnnouncement
4307 std::string sha1_digest;
4309 SendableMediaAnnouncement(const std::string name_="",
4310 const std::string sha1_digest_=""):
4312 sha1_digest(sha1_digest_)
4316 void Server::sendMediaAnnouncement(u16 peer_id)
4318 DSTACK(__FUNCTION_NAME);
4320 verbosestream<<"Server: Announcing files to id("<<peer_id<<")"
4323 std::list<SendableMediaAnnouncement> file_announcements;
4325 for(std::map<std::string, MediaInfo>::iterator i = m_media.begin();
4326 i != m_media.end(); i++){
4328 file_announcements.push_back(
4329 SendableMediaAnnouncement(i->first, i->second.sha1_digest));
4333 std::ostringstream os(std::ios_base::binary);
4341 u16 length of sha1_digest
4346 writeU16(os, TOCLIENT_ANNOUNCE_MEDIA);
4347 writeU16(os, file_announcements.size());
4349 for(std::list<SendableMediaAnnouncement>::iterator
4350 j = file_announcements.begin();
4351 j != file_announcements.end(); ++j){
4352 os<<serializeString(j->name);
4353 os<<serializeString(j->sha1_digest);
4355 os<<serializeString(g_settings->get("remote_media"));
4358 std::string s = os.str();
4359 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
4362 m_con.Send(peer_id, 0, data, true);
4365 struct SendableMedia
4371 SendableMedia(const std::string &name_="", const std::string path_="",
4372 const std::string &data_=""):
4379 void Server::sendRequestedMedia(u16 peer_id,
4380 const std::list<MediaRequest> &tosend)
4382 DSTACK(__FUNCTION_NAME);
4384 verbosestream<<"Server::sendRequestedMedia(): "
4385 <<"Sending files to client"<<std::endl;
4389 // Put 5kB in one bunch (this is not accurate)
4390 u32 bytes_per_bunch = 5000;
4392 std::vector< std::list<SendableMedia> > file_bunches;
4393 file_bunches.push_back(std::list<SendableMedia>());
4395 u32 file_size_bunch_total = 0;
4397 for(std::list<MediaRequest>::const_iterator i = tosend.begin();
4398 i != tosend.end(); ++i)
4400 if(m_media.find(i->name) == m_media.end()){
4401 errorstream<<"Server::sendRequestedMedia(): Client asked for "
4402 <<"unknown file \""<<(i->name)<<"\""<<std::endl;
4406 //TODO get path + name
4407 std::string tpath = m_media[(*i).name].path;
4410 std::ifstream fis(tpath.c_str(), std::ios_base::binary);
4411 if(fis.good() == false){
4412 errorstream<<"Server::sendRequestedMedia(): Could not open \""
4413 <<tpath<<"\" for reading"<<std::endl;
4416 std::ostringstream tmp_os(std::ios_base::binary);
4420 fis.read(buf, 1024);
4421 std::streamsize len = fis.gcount();
4422 tmp_os.write(buf, len);
4423 file_size_bunch_total += len;
4432 errorstream<<"Server::sendRequestedMedia(): Failed to read \""
4433 <<(*i).name<<"\""<<std::endl;
4436 /*infostream<<"Server::sendRequestedMedia(): Loaded \""
4437 <<tname<<"\""<<std::endl;*/
4439 file_bunches[file_bunches.size()-1].push_back(
4440 SendableMedia((*i).name, tpath, tmp_os.str()));
4442 // Start next bunch if got enough data
4443 if(file_size_bunch_total >= bytes_per_bunch){
4444 file_bunches.push_back(std::list<SendableMedia>());
4445 file_size_bunch_total = 0;
4450 /* Create and send packets */
4452 u32 num_bunches = file_bunches.size();
4453 for(u32 i=0; i<num_bunches; i++)
4455 std::ostringstream os(std::ios_base::binary);
4459 u16 total number of texture bunches
4460 u16 index of this bunch
4461 u32 number of files in this bunch
4470 writeU16(os, TOCLIENT_MEDIA);
4471 writeU16(os, num_bunches);
4473 writeU32(os, file_bunches[i].size());
4475 for(std::list<SendableMedia>::iterator
4476 j = file_bunches[i].begin();
4477 j != file_bunches[i].end(); ++j){
4478 os<<serializeString(j->name);
4479 os<<serializeLongString(j->data);
4483 std::string s = os.str();
4484 verbosestream<<"Server::sendRequestedMedia(): bunch "
4485 <<i<<"/"<<num_bunches
4486 <<" files="<<file_bunches[i].size()
4487 <<" size=" <<s.size()<<std::endl;
4488 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
4490 m_con.Send(peer_id, 0, data, true);
4494 void Server::sendDetachedInventory(const std::string &name, u16 peer_id)
4496 if(m_detached_inventories.count(name) == 0){
4497 errorstream<<__FUNCTION_NAME<<": \""<<name<<"\" not found"<<std::endl;
4500 Inventory *inv = m_detached_inventories[name];
4502 std::ostringstream os(std::ios_base::binary);
4503 writeU16(os, TOCLIENT_DETACHED_INVENTORY);
4504 os<<serializeString(name);
4508 std::string s = os.str();
4509 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
4511 m_con.Send(peer_id, 0, data, true);
4514 void Server::sendDetachedInventoryToAll(const std::string &name)
4516 DSTACK(__FUNCTION_NAME);
4518 for(std::map<u16, RemoteClient*>::iterator
4519 i = m_clients.begin();
4520 i != m_clients.end(); ++i){
4521 RemoteClient *client = i->second;
4522 sendDetachedInventory(name, client->peer_id);
4526 void Server::sendDetachedInventories(u16 peer_id)
4528 DSTACK(__FUNCTION_NAME);
4530 for(std::map<std::string, Inventory*>::iterator
4531 i = m_detached_inventories.begin();
4532 i != m_detached_inventories.end(); i++){
4533 const std::string &name = i->first;
4534 //Inventory *inv = i->second;
4535 sendDetachedInventory(name, peer_id);
4543 void Server::DiePlayer(u16 peer_id)
4545 DSTACK(__FUNCTION_NAME);
4547 PlayerSAO *playersao = getPlayerSAO(peer_id);
4550 infostream<<"Server::DiePlayer(): Player "
4551 <<playersao->getPlayer()->getName()
4552 <<" dies"<<std::endl;
4554 playersao->setHP(0);
4556 // Trigger scripted stuff
4557 m_script->on_dieplayer(playersao);
4559 SendPlayerHP(peer_id);
4560 SendDeathscreen(m_con, peer_id, false, v3f(0,0,0));
4563 void Server::RespawnPlayer(u16 peer_id)
4565 DSTACK(__FUNCTION_NAME);
4567 PlayerSAO *playersao = getPlayerSAO(peer_id);
4570 infostream<<"Server::RespawnPlayer(): Player "
4571 <<playersao->getPlayer()->getName()
4572 <<" respawns"<<std::endl;
4574 playersao->setHP(PLAYER_MAX_HP);
4576 bool repositioned = m_script->on_respawnplayer(playersao);
4578 v3f pos = findSpawnPos(m_env->getServerMap());
4579 playersao->setPos(pos);
4583 void Server::UpdateCrafting(u16 peer_id)
4585 DSTACK(__FUNCTION_NAME);
4587 Player* player = m_env->getPlayer(peer_id);
4590 // Get a preview for crafting
4592 getCraftingResult(&player->inventory, preview, false, this);
4594 // Put the new preview in
4595 InventoryList *plist = player->inventory.getList("craftpreview");
4597 assert(plist->getSize() >= 1);
4598 plist->changeItem(0, preview);
4601 RemoteClient* Server::getClient(u16 peer_id)
4603 DSTACK(__FUNCTION_NAME);
4604 //JMutexAutoLock lock(m_con_mutex);
4605 std::map<u16, RemoteClient*>::iterator n;
4606 n = m_clients.find(peer_id);
4607 // A client should exist for all peers
4608 assert(n != m_clients.end());
4612 std::wstring Server::getStatusString()
4614 std::wostringstream os(std::ios_base::binary);
4617 os<<L"version="<<narrow_to_wide(VERSION_STRING);
4619 os<<L", uptime="<<m_uptime.get();
4620 // Information about clients
4621 std::map<u16, RemoteClient*>::iterator i;
4624 for(i = m_clients.begin(), first = true;
4625 i != m_clients.end(); ++i)
4627 // Get client and check that it is valid
4628 RemoteClient *client = i->second;
4629 assert(client->peer_id == i->first);
4630 if(client->serialization_version == SER_FMT_VER_INVALID)
4633 Player *player = m_env->getPlayer(client->peer_id);
4634 // Get name of player
4635 std::wstring name = L"unknown";
4637 name = narrow_to_wide(player->getName());
4638 // Add name to information string
4646 if(((ServerMap*)(&m_env->getMap()))->isSavingEnabled() == false)
4647 os<<std::endl<<L"# Server: "<<" WARNING: Map saving is disabled.";
4648 if(g_settings->get("motd") != "")
4649 os<<std::endl<<L"# Server: "<<narrow_to_wide(g_settings->get("motd"));
4653 std::set<std::string> Server::getPlayerEffectivePrivs(const std::string &name)
4655 std::set<std::string> privs;
4656 m_script->getAuth(name, NULL, &privs);
4660 bool Server::checkPriv(const std::string &name, const std::string &priv)
4662 std::set<std::string> privs = getPlayerEffectivePrivs(name);
4663 return (privs.count(priv) != 0);
4666 void Server::reportPrivsModified(const std::string &name)
4669 for(std::map<u16, RemoteClient*>::iterator
4670 i = m_clients.begin();
4671 i != m_clients.end(); ++i){
4672 RemoteClient *client = i->second;
4673 Player *player = m_env->getPlayer(client->peer_id);
4674 reportPrivsModified(player->getName());
4677 Player *player = m_env->getPlayer(name.c_str());
4680 SendPlayerPrivileges(player->peer_id);
4681 PlayerSAO *sao = player->getPlayerSAO();
4684 sao->updatePrivileges(
4685 getPlayerEffectivePrivs(name),
4690 void Server::reportInventoryFormspecModified(const std::string &name)
4692 Player *player = m_env->getPlayer(name.c_str());
4695 SendPlayerInventoryFormspec(player->peer_id);
4698 // Saves g_settings to configpath given at initialization
4699 void Server::saveConfig()
4701 if(m_path_config != "")
4702 g_settings->updateConfigFile(m_path_config.c_str());
4705 void Server::notifyPlayer(const char *name, const std::wstring msg, const bool prepend = true)
4707 Player *player = m_env->getPlayer(name);
4711 SendChatMessage(player->peer_id, std::wstring(L"Server -!- ")+msg);
4713 SendChatMessage(player->peer_id, msg);
4716 bool Server::showFormspec(const char *playername, const std::string &formspec, const std::string &formname)
4718 Player *player = m_env->getPlayer(playername);
4722 infostream<<"showFormspec: couldn't find player:"<<playername<<std::endl;
4726 SendShowFormspecMessage(player->peer_id, formspec, formname);
4730 u32 Server::hudAdd(Player *player, HudElement *form) {
4734 u32 id = hud_get_free_id(player);
4735 if (id < player->hud.size())
4736 player->hud[id] = form;
4738 player->hud.push_back(form);
4740 SendHUDAdd(player->peer_id, id, form);
4744 bool Server::hudRemove(Player *player, u32 id) {
4745 if (!player || id >= player->hud.size() || !player->hud[id])
4748 delete player->hud[id];
4749 player->hud[id] = NULL;
4751 SendHUDRemove(player->peer_id, id);
4755 bool Server::hudChange(Player *player, u32 id, HudElementStat stat, void *data) {
4759 SendHUDChange(player->peer_id, id, stat, data);
4763 bool Server::hudSetFlags(Player *player, u32 flags, u32 mask) {
4767 SendHUDSetFlags(player->peer_id, flags, mask);
4771 bool Server::hudSetHotbarItemcount(Player *player, s32 hotbar_itemcount) {
4774 if (hotbar_itemcount <= 0 || hotbar_itemcount > HUD_HOTBAR_ITEMCOUNT_MAX)
4777 std::ostringstream os(std::ios::binary);
4778 writeS32(os, hotbar_itemcount);
4779 SendHUDSetParam(player->peer_id, HUD_PARAM_HOTBAR_ITEMCOUNT, os.str());
4783 void Server::notifyPlayers(const std::wstring msg)
4785 BroadcastChatMessage(msg);
4788 void Server::spawnParticle(const char *playername, v3f pos,
4789 v3f velocity, v3f acceleration,
4790 float expirationtime, float size, bool
4791 collisiondetection, std::string texture)
4793 Player *player = m_env->getPlayer(playername);
4796 SendSpawnParticle(player->peer_id, pos, velocity, acceleration,
4797 expirationtime, size, collisiondetection, texture);
4800 void Server::spawnParticleAll(v3f pos, v3f velocity, v3f acceleration,
4801 float expirationtime, float size,
4802 bool collisiondetection, std::string texture)
4804 SendSpawnParticleAll(pos, velocity, acceleration,
4805 expirationtime, size, collisiondetection, texture);
4808 u32 Server::addParticleSpawner(const char *playername,
4809 u16 amount, float spawntime,
4810 v3f minpos, v3f maxpos,
4811 v3f minvel, v3f maxvel,
4812 v3f minacc, v3f maxacc,
4813 float minexptime, float maxexptime,
4814 float minsize, float maxsize,
4815 bool collisiondetection, std::string texture)
4817 Player *player = m_env->getPlayer(playername);
4822 for(;;) // look for unused particlespawner id
4825 if (std::find(m_particlespawner_ids.begin(),
4826 m_particlespawner_ids.end(), id)
4827 == m_particlespawner_ids.end())
4829 m_particlespawner_ids.push_back(id);
4834 SendAddParticleSpawner(player->peer_id, amount, spawntime,
4835 minpos, maxpos, minvel, maxvel, minacc, maxacc,
4836 minexptime, maxexptime, minsize, maxsize,
4837 collisiondetection, texture, id);
4842 u32 Server::addParticleSpawnerAll(u16 amount, float spawntime,
4843 v3f minpos, v3f maxpos,
4844 v3f minvel, v3f maxvel,
4845 v3f minacc, v3f maxacc,
4846 float minexptime, float maxexptime,
4847 float minsize, float maxsize,
4848 bool collisiondetection, std::string texture)
4851 for(;;) // look for unused particlespawner id
4854 if (std::find(m_particlespawner_ids.begin(),
4855 m_particlespawner_ids.end(), id)
4856 == m_particlespawner_ids.end())
4858 m_particlespawner_ids.push_back(id);
4863 SendAddParticleSpawnerAll(amount, spawntime,
4864 minpos, maxpos, minvel, maxvel, minacc, maxacc,
4865 minexptime, maxexptime, minsize, maxsize,
4866 collisiondetection, texture, id);
4871 void Server::deleteParticleSpawner(const char *playername, u32 id)
4873 Player *player = m_env->getPlayer(playername);
4877 m_particlespawner_ids.erase(
4878 std::remove(m_particlespawner_ids.begin(),
4879 m_particlespawner_ids.end(), id),
4880 m_particlespawner_ids.end());
4881 SendDeleteParticleSpawner(player->peer_id, id);
4884 void Server::deleteParticleSpawnerAll(u32 id)
4886 m_particlespawner_ids.erase(
4887 std::remove(m_particlespawner_ids.begin(),
4888 m_particlespawner_ids.end(), id),
4889 m_particlespawner_ids.end());
4890 SendDeleteParticleSpawnerAll(id);
4893 void Server::queueBlockEmerge(v3s16 blockpos, bool allow_generate)
4895 m_emerge->enqueueBlockEmerge(PEER_ID_INEXISTENT, blockpos, allow_generate);
4898 Inventory* Server::createDetachedInventory(const std::string &name)
4900 if(m_detached_inventories.count(name) > 0){
4901 infostream<<"Server clearing detached inventory \""<<name<<"\""<<std::endl;
4902 delete m_detached_inventories[name];
4904 infostream<<"Server creating detached inventory \""<<name<<"\""<<std::endl;
4906 Inventory *inv = new Inventory(m_itemdef);
4908 m_detached_inventories[name] = inv;
4909 sendDetachedInventoryToAll(name);
4916 BoolScopeSet(bool *dst, bool val):
4919 m_orig_state = *m_dst;
4924 *m_dst = m_orig_state;
4931 // actions: time-reversed list
4932 // Return value: success/failure
4933 bool Server::rollbackRevertActions(const std::list<RollbackAction> &actions,
4934 std::list<std::string> *log)
4936 infostream<<"Server::rollbackRevertActions(len="<<actions.size()<<")"<<std::endl;
4937 ServerMap *map = (ServerMap*)(&m_env->getMap());
4938 // Disable rollback report sink while reverting
4939 BoolScopeSet rollback_scope_disable(&m_rollback_sink_enabled, false);
4941 // Fail if no actions to handle
4942 if(actions.empty()){
4943 log->push_back("Nothing to do.");
4950 for(std::list<RollbackAction>::const_iterator
4951 i = actions.begin();
4952 i != actions.end(); i++)
4954 const RollbackAction &action = *i;
4956 bool success = action.applyRevert(map, this, this);
4959 std::ostringstream os;
4960 os<<"Revert of step ("<<num_tried<<") "<<action.toString()<<" failed";
4961 infostream<<"Map::rollbackRevertActions(): "<<os.str()<<std::endl;
4963 log->push_back(os.str());
4965 std::ostringstream os;
4966 os<<"Successfully reverted step ("<<num_tried<<") "<<action.toString();
4967 infostream<<"Map::rollbackRevertActions(): "<<os.str()<<std::endl;
4969 log->push_back(os.str());
4973 infostream<<"Map::rollbackRevertActions(): "<<num_failed<<"/"<<num_tried
4974 <<" failed"<<std::endl;
4976 // Call it done if less than half failed
4977 return num_failed <= num_tried/2;
4980 // IGameDef interface
4982 IItemDefManager* Server::getItemDefManager()
4986 INodeDefManager* Server::getNodeDefManager()
4990 ICraftDefManager* Server::getCraftDefManager()
4994 ITextureSource* Server::getTextureSource()
4998 IShaderSource* Server::getShaderSource()
5002 u16 Server::allocateUnknownNodeId(const std::string &name)
5004 return m_nodedef->allocateDummy(name);
5006 ISoundManager* Server::getSoundManager()
5008 return &dummySoundManager;
5010 MtEventManager* Server::getEventManager()
5014 IRollbackReportSink* Server::getRollbackReportSink()
5016 if(!m_enable_rollback_recording)
5018 if(!m_rollback_sink_enabled)
5023 IWritableItemDefManager* Server::getWritableItemDefManager()
5027 IWritableNodeDefManager* Server::getWritableNodeDefManager()
5031 IWritableCraftDefManager* Server::getWritableCraftDefManager()
5036 const ModSpec* Server::getModSpec(const std::string &modname)
5038 for(std::vector<ModSpec>::iterator i = m_mods.begin();
5039 i != m_mods.end(); i++){
5040 const ModSpec &mod = *i;
5041 if(mod.name == modname)
5046 void Server::getModNames(std::list<std::string> &modlist)
5048 for(std::vector<ModSpec>::iterator i = m_mods.begin(); i != m_mods.end(); i++)
5050 modlist.push_back(i->name);
5053 std::string Server::getBuiltinLuaPath()
5055 return porting::path_share + DIR_DELIM + "builtin";
5058 v3f findSpawnPos(ServerMap &map)
5060 //return v3f(50,50,50)*BS;
5065 nodepos = v2s16(0,0);
5070 s16 water_level = map.m_mgparams->water_level;
5072 // Try to find a good place a few times
5073 for(s32 i=0; i<1000; i++)
5076 // We're going to try to throw the player to this position
5077 v2s16 nodepos2d = v2s16(
5078 -range + (myrand() % (range * 2)),
5079 -range + (myrand() % (range * 2)));
5081 // Get ground height at point
5082 s16 groundheight = map.findGroundLevel(nodepos2d);
5083 if (groundheight <= water_level) // Don't go underwater
5085 if (groundheight > water_level + 6) // Don't go to high places
5088 nodepos = v3s16(nodepos2d.X, groundheight, nodepos2d.Y);
5089 bool is_good = false;
5091 for (s32 i = 0; i < 10; i++) {
5092 v3s16 blockpos = getNodeBlockPos(nodepos);
5093 map.emergeBlock(blockpos, true);
5094 content_t c = map.getNodeNoEx(nodepos).getContent();
5095 if (c == CONTENT_AIR || c == CONTENT_IGNORE) {
5097 if (air_count >= 2){
5105 // Found a good place
5106 //infostream<<"Searched through "<<i<<" places."<<std::endl;
5112 return intToFloat(nodepos, BS);
5115 PlayerSAO* Server::emergePlayer(const char *name, u16 peer_id)
5117 RemotePlayer *player = NULL;
5118 bool newplayer = false;
5121 Try to get an existing player
5123 player = static_cast<RemotePlayer*>(m_env->getPlayer(name));
5125 // If player is already connected, cancel
5126 if(player != NULL && player->peer_id != 0)
5128 infostream<<"emergePlayer(): Player already connected"<<std::endl;
5133 If player with the wanted peer_id already exists, cancel.
5135 if(m_env->getPlayer(peer_id) != NULL)
5137 infostream<<"emergePlayer(): Player with wrong name but same"
5138 " peer_id already exists"<<std::endl;
5143 Create a new player if it doesn't exist yet
5148 player = new RemotePlayer(this);
5149 player->updateName(name);
5151 /* Set player position */
5152 infostream<<"Server: Finding spawn place for player \""
5153 <<name<<"\""<<std::endl;
5154 v3f pos = findSpawnPos(m_env->getServerMap());
5155 player->setPosition(pos);
5157 /* Add player to environment */
5158 m_env->addPlayer(player);
5162 Create a new player active object
5164 PlayerSAO *playersao = new PlayerSAO(m_env, player, peer_id,
5165 getPlayerEffectivePrivs(player->getName()),
5168 /* Clean up old HUD elements from previous sessions */
5169 player->hud.clear();
5171 /* Add object to environment */
5172 m_env->addActiveObject(playersao);
5176 m_script->on_newplayer(playersao);
5178 m_script->on_joinplayer(playersao);
5183 void Server::handlePeerChange(PeerChange &c)
5185 JMutexAutoLock envlock(m_env_mutex);
5186 JMutexAutoLock conlock(m_con_mutex);
5188 if(c.type == PEER_ADDED)
5195 std::map<u16, RemoteClient*>::iterator n;
5196 n = m_clients.find(c.peer_id);
5197 // The client shouldn't already exist
5198 assert(n == m_clients.end());
5201 RemoteClient *client = new RemoteClient();
5202 client->peer_id = c.peer_id;
5203 m_clients[client->peer_id] = client;
5206 else if(c.type == PEER_REMOVED)
5213 std::map<u16, RemoteClient*>::iterator n;
5214 n = m_clients.find(c.peer_id);
5215 // The client should exist
5216 assert(n != m_clients.end());
5219 Mark objects to be not known by the client
5221 RemoteClient *client = n->second;
5223 for(std::set<u16>::iterator
5224 i = client->m_known_objects.begin();
5225 i != client->m_known_objects.end(); ++i)
5229 ServerActiveObject* obj = m_env->getActiveObject(id);
5231 if(obj && obj->m_known_by_count > 0)
5232 obj->m_known_by_count--;
5236 Clear references to playing sounds
5238 for(std::map<s32, ServerPlayingSound>::iterator
5239 i = m_playing_sounds.begin();
5240 i != m_playing_sounds.end();)
5242 ServerPlayingSound &psound = i->second;
5243 psound.clients.erase(c.peer_id);
5244 if(psound.clients.size() == 0)
5245 m_playing_sounds.erase(i++);
5250 Player *player = m_env->getPlayer(c.peer_id);
5252 // Collect information about leaving in chat
5253 std::wstring message;
5257 std::wstring name = narrow_to_wide(player->getName());
5260 message += L" left the game.";
5262 message += L" (timed out)";
5266 /* Run scripts and remove from environment */
5270 PlayerSAO *playersao = player->getPlayerSAO();
5273 m_script->on_leaveplayer(playersao);
5275 playersao->disconnected();
5285 std::ostringstream os(std::ios_base::binary);
5286 for(std::map<u16, RemoteClient*>::iterator
5287 i = m_clients.begin();
5288 i != m_clients.end(); ++i)
5290 RemoteClient *client = i->second;
5291 assert(client->peer_id == i->first);
5292 if(client->serialization_version == SER_FMT_VER_INVALID)
5295 Player *player = m_env->getPlayer(client->peer_id);
5298 // Get name of player
5299 os<<player->getName()<<" ";
5302 actionstream<<player->getName()<<" "
5303 <<(c.timeout?"times out.":"leaves game.")
5304 <<" List of players: "
5305 <<os.str()<<std::endl;
5310 delete m_clients[c.peer_id];
5311 m_clients.erase(c.peer_id);
5313 // Send player info to all remaining clients
5314 //SendPlayerInfos();
5316 // Send leave chat message to all remaining clients
5317 if(message.length() != 0)
5318 BroadcastChatMessage(message);
5327 void Server::handlePeerChanges()
5329 while(m_peer_change_queue.size() > 0)
5331 PeerChange c = m_peer_change_queue.pop_front();
5333 verbosestream<<"Server: Handling peer change: "
5334 <<"id="<<c.peer_id<<", timeout="<<c.timeout
5337 handlePeerChange(c);
5341 void dedicated_server_loop(Server &server, bool &kill)
5343 DSTACK(__FUNCTION_NAME);
5345 verbosestream<<"dedicated_server_loop()"<<std::endl;
5347 IntervalLimiter m_profiler_interval;
5351 float steplen = g_settings->getFloat("dedicated_server_step");
5352 // This is kind of a hack but can be done like this
5353 // because server.step() is very light
5355 ScopeProfiler sp(g_profiler, "dedicated server sleep");
5356 sleep_ms((int)(steplen*1000.0));
5358 server.step(steplen);
5360 if(server.getShutdownRequested() || kill)
5362 infostream<<"Dedicated server quitting"<<std::endl;
5364 if(g_settings->getBool("server_announce") == true)
5365 ServerList::sendAnnounce("delete");
5373 float profiler_print_interval =
5374 g_settings->getFloat("profiler_print_interval");
5375 if(profiler_print_interval != 0)
5377 if(m_profiler_interval.step(steplen, profiler_print_interval))
5379 infostream<<"Profiler:"<<std::endl;
5380 g_profiler->print(infostream);
5381 g_profiler->clear();