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);
1093 // Figure out and report maximum lag to environment
1094 float max_lag = m_env->getMaxLagEstimate();
1095 max_lag *= 0.9998; // Decrease slowly (about half per 5 minutes)
1096 if(dtime > max_lag){
1097 if(dtime > 0.1 && dtime > max_lag * 2.0)
1098 infostream<<"Server: Maximum lag peaked to "<<dtime
1102 m_env->reportMaxLagEstimate(max_lag);
1104 ScopeProfiler sp(g_profiler, "SEnv step");
1105 ScopeProfiler sp2(g_profiler, "SEnv step avg", SPT_AVG);
1109 const float map_timer_and_unload_dtime = 2.92;
1110 if(m_map_timer_and_unload_interval.step(dtime, map_timer_and_unload_dtime))
1112 JMutexAutoLock lock(m_env_mutex);
1113 // Run Map's timers and unload unused data
1114 ScopeProfiler sp(g_profiler, "Server: map timer and unload");
1115 m_env->getMap().timerUpdate(map_timer_and_unload_dtime,
1116 g_settings->getFloat("server_unload_unused_data_timeout"));
1127 JMutexAutoLock lock(m_env_mutex);
1128 JMutexAutoLock lock2(m_con_mutex);
1130 ScopeProfiler sp(g_profiler, "Server: handle players");
1132 for(std::map<u16, RemoteClient*>::iterator
1133 i = m_clients.begin();
1134 i != m_clients.end(); ++i)
1136 RemoteClient *client = i->second;
1137 PlayerSAO *playersao = getPlayerSAO(client->peer_id);
1138 if(playersao == NULL)
1142 Handle player HPs (die if hp=0)
1144 if(playersao->m_hp_not_sent && g_settings->getBool("enable_damage"))
1146 if(playersao->getHP() == 0)
1147 DiePlayer(client->peer_id);
1149 SendPlayerHP(client->peer_id);
1153 Send player breath if changed
1155 if(playersao->m_breath_not_sent){
1156 SendPlayerBreath(client->peer_id);
1160 Send player inventories if necessary
1162 if(playersao->m_moved){
1163 SendMovePlayer(client->peer_id);
1164 playersao->m_moved = false;
1166 if(playersao->m_inventory_not_sent){
1167 UpdateCrafting(client->peer_id);
1168 SendInventory(client->peer_id);
1173 /* Transform liquids */
1174 m_liquid_transform_timer += dtime;
1175 if(m_liquid_transform_timer >= m_liquid_transform_every)
1177 m_liquid_transform_timer -= m_liquid_transform_every;
1179 JMutexAutoLock lock(m_env_mutex);
1181 ScopeProfiler sp(g_profiler, "Server: liquid transform");
1183 std::map<v3s16, MapBlock*> modified_blocks;
1184 m_env->getMap().transformLiquids(modified_blocks);
1189 core::map<v3s16, MapBlock*> lighting_modified_blocks;
1190 ServerMap &map = ((ServerMap&)m_env->getMap());
1191 map.updateLighting(modified_blocks, lighting_modified_blocks);
1193 // Add blocks modified by lighting to modified_blocks
1194 for(core::map<v3s16, MapBlock*>::Iterator
1195 i = lighting_modified_blocks.getIterator();
1196 i.atEnd() == false; i++)
1198 MapBlock *block = i.getNode()->getValue();
1199 modified_blocks.insert(block->getPos(), block);
1203 Set the modified blocks unsent for all the clients
1206 JMutexAutoLock lock2(m_con_mutex);
1208 for(std::map<u16, RemoteClient*>::iterator
1209 i = m_clients.begin();
1210 i != m_clients.end(); ++i)
1212 RemoteClient *client = i->second;
1214 if(modified_blocks.size() > 0)
1216 // Remove block from sent history
1217 client->SetBlocksNotSent(modified_blocks);
1222 // Periodically print some info
1224 float &counter = m_print_info_timer;
1230 JMutexAutoLock lock2(m_con_mutex);
1231 m_clients_number = 0;
1232 if(m_clients.size() != 0)
1233 infostream<<"Players:"<<std::endl;
1234 for(std::map<u16, RemoteClient*>::iterator
1235 i = m_clients.begin();
1236 i != m_clients.end(); ++i)
1238 //u16 peer_id = i.getNode()->getKey();
1239 RemoteClient *client = i->second;
1240 Player *player = m_env->getPlayer(client->peer_id);
1243 infostream<<"* "<<player->getName()<<"\t";
1244 client->PrintInfo(infostream);
1252 // send masterserver announce
1254 float &counter = m_masterserver_timer;
1255 if(!isSingleplayer() && (!counter || counter >= 300.0) && g_settings->getBool("server_announce") == true)
1257 ServerList::sendAnnounce(!counter ? "start" : "update", m_clients_number, m_uptime.get(), m_gamespec.id, m_mods);
1264 //if(g_settings->getBool("enable_experimental"))
1268 Check added and deleted active objects
1271 //infostream<<"Server: Checking added and deleted active objects"<<std::endl;
1272 JMutexAutoLock envlock(m_env_mutex);
1273 JMutexAutoLock conlock(m_con_mutex);
1275 ScopeProfiler sp(g_profiler, "Server: checking added and deleted objs");
1277 // Radius inside which objects are active
1278 s16 radius = g_settings->getS16("active_object_send_range_blocks");
1279 radius *= MAP_BLOCKSIZE;
1281 for(std::map<u16, RemoteClient*>::iterator
1282 i = m_clients.begin();
1283 i != m_clients.end(); ++i)
1285 RemoteClient *client = i->second;
1287 // If definitions and textures have not been sent, don't
1288 // send objects either
1289 if(!client->definitions_sent)
1292 Player *player = m_env->getPlayer(client->peer_id);
1295 // This can happen if the client timeouts somehow
1296 /*infostream<<"WARNING: "<<__FUNCTION_NAME<<": Client "
1298 <<" has no associated player"<<std::endl;*/
1301 v3s16 pos = floatToInt(player->getPosition(), BS);
1303 std::set<u16> removed_objects;
1304 std::set<u16> added_objects;
1305 m_env->getRemovedActiveObjects(pos, radius,
1306 client->m_known_objects, removed_objects);
1307 m_env->getAddedActiveObjects(pos, radius,
1308 client->m_known_objects, added_objects);
1310 // Ignore if nothing happened
1311 if(removed_objects.size() == 0 && added_objects.size() == 0)
1313 //infostream<<"active objects: none changed"<<std::endl;
1317 std::string data_buffer;
1321 // Handle removed objects
1322 writeU16((u8*)buf, removed_objects.size());
1323 data_buffer.append(buf, 2);
1324 for(std::set<u16>::iterator
1325 i = removed_objects.begin();
1326 i != removed_objects.end(); ++i)
1330 ServerActiveObject* obj = m_env->getActiveObject(id);
1332 // Add to data buffer for sending
1333 writeU16((u8*)buf, id);
1334 data_buffer.append(buf, 2);
1336 // Remove from known objects
1337 client->m_known_objects.erase(id);
1339 if(obj && obj->m_known_by_count > 0)
1340 obj->m_known_by_count--;
1343 // Handle added objects
1344 writeU16((u8*)buf, added_objects.size());
1345 data_buffer.append(buf, 2);
1346 for(std::set<u16>::iterator
1347 i = added_objects.begin();
1348 i != added_objects.end(); ++i)
1352 ServerActiveObject* obj = m_env->getActiveObject(id);
1355 u8 type = ACTIVEOBJECT_TYPE_INVALID;
1357 infostream<<"WARNING: "<<__FUNCTION_NAME
1358 <<": NULL object"<<std::endl;
1360 type = obj->getSendType();
1362 // Add to data buffer for sending
1363 writeU16((u8*)buf, id);
1364 data_buffer.append(buf, 2);
1365 writeU8((u8*)buf, type);
1366 data_buffer.append(buf, 1);
1369 data_buffer.append(serializeLongString(
1370 obj->getClientInitializationData(client->net_proto_version)));
1372 data_buffer.append(serializeLongString(""));
1374 // Add to known objects
1375 client->m_known_objects.insert(id);
1378 obj->m_known_by_count++;
1382 SharedBuffer<u8> reply(2 + data_buffer.size());
1383 writeU16(&reply[0], TOCLIENT_ACTIVE_OBJECT_REMOVE_ADD);
1384 memcpy((char*)&reply[2], data_buffer.c_str(),
1385 data_buffer.size());
1387 m_con.Send(client->peer_id, 0, reply, true);
1389 verbosestream<<"Server: Sent object remove/add: "
1390 <<removed_objects.size()<<" removed, "
1391 <<added_objects.size()<<" added, "
1392 <<"packet size is "<<reply.getSize()<<std::endl;
1397 Collect a list of all the objects known by the clients
1398 and report it back to the environment.
1401 core::map<u16, bool> all_known_objects;
1403 for(core::map<u16, RemoteClient*>::Iterator
1404 i = m_clients.getIterator();
1405 i.atEnd() == false; i++)
1407 RemoteClient *client = i.getNode()->getValue();
1408 // Go through all known objects of client
1409 for(core::map<u16, bool>::Iterator
1410 i = client->m_known_objects.getIterator();
1411 i.atEnd()==false; i++)
1413 u16 id = i.getNode()->getKey();
1414 all_known_objects[id] = true;
1418 m_env->setKnownActiveObjects(whatever);
1424 Send object messages
1427 JMutexAutoLock envlock(m_env_mutex);
1428 JMutexAutoLock conlock(m_con_mutex);
1430 ScopeProfiler sp(g_profiler, "Server: sending object messages");
1433 // Value = data sent by object
1434 std::map<u16, std::list<ActiveObjectMessage>* > buffered_messages;
1436 // Get active object messages from environment
1439 ActiveObjectMessage aom = m_env->getActiveObjectMessage();
1443 std::list<ActiveObjectMessage>* message_list = NULL;
1444 std::map<u16, std::list<ActiveObjectMessage>* >::iterator n;
1445 n = buffered_messages.find(aom.id);
1446 if(n == buffered_messages.end())
1448 message_list = new std::list<ActiveObjectMessage>;
1449 buffered_messages[aom.id] = message_list;
1453 message_list = n->second;
1455 message_list->push_back(aom);
1458 // Route data to every client
1459 for(std::map<u16, RemoteClient*>::iterator
1460 i = m_clients.begin();
1461 i != m_clients.end(); ++i)
1463 RemoteClient *client = i->second;
1464 std::string reliable_data;
1465 std::string unreliable_data;
1466 // Go through all objects in message buffer
1467 for(std::map<u16, std::list<ActiveObjectMessage>* >::iterator
1468 j = buffered_messages.begin();
1469 j != buffered_messages.end(); ++j)
1471 // If object is not known by client, skip it
1473 if(client->m_known_objects.find(id) == client->m_known_objects.end())
1475 // Get message list of object
1476 std::list<ActiveObjectMessage>* list = j->second;
1477 // Go through every message
1478 for(std::list<ActiveObjectMessage>::iterator
1479 k = list->begin(); k != list->end(); ++k)
1481 // Compose the full new data with header
1482 ActiveObjectMessage aom = *k;
1483 std::string new_data;
1486 writeU16((u8*)&buf[0], aom.id);
1487 new_data.append(buf, 2);
1489 new_data += serializeString(aom.datastring);
1490 // Add data to buffer
1492 reliable_data += new_data;
1494 unreliable_data += new_data;
1498 reliable_data and unreliable_data are now ready.
1501 if(reliable_data.size() > 0)
1503 SharedBuffer<u8> reply(2 + reliable_data.size());
1504 writeU16(&reply[0], TOCLIENT_ACTIVE_OBJECT_MESSAGES);
1505 memcpy((char*)&reply[2], reliable_data.c_str(),
1506 reliable_data.size());
1508 m_con.Send(client->peer_id, 0, reply, true);
1510 if(unreliable_data.size() > 0)
1512 SharedBuffer<u8> reply(2 + unreliable_data.size());
1513 writeU16(&reply[0], TOCLIENT_ACTIVE_OBJECT_MESSAGES);
1514 memcpy((char*)&reply[2], unreliable_data.c_str(),
1515 unreliable_data.size());
1516 // Send as unreliable
1517 m_con.Send(client->peer_id, 0, reply, false);
1520 /*if(reliable_data.size() > 0 || unreliable_data.size() > 0)
1522 infostream<<"Server: Size of object message data: "
1523 <<"reliable: "<<reliable_data.size()
1524 <<", unreliable: "<<unreliable_data.size()
1529 // Clear buffered_messages
1530 for(std::map<u16, std::list<ActiveObjectMessage>* >::iterator
1531 i = buffered_messages.begin();
1532 i != buffered_messages.end(); ++i)
1538 } // enable_experimental
1541 Send queued-for-sending map edit events.
1544 // We will be accessing the environment and the connection
1545 JMutexAutoLock lock(m_env_mutex);
1546 JMutexAutoLock conlock(m_con_mutex);
1548 // Don't send too many at a time
1551 // Single change sending is disabled if queue size is not small
1552 bool disable_single_change_sending = false;
1553 if(m_unsent_map_edit_queue.size() >= 4)
1554 disable_single_change_sending = true;
1556 int event_count = m_unsent_map_edit_queue.size();
1558 // We'll log the amount of each
1561 while(m_unsent_map_edit_queue.size() != 0)
1563 MapEditEvent* event = m_unsent_map_edit_queue.pop_front();
1565 // Players far away from the change are stored here.
1566 // Instead of sending the changes, MapBlocks are set not sent
1568 std::list<u16> far_players;
1570 if(event->type == MEET_ADDNODE)
1572 //infostream<<"Server: MEET_ADDNODE"<<std::endl;
1573 prof.add("MEET_ADDNODE", 1);
1574 if(disable_single_change_sending)
1575 sendAddNode(event->p, event->n, event->already_known_by_peer,
1578 sendAddNode(event->p, event->n, event->already_known_by_peer,
1581 else if(event->type == MEET_REMOVENODE)
1583 //infostream<<"Server: MEET_REMOVENODE"<<std::endl;
1584 prof.add("MEET_REMOVENODE", 1);
1585 if(disable_single_change_sending)
1586 sendRemoveNode(event->p, event->already_known_by_peer,
1589 sendRemoveNode(event->p, event->already_known_by_peer,
1592 else if(event->type == MEET_BLOCK_NODE_METADATA_CHANGED)
1594 infostream<<"Server: MEET_BLOCK_NODE_METADATA_CHANGED"<<std::endl;
1595 prof.add("MEET_BLOCK_NODE_METADATA_CHANGED", 1);
1596 setBlockNotSent(event->p);
1598 else if(event->type == MEET_OTHER)
1600 infostream<<"Server: MEET_OTHER"<<std::endl;
1601 prof.add("MEET_OTHER", 1);
1602 for(std::set<v3s16>::iterator
1603 i = event->modified_blocks.begin();
1604 i != event->modified_blocks.end(); ++i)
1606 setBlockNotSent(*i);
1611 prof.add("unknown", 1);
1612 infostream<<"WARNING: Server: Unknown MapEditEvent "
1613 <<((u32)event->type)<<std::endl;
1617 Set blocks not sent to far players
1619 if(far_players.size() > 0)
1621 // Convert list format to that wanted by SetBlocksNotSent
1622 std::map<v3s16, MapBlock*> modified_blocks2;
1623 for(std::set<v3s16>::iterator
1624 i = event->modified_blocks.begin();
1625 i != event->modified_blocks.end(); ++i)
1627 modified_blocks2[*i] =
1628 m_env->getMap().getBlockNoCreateNoEx(*i);
1630 // Set blocks not sent
1631 for(std::list<u16>::iterator
1632 i = far_players.begin();
1633 i != far_players.end(); ++i)
1636 RemoteClient *client = getClient(peer_id);
1639 client->SetBlocksNotSent(modified_blocks2);
1645 /*// Don't send too many at a time
1647 if(count >= 1 && m_unsent_map_edit_queue.size() < 100)
1651 if(event_count >= 5){
1652 infostream<<"Server: MapEditEvents:"<<std::endl;
1653 prof.print(infostream);
1654 } else if(event_count != 0){
1655 verbosestream<<"Server: MapEditEvents:"<<std::endl;
1656 prof.print(verbosestream);
1662 Trigger emergethread (it somehow gets to a non-triggered but
1663 bysy state sometimes)
1666 float &counter = m_emergethread_trigger_timer;
1672 for (unsigned int i = 0; i != m_emerge->emergethread.size(); i++)
1673 m_emerge->emergethread[i]->trigger();
1675 // Update m_enable_rollback_recording here too
1676 m_enable_rollback_recording =
1677 g_settings->getBool("enable_rollback_recording");
1681 // Save map, players and auth stuff
1683 float &counter = m_savemap_timer;
1685 if(counter >= g_settings->getFloat("server_map_save_interval"))
1688 JMutexAutoLock lock(m_env_mutex);
1690 ScopeProfiler sp(g_profiler, "Server: saving stuff");
1693 if(m_banmanager.isModified())
1694 m_banmanager.save();
1696 // Save changed parts of map
1697 m_env->getMap().save(MOD_STATE_WRITE_NEEDED);
1700 m_env->serializePlayers(m_path_world);
1702 // Save environment metadata
1703 m_env->saveMeta(m_path_world);
1708 void Server::Receive()
1710 DSTACK(__FUNCTION_NAME);
1711 SharedBuffer<u8> data;
1716 JMutexAutoLock conlock(m_con_mutex);
1717 datasize = m_con.Receive(peer_id, data);
1720 // This has to be called so that the client list gets synced
1721 // with the peer list of the connection
1722 handlePeerChanges();
1724 ProcessData(*data, datasize, peer_id);
1726 catch(con::InvalidIncomingDataException &e)
1728 infostream<<"Server::Receive(): "
1729 "InvalidIncomingDataException: what()="
1730 <<e.what()<<std::endl;
1732 catch(con::PeerNotFoundException &e)
1734 //NOTE: This is not needed anymore
1736 // The peer has been disconnected.
1737 // Find the associated player and remove it.
1739 /*JMutexAutoLock envlock(m_env_mutex);
1741 infostream<<"ServerThread: peer_id="<<peer_id
1742 <<" has apparently closed connection. "
1743 <<"Removing player."<<std::endl;
1745 m_env->removePlayer(peer_id);*/
1749 void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
1751 DSTACK(__FUNCTION_NAME);
1752 // Environment is locked first.
1753 JMutexAutoLock envlock(m_env_mutex);
1754 JMutexAutoLock conlock(m_con_mutex);
1756 ScopeProfiler sp(g_profiler, "Server::ProcessData");
1760 Address address = m_con.GetPeerAddress(peer_id);
1761 addr_s = address.serializeString();
1763 // drop player if is ip is banned
1764 if(m_banmanager.isIpBanned(addr_s)){
1765 infostream<<"Server: A banned client tried to connect from "
1766 <<addr_s<<"; banned name was "
1767 <<m_banmanager.getBanName(addr_s)<<std::endl;
1768 // This actually doesn't seem to transfer to the client
1769 SendAccessDenied(m_con, peer_id,
1770 L"Your ip is banned. Banned name was "
1771 +narrow_to_wide(m_banmanager.getBanName(addr_s)));
1772 m_con.DeletePeer(peer_id);
1776 catch(con::PeerNotFoundException &e)
1778 infostream<<"Server::ProcessData(): Cancelling: peer "
1779 <<peer_id<<" not found"<<std::endl;
1783 u8 peer_ser_ver = getClient(peer_id)->serialization_version;
1791 ToServerCommand command = (ToServerCommand)readU16(&data[0]);
1793 if(command == TOSERVER_INIT)
1795 // [0] u16 TOSERVER_INIT
1796 // [2] u8 SER_FMT_VER_HIGHEST_READ
1797 // [3] u8[20] player_name
1798 // [23] u8[28] password <--- can be sent without this, from old versions
1800 if(datasize < 2+1+PLAYERNAME_SIZE)
1803 verbosestream<<"Server: Got TOSERVER_INIT from "
1804 <<peer_id<<std::endl;
1806 // First byte after command is maximum supported
1807 // serialization version
1808 u8 client_max = data[2];
1809 u8 our_max = SER_FMT_VER_HIGHEST_READ;
1810 // Use the highest version supported by both
1811 u8 deployed = std::min(client_max, our_max);
1812 // If it's lower than the lowest supported, give up.
1813 if(deployed < SER_FMT_VER_LOWEST)
1814 deployed = SER_FMT_VER_INVALID;
1816 //peer->serialization_version = deployed;
1817 getClient(peer_id)->pending_serialization_version = deployed;
1819 if(deployed == SER_FMT_VER_INVALID)
1821 actionstream<<"Server: A mismatched client tried to connect from "
1822 <<addr_s<<std::endl;
1823 infostream<<"Server: Cannot negotiate "
1824 "serialization version with peer "
1825 <<peer_id<<std::endl;
1826 SendAccessDenied(m_con, peer_id, std::wstring(
1827 L"Your client's version is not supported.\n"
1828 L"Server version is ")
1829 + narrow_to_wide(VERSION_STRING) + L"."
1835 Read and check network protocol version
1838 u16 min_net_proto_version = 0;
1839 if(datasize >= 2+1+PLAYERNAME_SIZE+PASSWORD_SIZE+2)
1840 min_net_proto_version = readU16(&data[2+1+PLAYERNAME_SIZE+PASSWORD_SIZE]);
1842 // Use same version as minimum and maximum if maximum version field
1843 // doesn't exist (backwards compatibility)
1844 u16 max_net_proto_version = min_net_proto_version;
1845 if(datasize >= 2+1+PLAYERNAME_SIZE+PASSWORD_SIZE+2+2)
1846 max_net_proto_version = readU16(&data[2+1+PLAYERNAME_SIZE+PASSWORD_SIZE+2]);
1848 // Start with client's maximum version
1849 u16 net_proto_version = max_net_proto_version;
1851 // Figure out a working version if it is possible at all
1852 if(max_net_proto_version >= SERVER_PROTOCOL_VERSION_MIN ||
1853 min_net_proto_version <= SERVER_PROTOCOL_VERSION_MAX)
1855 // If maximum is larger than our maximum, go with our maximum
1856 if(max_net_proto_version > SERVER_PROTOCOL_VERSION_MAX)
1857 net_proto_version = SERVER_PROTOCOL_VERSION_MAX;
1858 // Else go with client's maximum
1860 net_proto_version = max_net_proto_version;
1863 verbosestream<<"Server: "<<peer_id<<" Protocol version: min: "
1864 <<min_net_proto_version<<", max: "<<max_net_proto_version
1865 <<", chosen: "<<net_proto_version<<std::endl;
1867 getClient(peer_id)->net_proto_version = net_proto_version;
1869 if(net_proto_version < SERVER_PROTOCOL_VERSION_MIN ||
1870 net_proto_version > SERVER_PROTOCOL_VERSION_MAX)
1872 actionstream<<"Server: A mismatched client tried to connect from "<<addr_s
1874 SendAccessDenied(m_con, peer_id, std::wstring(
1875 L"Your client's version is not supported.\n"
1876 L"Server version is ")
1877 + narrow_to_wide(VERSION_STRING) + L",\n"
1878 + L"server's PROTOCOL_VERSION is "
1879 + narrow_to_wide(itos(SERVER_PROTOCOL_VERSION_MIN))
1881 + narrow_to_wide(itos(SERVER_PROTOCOL_VERSION_MAX))
1882 + L", client's PROTOCOL_VERSION is "
1883 + narrow_to_wide(itos(min_net_proto_version))
1885 + narrow_to_wide(itos(max_net_proto_version))
1890 if(g_settings->getBool("strict_protocol_version_checking"))
1892 if(net_proto_version != LATEST_PROTOCOL_VERSION)
1894 actionstream<<"Server: A mismatched (strict) client tried to "
1895 <<"connect from "<<addr_s<<std::endl;
1896 SendAccessDenied(m_con, peer_id, std::wstring(
1897 L"Your client's version is not supported.\n"
1898 L"Server version is ")
1899 + narrow_to_wide(VERSION_STRING) + L",\n"
1900 + L"server's PROTOCOL_VERSION (strict) is "
1901 + narrow_to_wide(itos(LATEST_PROTOCOL_VERSION))
1902 + L", client's PROTOCOL_VERSION is "
1903 + narrow_to_wide(itos(min_net_proto_version))
1905 + narrow_to_wide(itos(max_net_proto_version))
1916 char playername[PLAYERNAME_SIZE];
1917 for(u32 i=0; i<PLAYERNAME_SIZE-1; i++)
1919 playername[i] = data[3+i];
1921 playername[PLAYERNAME_SIZE-1] = 0;
1923 if(playername[0]=='\0')
1925 actionstream<<"Server: Player with an empty name "
1926 <<"tried to connect from "<<addr_s<<std::endl;
1927 SendAccessDenied(m_con, peer_id,
1932 if(string_allowed(playername, PLAYERNAME_ALLOWED_CHARS)==false)
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 contains unallowed characters");
1941 if(!isSingleplayer() && strcasecmp(playername, "singleplayer") == 0)
1943 actionstream<<"Server: Player with an invalid name "
1944 <<"tried to connect from "<<addr_s<<std::endl;
1945 SendAccessDenied(m_con, peer_id,
1946 L"Name is not allowed");
1950 infostream<<"Server: New connection: \""<<playername<<"\" from "
1951 <<m_con.GetPeerAddress(peer_id).serializeString()<<std::endl;
1954 char given_password[PASSWORD_SIZE];
1955 if(datasize < 2+1+PLAYERNAME_SIZE+PASSWORD_SIZE)
1957 // old version - assume blank password
1958 given_password[0] = 0;
1962 for(u32 i=0; i<PASSWORD_SIZE-1; i++)
1964 given_password[i] = data[23+i];
1966 given_password[PASSWORD_SIZE-1] = 0;
1969 if(!base64_is_valid(given_password)){
1970 infostream<<"Server: "<<playername
1971 <<" supplied invalid password hash"<<std::endl;
1972 SendAccessDenied(m_con, peer_id, L"Invalid password hash");
1976 std::string checkpwd; // Password hash to check against
1977 bool has_auth = m_script->getAuth(playername, &checkpwd, NULL);
1979 // If no authentication info exists for user, create it
1981 if(!isSingleplayer() &&
1982 g_settings->getBool("disallow_empty_password") &&
1983 std::string(given_password) == ""){
1984 SendAccessDenied(m_con, peer_id, L"Empty passwords are "
1985 L"disallowed. Set a password and try again.");
1988 std::wstring raw_default_password =
1989 narrow_to_wide(g_settings->get("default_password"));
1990 std::string initial_password =
1991 translatePassword(playername, raw_default_password);
1993 // If default_password is empty, allow any initial password
1994 if (raw_default_password.length() == 0)
1995 initial_password = given_password;
1997 m_script->createAuth(playername, initial_password);
2000 has_auth = m_script->getAuth(playername, &checkpwd, NULL);
2003 SendAccessDenied(m_con, peer_id, L"Not allowed to login");
2007 if(given_password != checkpwd){
2008 infostream<<"Server: peer_id="<<peer_id
2009 <<": supplied invalid password for "
2010 <<playername<<std::endl;
2011 SendAccessDenied(m_con, peer_id, L"Invalid password");
2015 // Do not allow multiple players in simple singleplayer mode.
2016 // This isn't a perfect way to do it, but will suffice for now.
2017 if(m_simple_singleplayer_mode && m_clients.size() > 1){
2018 infostream<<"Server: Not allowing another client to connect in"
2019 <<" simple singleplayer mode"<<std::endl;
2020 SendAccessDenied(m_con, peer_id,
2021 L"Running in simple singleplayer mode.");
2025 // Enforce user limit.
2026 // Don't enforce for users that have some admin right
2027 if(m_clients.size() >= g_settings->getU16("max_users") &&
2028 !checkPriv(playername, "server") &&
2029 !checkPriv(playername, "ban") &&
2030 !checkPriv(playername, "privs") &&
2031 !checkPriv(playername, "password") &&
2032 playername != g_settings->get("name"))
2034 actionstream<<"Server: "<<playername<<" tried to join, but there"
2035 <<" are already max_users="
2036 <<g_settings->getU16("max_users")<<" players."<<std::endl;
2037 SendAccessDenied(m_con, peer_id, L"Too many users.");
2042 PlayerSAO *playersao = emergePlayer(playername, peer_id);
2044 // If failed, cancel
2045 if(playersao == NULL)
2047 errorstream<<"Server: peer_id="<<peer_id
2048 <<": failed to emerge player"<<std::endl;
2053 Answer with a TOCLIENT_INIT
2056 SharedBuffer<u8> reply(2+1+6+8+4);
2057 writeU16(&reply[0], TOCLIENT_INIT);
2058 writeU8(&reply[2], deployed);
2059 writeV3S16(&reply[2+1], floatToInt(playersao->getPlayer()->getPosition()+v3f(0,BS/2,0), BS));
2060 writeU64(&reply[2+1+6], m_env->getServerMap().getSeed());
2061 writeF1000(&reply[2+1+6+8], g_settings->getFloat("dedicated_server_step"));
2064 m_con.Send(peer_id, 0, reply, true);
2068 Send complete position information
2070 SendMovePlayer(peer_id);
2075 if(command == TOSERVER_INIT2)
2077 verbosestream<<"Server: Got TOSERVER_INIT2 from "
2078 <<peer_id<<std::endl;
2080 Player *player = m_env->getPlayer(peer_id);
2082 verbosestream<<"Server: TOSERVER_INIT2: "
2083 <<"Player not found; ignoring."<<std::endl;
2087 RemoteClient *client = getClient(peer_id);
2088 client->serialization_version =
2089 getClient(peer_id)->pending_serialization_version;
2092 Send some initialization data
2095 infostream<<"Server: Sending content to "
2096 <<getPlayerName(peer_id)<<std::endl;
2098 // Send player movement settings
2099 SendMovement(m_con, peer_id);
2101 // Send item definitions
2102 SendItemDef(m_con, peer_id, m_itemdef, client->net_proto_version);
2104 // Send node definitions
2105 SendNodeDef(m_con, peer_id, m_nodedef, client->net_proto_version);
2107 // Send media announcement
2108 sendMediaAnnouncement(peer_id);
2111 SendPlayerPrivileges(peer_id);
2113 // Send inventory formspec
2114 SendPlayerInventoryFormspec(peer_id);
2117 UpdateCrafting(peer_id);
2118 SendInventory(peer_id);
2121 if(g_settings->getBool("enable_damage"))
2122 SendPlayerHP(peer_id);
2125 SendPlayerBreath(peer_id);
2127 // Send detached inventories
2128 sendDetachedInventories(peer_id);
2130 // Show death screen if necessary
2132 SendDeathscreen(m_con, peer_id, false, v3f(0,0,0));
2136 SharedBuffer<u8> data = makePacket_TOCLIENT_TIME_OF_DAY(
2137 m_env->getTimeOfDay(), g_settings->getFloat("time_speed"));
2138 m_con.Send(peer_id, 0, data, true);
2141 // Note things in chat if not in simple singleplayer mode
2142 if(!m_simple_singleplayer_mode)
2144 // Send information about server to player in chat
2145 SendChatMessage(peer_id, getStatusString());
2147 // Send information about joining in chat
2149 std::wstring name = L"unknown";
2150 Player *player = m_env->getPlayer(peer_id);
2152 name = narrow_to_wide(player->getName());
2154 std::wstring message;
2157 message += L" joined the game.";
2158 BroadcastChatMessage(message);
2162 // Warnings about protocol version can be issued here
2163 if(getClient(peer_id)->net_proto_version < LATEST_PROTOCOL_VERSION)
2165 SendChatMessage(peer_id, L"# Server: WARNING: YOUR CLIENT'S "
2166 L"VERSION MAY NOT BE FULLY COMPATIBLE WITH THIS SERVER!");
2173 std::ostringstream os(std::ios_base::binary);
2174 for(std::map<u16, RemoteClient*>::iterator
2175 i = m_clients.begin();
2176 i != m_clients.end(); ++i)
2178 RemoteClient *client = i->second;
2179 assert(client->peer_id == i->first);
2180 if(client->serialization_version == SER_FMT_VER_INVALID)
2183 Player *player = m_env->getPlayer(client->peer_id);
2186 // Get name of player
2187 os<<player->getName()<<" ";
2190 actionstream<<player->getName()<<" ["<<addr_s<<"] "<<"joins game. List of players: "
2191 <<os.str()<<std::endl;
2197 if(peer_ser_ver == SER_FMT_VER_INVALID)
2199 infostream<<"Server::ProcessData(): Cancelling: Peer"
2200 " serialization format invalid or not initialized."
2201 " Skipping incoming command="<<command<<std::endl;
2205 Player *player = m_env->getPlayer(peer_id);
2207 infostream<<"Server::ProcessData(): Cancelling: "
2208 "No player for peer_id="<<peer_id
2213 PlayerSAO *playersao = player->getPlayerSAO();
2214 if(playersao == NULL){
2215 infostream<<"Server::ProcessData(): Cancelling: "
2216 "No player object for peer_id="<<peer_id
2221 if(command == TOSERVER_PLAYERPOS)
2223 if(datasize < 2+12+12+4+4)
2227 v3s32 ps = readV3S32(&data[start+2]);
2228 v3s32 ss = readV3S32(&data[start+2+12]);
2229 f32 pitch = (f32)readS32(&data[2+12+12]) / 100.0;
2230 f32 yaw = (f32)readS32(&data[2+12+12+4]) / 100.0;
2232 if(datasize >= 2+12+12+4+4+4)
2233 keyPressed = (u32)readU32(&data[2+12+12+4+4]);
2234 v3f position((f32)ps.X/100., (f32)ps.Y/100., (f32)ps.Z/100.);
2235 v3f speed((f32)ss.X/100., (f32)ss.Y/100., (f32)ss.Z/100.);
2236 pitch = wrapDegrees(pitch);
2237 yaw = wrapDegrees(yaw);
2239 player->setPosition(position);
2240 player->setSpeed(speed);
2241 player->setPitch(pitch);
2242 player->setYaw(yaw);
2243 player->keyPressed=keyPressed;
2244 player->control.up = (bool)(keyPressed&1);
2245 player->control.down = (bool)(keyPressed&2);
2246 player->control.left = (bool)(keyPressed&4);
2247 player->control.right = (bool)(keyPressed&8);
2248 player->control.jump = (bool)(keyPressed&16);
2249 player->control.aux1 = (bool)(keyPressed&32);
2250 player->control.sneak = (bool)(keyPressed&64);
2251 player->control.LMB = (bool)(keyPressed&128);
2252 player->control.RMB = (bool)(keyPressed&256);
2254 playersao->checkMovementCheat();
2256 /*infostream<<"Server::ProcessData(): Moved player "<<peer_id<<" to "
2257 <<"("<<position.X<<","<<position.Y<<","<<position.Z<<")"
2258 <<" pitch="<<pitch<<" yaw="<<yaw<<std::endl;*/
2260 else if(command == TOSERVER_GOTBLOCKS)
2273 u16 count = data[2];
2274 for(u16 i=0; i<count; i++)
2276 if((s16)datasize < 2+1+(i+1)*6)
2277 throw con::InvalidIncomingDataException
2278 ("GOTBLOCKS length is too short");
2279 v3s16 p = readV3S16(&data[2+1+i*6]);
2280 /*infostream<<"Server: GOTBLOCKS ("
2281 <<p.X<<","<<p.Y<<","<<p.Z<<")"<<std::endl;*/
2282 RemoteClient *client = getClient(peer_id);
2283 client->GotBlock(p);
2286 else if(command == TOSERVER_DELETEDBLOCKS)
2299 u16 count = data[2];
2300 for(u16 i=0; i<count; i++)
2302 if((s16)datasize < 2+1+(i+1)*6)
2303 throw con::InvalidIncomingDataException
2304 ("DELETEDBLOCKS length is too short");
2305 v3s16 p = readV3S16(&data[2+1+i*6]);
2306 /*infostream<<"Server: DELETEDBLOCKS ("
2307 <<p.X<<","<<p.Y<<","<<p.Z<<")"<<std::endl;*/
2308 RemoteClient *client = getClient(peer_id);
2309 client->SetBlockNotSent(p);
2312 else if(command == TOSERVER_CLICK_OBJECT)
2314 infostream<<"Server: CLICK_OBJECT not supported anymore"<<std::endl;
2317 else if(command == TOSERVER_CLICK_ACTIVEOBJECT)
2319 infostream<<"Server: CLICK_ACTIVEOBJECT not supported anymore"<<std::endl;
2322 else if(command == TOSERVER_GROUND_ACTION)
2324 infostream<<"Server: GROUND_ACTION not supported anymore"<<std::endl;
2328 else if(command == TOSERVER_RELEASE)
2330 infostream<<"Server: RELEASE not supported anymore"<<std::endl;
2333 else if(command == TOSERVER_SIGNTEXT)
2335 infostream<<"Server: SIGNTEXT not supported anymore"
2339 else if(command == TOSERVER_SIGNNODETEXT)
2341 infostream<<"Server: SIGNNODETEXT not supported anymore"
2345 else if(command == TOSERVER_INVENTORY_ACTION)
2347 // Strip command and create a stream
2348 std::string datastring((char*)&data[2], datasize-2);
2349 verbosestream<<"TOSERVER_INVENTORY_ACTION: data="<<datastring<<std::endl;
2350 std::istringstream is(datastring, std::ios_base::binary);
2352 InventoryAction *a = InventoryAction::deSerialize(is);
2355 infostream<<"TOSERVER_INVENTORY_ACTION: "
2356 <<"InventoryAction::deSerialize() returned NULL"
2361 // If something goes wrong, this player is to blame
2362 RollbackScopeActor rollback_scope(m_rollback,
2363 std::string("player:")+player->getName());
2366 Note: Always set inventory not sent, to repair cases
2367 where the client made a bad prediction.
2371 Handle restrictions and special cases of the move action
2373 if(a->getType() == IACTION_MOVE)
2375 IMoveAction *ma = (IMoveAction*)a;
2377 ma->from_inv.applyCurrentPlayer(player->getName());
2378 ma->to_inv.applyCurrentPlayer(player->getName());
2380 setInventoryModified(ma->from_inv);
2381 setInventoryModified(ma->to_inv);
2383 bool from_inv_is_current_player =
2384 (ma->from_inv.type == InventoryLocation::PLAYER) &&
2385 (ma->from_inv.name == player->getName());
2387 bool to_inv_is_current_player =
2388 (ma->to_inv.type == InventoryLocation::PLAYER) &&
2389 (ma->to_inv.name == player->getName());
2392 Disable moving items out of craftpreview
2394 if(ma->from_list == "craftpreview")
2396 infostream<<"Ignoring IMoveAction from "
2397 <<(ma->from_inv.dump())<<":"<<ma->from_list
2398 <<" to "<<(ma->to_inv.dump())<<":"<<ma->to_list
2399 <<" because src is "<<ma->from_list<<std::endl;
2405 Disable moving items into craftresult and craftpreview
2407 if(ma->to_list == "craftpreview" || ma->to_list == "craftresult")
2409 infostream<<"Ignoring IMoveAction from "
2410 <<(ma->from_inv.dump())<<":"<<ma->from_list
2411 <<" to "<<(ma->to_inv.dump())<<":"<<ma->to_list
2412 <<" because dst is "<<ma->to_list<<std::endl;
2417 // Disallow moving items in elsewhere than player's inventory
2418 // if not allowed to interact
2419 if(!checkPriv(player->getName(), "interact") &&
2420 (!from_inv_is_current_player ||
2421 !to_inv_is_current_player))
2423 infostream<<"Cannot move outside of player's inventory: "
2424 <<"No interact privilege"<<std::endl;
2430 Handle restrictions and special cases of the drop action
2432 else if(a->getType() == IACTION_DROP)
2434 IDropAction *da = (IDropAction*)a;
2436 da->from_inv.applyCurrentPlayer(player->getName());
2438 setInventoryModified(da->from_inv);
2441 Disable dropping items out of craftpreview
2443 if(da->from_list == "craftpreview")
2445 infostream<<"Ignoring IDropAction from "
2446 <<(da->from_inv.dump())<<":"<<da->from_list
2447 <<" because src is "<<da->from_list<<std::endl;
2452 // Disallow dropping items if not allowed to interact
2453 if(!checkPriv(player->getName(), "interact"))
2460 Handle restrictions and special cases of the craft action
2462 else if(a->getType() == IACTION_CRAFT)
2464 ICraftAction *ca = (ICraftAction*)a;
2466 ca->craft_inv.applyCurrentPlayer(player->getName());
2468 setInventoryModified(ca->craft_inv);
2470 //bool craft_inv_is_current_player =
2471 // (ca->craft_inv.type == InventoryLocation::PLAYER) &&
2472 // (ca->craft_inv.name == player->getName());
2474 // Disallow crafting if not allowed to interact
2475 if(!checkPriv(player->getName(), "interact"))
2477 infostream<<"Cannot craft: "
2478 <<"No interact privilege"<<std::endl;
2485 a->apply(this, playersao, this);
2489 else if(command == TOSERVER_CHAT_MESSAGE)
2497 std::string datastring((char*)&data[2], datasize-2);
2498 std::istringstream is(datastring, std::ios_base::binary);
2501 is.read((char*)buf, 2);
2502 u16 len = readU16(buf);
2504 std::wstring message;
2505 for(u16 i=0; i<len; i++)
2507 is.read((char*)buf, 2);
2508 message += (wchar_t)readU16(buf);
2511 // If something goes wrong, this player is to blame
2512 RollbackScopeActor rollback_scope(m_rollback,
2513 std::string("player:")+player->getName());
2515 // Get player name of this client
2516 std::wstring name = narrow_to_wide(player->getName());
2519 bool ate = m_script->on_chat_message(player->getName(),
2520 wide_to_narrow(message));
2521 // If script ate the message, don't proceed
2525 // Line to send to players
2527 // Whether to send to the player that sent the line
2528 bool send_to_sender = false;
2529 // Whether to send to other players
2530 bool send_to_others = false;
2532 // Commands are implemented in Lua, so only catch invalid
2533 // commands that were not "eaten" and send an error back
2534 if(message[0] == L'/')
2536 message = message.substr(1);
2537 send_to_sender = true;
2538 if(message.length() == 0)
2539 line += L"-!- Empty command";
2541 line += L"-!- Invalid command: " + str_split(message, L' ')[0];
2545 if(checkPriv(player->getName(), "shout")){
2550 send_to_others = true;
2552 line += L"-!- You don't have permission to shout.";
2553 send_to_sender = true;
2560 actionstream<<"CHAT: "<<wide_to_narrow(line)<<std::endl;
2563 Send the message to clients
2565 for(std::map<u16, RemoteClient*>::iterator
2566 i = m_clients.begin();
2567 i != m_clients.end(); ++i)
2569 // Get client and check that it is valid
2570 RemoteClient *client = i->second;
2571 assert(client->peer_id == i->first);
2572 if(client->serialization_version == SER_FMT_VER_INVALID)
2576 bool sender_selected = (peer_id == client->peer_id);
2577 if(sender_selected == true && send_to_sender == false)
2579 if(sender_selected == false && send_to_others == false)
2582 SendChatMessage(client->peer_id, line);
2586 else if(command == TOSERVER_DAMAGE)
2588 std::string datastring((char*)&data[2], datasize-2);
2589 std::istringstream is(datastring, std::ios_base::binary);
2590 u8 damage = readU8(is);
2592 if(g_settings->getBool("enable_damage"))
2594 actionstream<<player->getName()<<" damaged by "
2595 <<(int)damage<<" hp at "<<PP(player->getPosition()/BS)
2598 playersao->setHP(playersao->getHP() - damage);
2600 if(playersao->getHP() == 0 && playersao->m_hp_not_sent)
2603 if(playersao->m_hp_not_sent)
2604 SendPlayerHP(peer_id);
2607 else if(command == TOSERVER_BREATH)
2609 std::string datastring((char*)&data[2], datasize-2);
2610 std::istringstream is(datastring, std::ios_base::binary);
2611 u16 breath = readU16(is);
2612 playersao->setBreath(breath);
2614 else if(command == TOSERVER_PASSWORD)
2617 [0] u16 TOSERVER_PASSWORD
2618 [2] u8[28] old password
2619 [30] u8[28] new password
2622 if(datasize != 2+PASSWORD_SIZE*2)
2624 /*char password[PASSWORD_SIZE];
2625 for(u32 i=0; i<PASSWORD_SIZE-1; i++)
2626 password[i] = data[2+i];
2627 password[PASSWORD_SIZE-1] = 0;*/
2629 for(u32 i=0; i<PASSWORD_SIZE-1; i++)
2637 for(u32 i=0; i<PASSWORD_SIZE-1; i++)
2639 char c = data[2+PASSWORD_SIZE+i];
2645 if(!base64_is_valid(newpwd)){
2646 infostream<<"Server: "<<player->getName()<<" supplied invalid password hash"<<std::endl;
2647 // Wrong old password supplied!!
2648 SendChatMessage(peer_id, L"Invalid new password hash supplied. Password NOT changed.");
2652 infostream<<"Server: Client requests a password change from "
2653 <<"'"<<oldpwd<<"' to '"<<newpwd<<"'"<<std::endl;
2655 std::string playername = player->getName();
2657 std::string checkpwd;
2658 m_script->getAuth(playername, &checkpwd, NULL);
2660 if(oldpwd != checkpwd)
2662 infostream<<"Server: invalid old password"<<std::endl;
2663 // Wrong old password supplied!!
2664 SendChatMessage(peer_id, L"Invalid old password supplied. Password NOT changed.");
2668 bool success = m_script->setPassword(playername, newpwd);
2670 actionstream<<player->getName()<<" changes password"<<std::endl;
2671 SendChatMessage(peer_id, L"Password change successful.");
2673 actionstream<<player->getName()<<" tries to change password but "
2674 <<"it fails"<<std::endl;
2675 SendChatMessage(peer_id, L"Password change failed or inavailable.");
2678 else if(command == TOSERVER_PLAYERITEM)
2683 u16 item = readU16(&data[2]);
2684 playersao->setWieldIndex(item);
2686 else if(command == TOSERVER_RESPAWN)
2688 if(player->hp != 0 || !g_settings->getBool("enable_damage"))
2691 RespawnPlayer(peer_id);
2693 actionstream<<player->getName()<<" respawns at "
2694 <<PP(player->getPosition()/BS)<<std::endl;
2696 // ActiveObject is added to environment in AsyncRunStep after
2697 // the previous addition has been succesfully removed
2699 else if(command == TOSERVER_REQUEST_MEDIA) {
2700 std::string datastring((char*)&data[2], datasize-2);
2701 std::istringstream is(datastring, std::ios_base::binary);
2703 std::list<MediaRequest> tosend;
2704 u16 numfiles = readU16(is);
2706 infostream<<"Sending "<<numfiles<<" files to "
2707 <<getPlayerName(peer_id)<<std::endl;
2708 verbosestream<<"TOSERVER_REQUEST_MEDIA: "<<std::endl;
2710 for(int i = 0; i < numfiles; i++) {
2711 std::string name = deSerializeString(is);
2712 tosend.push_back(MediaRequest(name));
2713 verbosestream<<"TOSERVER_REQUEST_MEDIA: requested file "
2717 sendRequestedMedia(peer_id, tosend);
2719 // Now the client should know about everything
2720 // (definitions and files)
2721 getClient(peer_id)->definitions_sent = true;
2723 else if(command == TOSERVER_RECEIVED_MEDIA) {
2724 getClient(peer_id)->definitions_sent = true;
2726 else if(command == TOSERVER_INTERACT)
2728 std::string datastring((char*)&data[2], datasize-2);
2729 std::istringstream is(datastring, std::ios_base::binary);
2735 [5] u32 length of the next item
2736 [9] serialized PointedThing
2738 0: start digging (from undersurface) or use
2739 1: stop digging (all parameters ignored)
2740 2: digging completed
2741 3: place block or item (to abovesurface)
2744 u8 action = readU8(is);
2745 u16 item_i = readU16(is);
2746 std::istringstream tmp_is(deSerializeLongString(is), std::ios::binary);
2747 PointedThing pointed;
2748 pointed.deSerialize(tmp_is);
2750 verbosestream<<"TOSERVER_INTERACT: action="<<(int)action<<", item="
2751 <<item_i<<", pointed="<<pointed.dump()<<std::endl;
2755 verbosestream<<"TOSERVER_INTERACT: "<<player->getName()
2756 <<" tried to interact, but is dead!"<<std::endl;
2760 v3f player_pos = playersao->getLastGoodPosition();
2762 // Update wielded item
2763 playersao->setWieldIndex(item_i);
2765 // Get pointed to node (undefined if not POINTEDTYPE_NODE)
2766 v3s16 p_under = pointed.node_undersurface;
2767 v3s16 p_above = pointed.node_abovesurface;
2769 // Get pointed to object (NULL if not POINTEDTYPE_OBJECT)
2770 ServerActiveObject *pointed_object = NULL;
2771 if(pointed.type == POINTEDTHING_OBJECT)
2773 pointed_object = m_env->getActiveObject(pointed.object_id);
2774 if(pointed_object == NULL)
2776 verbosestream<<"TOSERVER_INTERACT: "
2777 "pointed object is NULL"<<std::endl;
2783 v3f pointed_pos_under = player_pos;
2784 v3f pointed_pos_above = player_pos;
2785 if(pointed.type == POINTEDTHING_NODE)
2787 pointed_pos_under = intToFloat(p_under, BS);
2788 pointed_pos_above = intToFloat(p_above, BS);
2790 else if(pointed.type == POINTEDTHING_OBJECT)
2792 pointed_pos_under = pointed_object->getBasePosition();
2793 pointed_pos_above = pointed_pos_under;
2797 Check that target is reasonably close
2798 (only when digging or placing things)
2800 if(action == 0 || action == 2 || action == 3)
2802 float d = player_pos.getDistanceFrom(pointed_pos_under);
2803 float max_d = BS * 14; // Just some large enough value
2805 actionstream<<"Player "<<player->getName()
2806 <<" tried to access "<<pointed.dump()
2808 <<"d="<<d<<", max_d="<<max_d
2809 <<". ignoring."<<std::endl;
2810 // Re-send block to revert change on client-side
2811 RemoteClient *client = getClient(peer_id);
2812 v3s16 blockpos = getNodeBlockPos(floatToInt(pointed_pos_under, BS));
2813 client->SetBlockNotSent(blockpos);
2820 Make sure the player is allowed to do it
2822 if(!checkPriv(player->getName(), "interact"))
2824 actionstream<<player->getName()<<" attempted to interact with "
2825 <<pointed.dump()<<" without 'interact' privilege"
2827 // Re-send block to revert change on client-side
2828 RemoteClient *client = getClient(peer_id);
2829 // Digging completed -> under
2831 v3s16 blockpos = getNodeBlockPos(floatToInt(pointed_pos_under, BS));
2832 client->SetBlockNotSent(blockpos);
2834 // Placement -> above
2836 v3s16 blockpos = getNodeBlockPos(floatToInt(pointed_pos_above, BS));
2837 client->SetBlockNotSent(blockpos);
2843 If something goes wrong, this player is to blame
2845 RollbackScopeActor rollback_scope(m_rollback,
2846 std::string("player:")+player->getName());
2849 0: start digging or punch object
2853 if(pointed.type == POINTEDTHING_NODE)
2856 NOTE: This can be used in the future to check if
2857 somebody is cheating, by checking the timing.
2859 MapNode n(CONTENT_IGNORE);
2862 n = m_env->getMap().getNode(p_under);
2864 catch(InvalidPositionException &e)
2866 infostream<<"Server: Not punching: Node not found."
2867 <<" Adding block to emerge queue."
2869 m_emerge->enqueueBlockEmerge(peer_id, getNodeBlockPos(p_above), false);
2871 if(n.getContent() != CONTENT_IGNORE)
2872 m_script->node_on_punch(p_under, n, playersao);
2874 playersao->noCheatDigStart(p_under);
2876 else if(pointed.type == POINTEDTHING_OBJECT)
2878 // Skip if object has been removed
2879 if(pointed_object->m_removed)
2882 actionstream<<player->getName()<<" punches object "
2883 <<pointed.object_id<<": "
2884 <<pointed_object->getDescription()<<std::endl;
2886 ItemStack punchitem = playersao->getWieldedItem();
2887 ToolCapabilities toolcap =
2888 punchitem.getToolCapabilities(m_itemdef);
2889 v3f dir = (pointed_object->getBasePosition() -
2890 (player->getPosition() + player->getEyeOffset())
2892 float time_from_last_punch =
2893 playersao->resetTimeFromLastPunch();
2894 pointed_object->punch(dir, &toolcap, playersao,
2895 time_from_last_punch);
2903 else if(action == 1)
2908 2: Digging completed
2910 else if(action == 2)
2912 // Only digging of nodes
2913 if(pointed.type == POINTEDTHING_NODE)
2915 MapNode n(CONTENT_IGNORE);
2918 n = m_env->getMap().getNode(p_under);
2920 catch(InvalidPositionException &e)
2922 infostream<<"Server: Not finishing digging: Node not found."
2923 <<" Adding block to emerge queue."
2925 m_emerge->enqueueBlockEmerge(peer_id, getNodeBlockPos(p_above), false);
2928 /* Cheat prevention */
2929 bool is_valid_dig = true;
2930 if(!isSingleplayer() && !g_settings->getBool("disable_anticheat"))
2932 v3s16 nocheat_p = playersao->getNoCheatDigPos();
2933 float nocheat_t = playersao->getNoCheatDigTime();
2934 playersao->noCheatDigEnd();
2935 // If player didn't start digging this, ignore dig
2936 if(nocheat_p != p_under){
2937 infostream<<"Server: NoCheat: "<<player->getName()
2938 <<" started digging "
2939 <<PP(nocheat_p)<<" and completed digging "
2940 <<PP(p_under)<<"; not digging."<<std::endl;
2941 is_valid_dig = false;
2943 // Get player's wielded item
2944 ItemStack playeritem;
2945 InventoryList *mlist = playersao->getInventory()->getList("main");
2947 playeritem = mlist->getItem(playersao->getWieldIndex());
2948 ToolCapabilities playeritem_toolcap =
2949 playeritem.getToolCapabilities(m_itemdef);
2950 // Get diggability and expected digging time
2951 DigParams params = getDigParams(m_nodedef->get(n).groups,
2952 &playeritem_toolcap);
2953 // If can't dig, try hand
2954 if(!params.diggable){
2955 const ItemDefinition &hand = m_itemdef->get("");
2956 const ToolCapabilities *tp = hand.tool_capabilities;
2958 params = getDigParams(m_nodedef->get(n).groups, tp);
2960 // If can't dig, ignore dig
2961 if(!params.diggable){
2962 infostream<<"Server: NoCheat: "<<player->getName()
2963 <<" completed digging "<<PP(p_under)
2964 <<", which is not diggable with tool. not digging."
2966 is_valid_dig = false;
2968 // Check digging time
2969 // If already invalidated, we don't have to
2971 // Well not our problem then
2973 // Clean and long dig
2974 else if(params.time > 2.0 && nocheat_t * 1.2 > params.time){
2975 // All is good, but grab time from pool; don't care if
2976 // it's actually available
2977 playersao->getDigPool().grab(params.time);
2979 // Short or laggy dig
2980 // Try getting the time from pool
2981 else if(playersao->getDigPool().grab(params.time)){
2986 infostream<<"Server: NoCheat: "<<player->getName()
2987 <<" completed digging "<<PP(p_under)
2988 <<"too fast; not digging."<<std::endl;
2989 is_valid_dig = false;
2993 /* Actually dig node */
2995 if(is_valid_dig && n.getContent() != CONTENT_IGNORE)
2996 m_script->node_on_dig(p_under, n, playersao);
2998 // Send unusual result (that is, node not being removed)
2999 if(m_env->getMap().getNodeNoEx(p_under).getContent() != CONTENT_AIR)
3001 // Re-send block to revert change on client-side
3002 RemoteClient *client = getClient(peer_id);
3003 v3s16 blockpos = getNodeBlockPos(floatToInt(pointed_pos_under, BS));
3004 client->SetBlockNotSent(blockpos);
3010 3: place block or right-click object
3012 else if(action == 3)
3014 ItemStack item = playersao->getWieldedItem();
3016 // Reset build time counter
3017 if(pointed.type == POINTEDTHING_NODE &&
3018 item.getDefinition(m_itemdef).type == ITEM_NODE)
3019 getClient(peer_id)->m_time_from_building = 0.0;
3021 if(pointed.type == POINTEDTHING_OBJECT)
3023 // Right click object
3025 // Skip if object has been removed
3026 if(pointed_object->m_removed)
3029 actionstream<<player->getName()<<" right-clicks object "
3030 <<pointed.object_id<<": "
3031 <<pointed_object->getDescription()<<std::endl;
3034 pointed_object->rightClick(playersao);
3036 else if(m_script->item_OnPlace(
3037 item, playersao, pointed))
3039 // Placement was handled in lua
3041 // Apply returned ItemStack
3042 playersao->setWieldedItem(item);
3045 // If item has node placement prediction, always send the
3046 // blocks to make sure the client knows what exactly happened
3047 if(item.getDefinition(m_itemdef).node_placement_prediction != ""){
3048 RemoteClient *client = getClient(peer_id);
3049 v3s16 blockpos = getNodeBlockPos(floatToInt(pointed_pos_above, BS));
3050 client->SetBlockNotSent(blockpos);
3051 v3s16 blockpos2 = getNodeBlockPos(floatToInt(pointed_pos_under, BS));
3052 if(blockpos2 != blockpos){
3053 client->SetBlockNotSent(blockpos2);
3061 else if(action == 4)
3063 ItemStack item = playersao->getWieldedItem();
3065 actionstream<<player->getName()<<" uses "<<item.name
3066 <<", pointing at "<<pointed.dump()<<std::endl;
3068 if(m_script->item_OnUse(
3069 item, playersao, pointed))
3071 // Apply returned ItemStack
3072 playersao->setWieldedItem(item);
3079 Catch invalid actions
3083 infostream<<"WARNING: Server: Invalid action "
3084 <<action<<std::endl;
3087 else if(command == TOSERVER_REMOVED_SOUNDS)
3089 std::string datastring((char*)&data[2], datasize-2);
3090 std::istringstream is(datastring, std::ios_base::binary);
3092 int num = readU16(is);
3093 for(int k=0; k<num; k++){
3094 s32 id = readS32(is);
3095 std::map<s32, ServerPlayingSound>::iterator i =
3096 m_playing_sounds.find(id);
3097 if(i == m_playing_sounds.end())
3099 ServerPlayingSound &psound = i->second;
3100 psound.clients.erase(peer_id);
3101 if(psound.clients.size() == 0)
3102 m_playing_sounds.erase(i++);
3105 else if(command == TOSERVER_NODEMETA_FIELDS)
3107 std::string datastring((char*)&data[2], datasize-2);
3108 std::istringstream is(datastring, std::ios_base::binary);
3110 v3s16 p = readV3S16(is);
3111 std::string formname = deSerializeString(is);
3112 int num = readU16(is);
3113 std::map<std::string, std::string> fields;
3114 for(int k=0; k<num; k++){
3115 std::string fieldname = deSerializeString(is);
3116 std::string fieldvalue = deSerializeLongString(is);
3117 fields[fieldname] = fieldvalue;
3120 // If something goes wrong, this player is to blame
3121 RollbackScopeActor rollback_scope(m_rollback,
3122 std::string("player:")+player->getName());
3124 // Check the target node for rollback data; leave others unnoticed
3125 RollbackNode rn_old(&m_env->getMap(), p, this);
3127 m_script->node_on_receive_fields(p, formname, fields,playersao);
3129 // Report rollback data
3130 RollbackNode rn_new(&m_env->getMap(), p, this);
3131 if(rollback() && rn_new != rn_old){
3132 RollbackAction action;
3133 action.setSetNode(p, rn_old, rn_new);
3134 rollback()->reportAction(action);
3137 else if(command == TOSERVER_INVENTORY_FIELDS)
3139 std::string datastring((char*)&data[2], datasize-2);
3140 std::istringstream is(datastring, std::ios_base::binary);
3142 std::string formname = deSerializeString(is);
3143 int num = readU16(is);
3144 std::map<std::string, std::string> fields;
3145 for(int k=0; k<num; k++){
3146 std::string fieldname = deSerializeString(is);
3147 std::string fieldvalue = deSerializeLongString(is);
3148 fields[fieldname] = fieldvalue;
3151 m_script->on_playerReceiveFields(playersao, formname, fields);
3155 infostream<<"Server::ProcessData(): Ignoring "
3156 "unknown command "<<command<<std::endl;
3160 catch(SendFailedException &e)
3162 errorstream<<"Server::ProcessData(): SendFailedException: "
3168 void Server::onMapEditEvent(MapEditEvent *event)
3170 //infostream<<"Server::onMapEditEvent()"<<std::endl;
3171 if(m_ignore_map_edit_events)
3173 if(m_ignore_map_edit_events_area.contains(event->getArea()))
3175 MapEditEvent *e = event->clone();
3176 m_unsent_map_edit_queue.push_back(e);
3179 Inventory* Server::getInventory(const InventoryLocation &loc)
3182 case InventoryLocation::UNDEFINED:
3185 case InventoryLocation::CURRENT_PLAYER:
3188 case InventoryLocation::PLAYER:
3190 Player *player = m_env->getPlayer(loc.name.c_str());
3193 PlayerSAO *playersao = player->getPlayerSAO();
3196 return playersao->getInventory();
3199 case InventoryLocation::NODEMETA:
3201 NodeMetadata *meta = m_env->getMap().getNodeMetadata(loc.p);
3204 return meta->getInventory();
3207 case InventoryLocation::DETACHED:
3209 if(m_detached_inventories.count(loc.name) == 0)
3211 return m_detached_inventories[loc.name];
3219 void Server::setInventoryModified(const InventoryLocation &loc)
3222 case InventoryLocation::UNDEFINED:
3225 case InventoryLocation::PLAYER:
3227 Player *player = m_env->getPlayer(loc.name.c_str());
3230 PlayerSAO *playersao = player->getPlayerSAO();
3233 playersao->m_inventory_not_sent = true;
3234 playersao->m_wielded_item_not_sent = true;
3237 case InventoryLocation::NODEMETA:
3239 v3s16 blockpos = getNodeBlockPos(loc.p);
3241 MapBlock *block = m_env->getMap().getBlockNoCreateNoEx(blockpos);
3243 block->raiseModified(MOD_STATE_WRITE_NEEDED);
3245 setBlockNotSent(blockpos);
3248 case InventoryLocation::DETACHED:
3250 sendDetachedInventoryToAll(loc.name);
3258 //std::list<PlayerInfo> Server::getPlayerInfo()
3260 // DSTACK(__FUNCTION_NAME);
3261 // JMutexAutoLock envlock(m_env_mutex);
3262 // JMutexAutoLock conlock(m_con_mutex);
3264 // std::list<PlayerInfo> list;
3266 // std::list<Player*> players = m_env->getPlayers();
3268 // std::list<Player*>::iterator i;
3269 // for(i = players.begin();
3270 // i != players.end(); ++i)
3274 // Player *player = *i;
3277 // // Copy info from connection to info struct
3278 // info.id = player->peer_id;
3279 // info.address = m_con.GetPeerAddress(player->peer_id);
3280 // info.avg_rtt = m_con.GetPeerAvgRTT(player->peer_id);
3282 // catch(con::PeerNotFoundException &e)
3284 // // Set dummy peer info
3286 // info.address = Address(0,0,0,0,0);
3287 // info.avg_rtt = 0.0;
3290 // snprintf(info.name, PLAYERNAME_SIZE, "%s", player->getName());
3291 // info.position = player->getPosition();
3293 // list.push_back(info);
3300 void Server::peerAdded(con::Peer *peer)
3302 DSTACK(__FUNCTION_NAME);
3303 verbosestream<<"Server::peerAdded(): peer->id="
3304 <<peer->id<<std::endl;
3307 c.type = PEER_ADDED;
3308 c.peer_id = peer->id;
3310 m_peer_change_queue.push_back(c);
3313 void Server::deletingPeer(con::Peer *peer, bool timeout)
3315 DSTACK(__FUNCTION_NAME);
3316 verbosestream<<"Server::deletingPeer(): peer->id="
3317 <<peer->id<<", timeout="<<timeout<<std::endl;
3320 c.type = PEER_REMOVED;
3321 c.peer_id = peer->id;
3322 c.timeout = timeout;
3323 m_peer_change_queue.push_back(c);
3330 void Server::SendMovement(con::Connection &con, u16 peer_id)
3332 DSTACK(__FUNCTION_NAME);
3333 std::ostringstream os(std::ios_base::binary);
3335 writeU16(os, TOCLIENT_MOVEMENT);
3336 writeF1000(os, g_settings->getFloat("movement_acceleration_default"));
3337 writeF1000(os, g_settings->getFloat("movement_acceleration_air"));
3338 writeF1000(os, g_settings->getFloat("movement_acceleration_fast"));
3339 writeF1000(os, g_settings->getFloat("movement_speed_walk"));
3340 writeF1000(os, g_settings->getFloat("movement_speed_crouch"));
3341 writeF1000(os, g_settings->getFloat("movement_speed_fast"));
3342 writeF1000(os, g_settings->getFloat("movement_speed_climb"));
3343 writeF1000(os, g_settings->getFloat("movement_speed_jump"));
3344 writeF1000(os, g_settings->getFloat("movement_liquid_fluidity"));
3345 writeF1000(os, g_settings->getFloat("movement_liquid_fluidity_smooth"));
3346 writeF1000(os, g_settings->getFloat("movement_liquid_sink"));
3347 writeF1000(os, g_settings->getFloat("movement_gravity"));
3350 std::string s = os.str();
3351 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3353 con.Send(peer_id, 0, data, true);
3356 void Server::SendHP(con::Connection &con, u16 peer_id, u8 hp)
3358 DSTACK(__FUNCTION_NAME);
3359 std::ostringstream os(std::ios_base::binary);
3361 writeU16(os, TOCLIENT_HP);
3365 std::string s = os.str();
3366 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3368 con.Send(peer_id, 0, data, true);
3371 void Server::SendBreath(con::Connection &con, u16 peer_id, u16 breath)
3373 DSTACK(__FUNCTION_NAME);
3374 std::ostringstream os(std::ios_base::binary);
3376 writeU16(os, TOCLIENT_BREATH);
3377 writeU16(os, breath);
3380 std::string s = os.str();
3381 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3383 con.Send(peer_id, 0, data, true);
3386 void Server::SendAccessDenied(con::Connection &con, u16 peer_id,
3387 const std::wstring &reason)
3389 DSTACK(__FUNCTION_NAME);
3390 std::ostringstream os(std::ios_base::binary);
3392 writeU16(os, TOCLIENT_ACCESS_DENIED);
3393 os<<serializeWideString(reason);
3396 std::string s = os.str();
3397 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3399 con.Send(peer_id, 0, data, true);
3402 void Server::SendDeathscreen(con::Connection &con, u16 peer_id,
3403 bool set_camera_point_target, v3f camera_point_target)
3405 DSTACK(__FUNCTION_NAME);
3406 std::ostringstream os(std::ios_base::binary);
3408 writeU16(os, TOCLIENT_DEATHSCREEN);
3409 writeU8(os, set_camera_point_target);
3410 writeV3F1000(os, camera_point_target);
3413 std::string s = os.str();
3414 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3416 con.Send(peer_id, 0, data, true);
3419 void Server::SendItemDef(con::Connection &con, u16 peer_id,
3420 IItemDefManager *itemdef, u16 protocol_version)
3422 DSTACK(__FUNCTION_NAME);
3423 std::ostringstream os(std::ios_base::binary);
3427 u32 length of the next item
3428 zlib-compressed serialized ItemDefManager
3430 writeU16(os, TOCLIENT_ITEMDEF);
3431 std::ostringstream tmp_os(std::ios::binary);
3432 itemdef->serialize(tmp_os, protocol_version);
3433 std::ostringstream tmp_os2(std::ios::binary);
3434 compressZlib(tmp_os.str(), tmp_os2);
3435 os<<serializeLongString(tmp_os2.str());
3438 std::string s = os.str();
3439 verbosestream<<"Server: Sending item definitions to id("<<peer_id
3440 <<"): size="<<s.size()<<std::endl;
3441 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3443 con.Send(peer_id, 0, data, true);
3446 void Server::SendNodeDef(con::Connection &con, u16 peer_id,
3447 INodeDefManager *nodedef, u16 protocol_version)
3449 DSTACK(__FUNCTION_NAME);
3450 std::ostringstream os(std::ios_base::binary);
3454 u32 length of the next item
3455 zlib-compressed serialized NodeDefManager
3457 writeU16(os, TOCLIENT_NODEDEF);
3458 std::ostringstream tmp_os(std::ios::binary);
3459 nodedef->serialize(tmp_os, protocol_version);
3460 std::ostringstream tmp_os2(std::ios::binary);
3461 compressZlib(tmp_os.str(), tmp_os2);
3462 os<<serializeLongString(tmp_os2.str());
3465 std::string s = os.str();
3466 verbosestream<<"Server: Sending node definitions to id("<<peer_id
3467 <<"): size="<<s.size()<<std::endl;
3468 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3470 con.Send(peer_id, 0, data, true);
3474 Non-static send methods
3477 void Server::SendInventory(u16 peer_id)
3479 DSTACK(__FUNCTION_NAME);
3481 PlayerSAO *playersao = getPlayerSAO(peer_id);
3484 playersao->m_inventory_not_sent = false;
3490 std::ostringstream os;
3491 playersao->getInventory()->serialize(os);
3493 std::string s = os.str();
3495 SharedBuffer<u8> data(s.size()+2);
3496 writeU16(&data[0], TOCLIENT_INVENTORY);
3497 memcpy(&data[2], s.c_str(), s.size());
3500 m_con.Send(peer_id, 0, data, true);
3503 void Server::SendChatMessage(u16 peer_id, const std::wstring &message)
3505 DSTACK(__FUNCTION_NAME);
3507 std::ostringstream os(std::ios_base::binary);
3511 writeU16(buf, TOCLIENT_CHAT_MESSAGE);
3512 os.write((char*)buf, 2);
3515 writeU16(buf, message.size());
3516 os.write((char*)buf, 2);
3519 for(u32 i=0; i<message.size(); i++)
3523 os.write((char*)buf, 2);
3527 std::string s = os.str();
3528 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3530 m_con.Send(peer_id, 0, data, true);
3533 void Server::SendShowFormspecMessage(u16 peer_id, const std::string formspec,
3534 const std::string formname)
3536 DSTACK(__FUNCTION_NAME);
3538 std::ostringstream os(std::ios_base::binary);
3542 writeU16(buf, TOCLIENT_SHOW_FORMSPEC);
3543 os.write((char*)buf, 2);
3544 os<<serializeLongString(formspec);
3545 os<<serializeString(formname);
3548 std::string s = os.str();
3549 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3551 m_con.Send(peer_id, 0, data, true);
3554 // Spawns a particle on peer with peer_id
3555 void Server::SendSpawnParticle(u16 peer_id, v3f pos, v3f velocity, v3f acceleration,
3556 float expirationtime, float size, bool collisiondetection,
3557 std::string texture)
3559 DSTACK(__FUNCTION_NAME);
3561 std::ostringstream os(std::ios_base::binary);
3562 writeU16(os, TOCLIENT_SPAWN_PARTICLE);
3563 writeV3F1000(os, pos);
3564 writeV3F1000(os, velocity);
3565 writeV3F1000(os, acceleration);
3566 writeF1000(os, expirationtime);
3567 writeF1000(os, size);
3568 writeU8(os, collisiondetection);
3569 os<<serializeLongString(texture);
3572 std::string s = os.str();
3573 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3575 m_con.Send(peer_id, 0, data, true);
3578 // Spawns a particle on all peers
3579 void Server::SendSpawnParticleAll(v3f pos, v3f velocity, v3f acceleration,
3580 float expirationtime, float size, bool collisiondetection,
3581 std::string texture)
3583 for(std::map<u16, RemoteClient*>::iterator
3584 i = m_clients.begin();
3585 i != m_clients.end(); i++)
3587 // Get client and check that it is valid
3588 RemoteClient *client = i->second;
3589 assert(client->peer_id == i->first);
3590 if(client->serialization_version == SER_FMT_VER_INVALID)
3593 SendSpawnParticle(client->peer_id, pos, velocity, acceleration,
3594 expirationtime, size, collisiondetection, texture);
3598 // Adds a ParticleSpawner on peer with peer_id
3599 void Server::SendAddParticleSpawner(u16 peer_id, u16 amount, float spawntime, v3f minpos, v3f maxpos,
3600 v3f minvel, v3f maxvel, v3f minacc, v3f maxacc, float minexptime, float maxexptime,
3601 float minsize, float maxsize, bool collisiondetection, std::string texture, u32 id)
3603 DSTACK(__FUNCTION_NAME);
3605 std::ostringstream os(std::ios_base::binary);
3606 writeU16(os, TOCLIENT_ADD_PARTICLESPAWNER);
3608 writeU16(os, amount);
3609 writeF1000(os, spawntime);
3610 writeV3F1000(os, minpos);
3611 writeV3F1000(os, maxpos);
3612 writeV3F1000(os, minvel);
3613 writeV3F1000(os, maxvel);
3614 writeV3F1000(os, minacc);
3615 writeV3F1000(os, maxacc);
3616 writeF1000(os, minexptime);
3617 writeF1000(os, maxexptime);
3618 writeF1000(os, minsize);
3619 writeF1000(os, maxsize);
3620 writeU8(os, collisiondetection);
3621 os<<serializeLongString(texture);
3625 std::string s = os.str();
3626 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3628 m_con.Send(peer_id, 0, data, true);
3631 // Adds a ParticleSpawner on all peers
3632 void Server::SendAddParticleSpawnerAll(u16 amount, float spawntime, v3f minpos, v3f maxpos,
3633 v3f minvel, v3f maxvel, v3f minacc, v3f maxacc, float minexptime, float maxexptime,
3634 float minsize, float maxsize, bool collisiondetection, std::string texture, u32 id)
3636 for(std::map<u16, RemoteClient*>::iterator
3637 i = m_clients.begin();
3638 i != m_clients.end(); i++)
3640 // Get client and check that it is valid
3641 RemoteClient *client = i->second;
3642 assert(client->peer_id == i->first);
3643 if(client->serialization_version == SER_FMT_VER_INVALID)
3646 SendAddParticleSpawner(client->peer_id, amount, spawntime,
3647 minpos, maxpos, minvel, maxvel, minacc, maxacc,
3648 minexptime, maxexptime, minsize, maxsize, collisiondetection, texture, id);
3652 void Server::SendDeleteParticleSpawner(u16 peer_id, u32 id)
3654 DSTACK(__FUNCTION_NAME);
3656 std::ostringstream os(std::ios_base::binary);
3657 writeU16(os, TOCLIENT_DELETE_PARTICLESPAWNER);
3662 std::string s = os.str();
3663 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3665 m_con.Send(peer_id, 0, data, true);
3668 void Server::SendDeleteParticleSpawnerAll(u32 id)
3670 for(std::map<u16, RemoteClient*>::iterator
3671 i = m_clients.begin();
3672 i != m_clients.end(); i++)
3674 // Get client and check that it is valid
3675 RemoteClient *client = i->second;
3676 assert(client->peer_id == i->first);
3677 if(client->serialization_version == SER_FMT_VER_INVALID)
3680 SendDeleteParticleSpawner(client->peer_id, id);
3684 void Server::SendHUDAdd(u16 peer_id, u32 id, HudElement *form)
3686 std::ostringstream os(std::ios_base::binary);
3689 writeU16(os, TOCLIENT_HUDADD);
3691 writeU8(os, (u8)form->type);
3692 writeV2F1000(os, form->pos);
3693 os << serializeString(form->name);
3694 writeV2F1000(os, form->scale);
3695 os << serializeString(form->text);
3696 writeU32(os, form->number);
3697 writeU32(os, form->item);
3698 writeU32(os, form->dir);
3699 writeV2F1000(os, form->align);
3700 writeV2F1000(os, form->offset);
3703 std::string s = os.str();
3704 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3706 m_con.Send(peer_id, 0, data, true);
3709 void Server::SendHUDRemove(u16 peer_id, u32 id)
3711 std::ostringstream os(std::ios_base::binary);
3714 writeU16(os, TOCLIENT_HUDRM);
3718 std::string s = os.str();
3719 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3721 m_con.Send(peer_id, 0, data, true);
3724 void Server::SendHUDChange(u16 peer_id, u32 id, HudElementStat stat, void *value)
3726 std::ostringstream os(std::ios_base::binary);
3729 writeU16(os, TOCLIENT_HUDCHANGE);
3731 writeU8(os, (u8)stat);
3734 case HUD_STAT_SCALE:
3735 case HUD_STAT_ALIGN:
3736 case HUD_STAT_OFFSET:
3737 writeV2F1000(os, *(v2f *)value);
3741 os << serializeString(*(std::string *)value);
3743 case HUD_STAT_NUMBER:
3747 writeU32(os, *(u32 *)value);
3752 std::string s = os.str();
3753 SharedBuffer<u8> data((u8 *)s.c_str(), s.size());
3755 m_con.Send(peer_id, 0, data, true);
3758 void Server::SendHUDSetFlags(u16 peer_id, u32 flags, u32 mask)
3760 std::ostringstream os(std::ios_base::binary);
3763 writeU16(os, TOCLIENT_HUD_SET_FLAGS);
3764 writeU32(os, flags);
3768 std::string s = os.str();
3769 SharedBuffer<u8> data((u8 *)s.c_str(), s.size());
3771 m_con.Send(peer_id, 0, data, true);
3774 void Server::SendHUDSetParam(u16 peer_id, u16 param, const std::string &value)
3776 std::ostringstream os(std::ios_base::binary);
3779 writeU16(os, TOCLIENT_HUD_SET_PARAM);
3780 writeU16(os, param);
3781 os<<serializeString(value);
3784 std::string s = os.str();
3785 SharedBuffer<u8> data((u8 *)s.c_str(), s.size());
3787 m_con.Send(peer_id, 0, data, true);
3790 void Server::BroadcastChatMessage(const std::wstring &message)
3792 for(std::map<u16, RemoteClient*>::iterator
3793 i = m_clients.begin();
3794 i != m_clients.end(); ++i)
3796 // Get client and check that it is valid
3797 RemoteClient *client = i->second;
3798 assert(client->peer_id == i->first);
3799 if(client->serialization_version == SER_FMT_VER_INVALID)
3802 SendChatMessage(client->peer_id, message);
3806 void Server::SendPlayerHP(u16 peer_id)
3808 DSTACK(__FUNCTION_NAME);
3809 PlayerSAO *playersao = getPlayerSAO(peer_id);
3811 playersao->m_hp_not_sent = false;
3812 SendHP(m_con, peer_id, playersao->getHP());
3815 void Server::SendPlayerBreath(u16 peer_id)
3817 DSTACK(__FUNCTION_NAME);
3818 PlayerSAO *playersao = getPlayerSAO(peer_id);
3820 playersao->m_breath_not_sent = false;
3821 SendBreath(m_con, peer_id, playersao->getBreath());
3824 void Server::SendMovePlayer(u16 peer_id)
3826 DSTACK(__FUNCTION_NAME);
3827 Player *player = m_env->getPlayer(peer_id);
3830 std::ostringstream os(std::ios_base::binary);
3831 writeU16(os, TOCLIENT_MOVE_PLAYER);
3832 writeV3F1000(os, player->getPosition());
3833 writeF1000(os, player->getPitch());
3834 writeF1000(os, player->getYaw());
3837 v3f pos = player->getPosition();
3838 f32 pitch = player->getPitch();
3839 f32 yaw = player->getYaw();
3840 verbosestream<<"Server: Sending TOCLIENT_MOVE_PLAYER"
3841 <<" pos=("<<pos.X<<","<<pos.Y<<","<<pos.Z<<")"
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::SendPlayerPrivileges(u16 peer_id)
3856 Player *player = m_env->getPlayer(peer_id);
3858 if(player->peer_id == PEER_ID_INEXISTENT)
3861 std::set<std::string> privs;
3862 m_script->getAuth(player->getName(), NULL, &privs);
3864 std::ostringstream os(std::ios_base::binary);
3865 writeU16(os, TOCLIENT_PRIVILEGES);
3866 writeU16(os, privs.size());
3867 for(std::set<std::string>::const_iterator i = privs.begin();
3868 i != privs.end(); i++){
3869 os<<serializeString(*i);
3873 std::string s = os.str();
3874 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3876 m_con.Send(peer_id, 0, data, true);
3879 void Server::SendPlayerInventoryFormspec(u16 peer_id)
3881 Player *player = m_env->getPlayer(peer_id);
3883 if(player->peer_id == PEER_ID_INEXISTENT)
3886 std::ostringstream os(std::ios_base::binary);
3887 writeU16(os, TOCLIENT_INVENTORY_FORMSPEC);
3888 os<<serializeLongString(player->inventory_formspec);
3891 std::string s = os.str();
3892 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3894 m_con.Send(peer_id, 0, data, true);
3897 s32 Server::playSound(const SimpleSoundSpec &spec,
3898 const ServerSoundParams ¶ms)
3900 // Find out initial position of sound
3901 bool pos_exists = false;
3902 v3f pos = params.getPos(m_env, &pos_exists);
3903 // If position is not found while it should be, cancel sound
3904 if(pos_exists != (params.type != ServerSoundParams::SSP_LOCAL))
3906 // Filter destination clients
3907 std::set<RemoteClient*> dst_clients;
3908 if(params.to_player != "")
3910 Player *player = m_env->getPlayer(params.to_player.c_str());
3912 infostream<<"Server::playSound: Player \""<<params.to_player
3913 <<"\" not found"<<std::endl;
3916 if(player->peer_id == PEER_ID_INEXISTENT){
3917 infostream<<"Server::playSound: Player \""<<params.to_player
3918 <<"\" not connected"<<std::endl;
3921 RemoteClient *client = getClient(player->peer_id);
3922 dst_clients.insert(client);
3926 for(std::map<u16, RemoteClient*>::iterator
3927 i = m_clients.begin(); i != m_clients.end(); ++i)
3929 RemoteClient *client = i->second;
3930 Player *player = m_env->getPlayer(client->peer_id);
3934 if(player->getPosition().getDistanceFrom(pos) >
3935 params.max_hear_distance)
3938 dst_clients.insert(client);
3941 if(dst_clients.size() == 0)
3944 s32 id = m_next_sound_id++;
3945 // The sound will exist as a reference in m_playing_sounds
3946 m_playing_sounds[id] = ServerPlayingSound();
3947 ServerPlayingSound &psound = m_playing_sounds[id];
3948 psound.params = params;
3949 for(std::set<RemoteClient*>::iterator i = dst_clients.begin();
3950 i != dst_clients.end(); i++)
3951 psound.clients.insert((*i)->peer_id);
3953 std::ostringstream os(std::ios_base::binary);
3954 writeU16(os, TOCLIENT_PLAY_SOUND);
3956 os<<serializeString(spec.name);
3957 writeF1000(os, spec.gain * params.gain);
3958 writeU8(os, params.type);
3959 writeV3F1000(os, pos);
3960 writeU16(os, params.object);
3961 writeU8(os, params.loop);
3963 std::string s = os.str();
3964 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3966 for(std::set<RemoteClient*>::iterator i = dst_clients.begin();
3967 i != dst_clients.end(); i++){
3969 m_con.Send((*i)->peer_id, 0, data, true);
3973 void Server::stopSound(s32 handle)
3975 // Get sound reference
3976 std::map<s32, ServerPlayingSound>::iterator i =
3977 m_playing_sounds.find(handle);
3978 if(i == m_playing_sounds.end())
3980 ServerPlayingSound &psound = i->second;
3982 std::ostringstream os(std::ios_base::binary);
3983 writeU16(os, TOCLIENT_STOP_SOUND);
3984 writeS32(os, handle);
3986 std::string s = os.str();
3987 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3989 for(std::set<u16>::iterator i = psound.clients.begin();
3990 i != psound.clients.end(); i++){
3992 m_con.Send(*i, 0, data, true);
3994 // Remove sound reference
3995 m_playing_sounds.erase(i);
3998 void Server::sendRemoveNode(v3s16 p, u16 ignore_id,
3999 std::list<u16> *far_players, float far_d_nodes)
4001 float maxd = far_d_nodes*BS;
4002 v3f p_f = intToFloat(p, BS);
4006 SharedBuffer<u8> reply(replysize);
4007 writeU16(&reply[0], TOCLIENT_REMOVENODE);
4008 writeS16(&reply[2], p.X);
4009 writeS16(&reply[4], p.Y);
4010 writeS16(&reply[6], p.Z);
4012 for(std::map<u16, RemoteClient*>::iterator
4013 i = m_clients.begin();
4014 i != m_clients.end(); ++i)
4016 // Get client and check that it is valid
4017 RemoteClient *client = i->second;
4018 assert(client->peer_id == i->first);
4019 if(client->serialization_version == SER_FMT_VER_INVALID)
4022 // Don't send if it's the same one
4023 if(client->peer_id == ignore_id)
4029 Player *player = m_env->getPlayer(client->peer_id);
4032 // If player is far away, only set modified blocks not sent
4033 v3f player_pos = player->getPosition();
4034 if(player_pos.getDistanceFrom(p_f) > maxd)
4036 far_players->push_back(client->peer_id);
4043 m_con.Send(client->peer_id, 0, reply, true);
4047 void Server::sendAddNode(v3s16 p, MapNode n, u16 ignore_id,
4048 std::list<u16> *far_players, float far_d_nodes)
4050 float maxd = far_d_nodes*BS;
4051 v3f p_f = intToFloat(p, BS);
4053 for(std::map<u16, RemoteClient*>::iterator
4054 i = m_clients.begin();
4055 i != m_clients.end(); ++i)
4057 // Get client and check that it is valid
4058 RemoteClient *client = i->second;
4059 assert(client->peer_id == i->first);
4060 if(client->serialization_version == SER_FMT_VER_INVALID)
4063 // Don't send if it's the same one
4064 if(client->peer_id == ignore_id)
4070 Player *player = m_env->getPlayer(client->peer_id);
4073 // If player is far away, only set modified blocks not sent
4074 v3f player_pos = player->getPosition();
4075 if(player_pos.getDistanceFrom(p_f) > maxd)
4077 far_players->push_back(client->peer_id);
4084 u32 replysize = 8 + MapNode::serializedLength(client->serialization_version);
4085 SharedBuffer<u8> reply(replysize);
4086 writeU16(&reply[0], TOCLIENT_ADDNODE);
4087 writeS16(&reply[2], p.X);
4088 writeS16(&reply[4], p.Y);
4089 writeS16(&reply[6], p.Z);
4090 n.serialize(&reply[8], client->serialization_version);
4093 m_con.Send(client->peer_id, 0, reply, true);
4097 void Server::setBlockNotSent(v3s16 p)
4099 for(std::map<u16, RemoteClient*>::iterator
4100 i = m_clients.begin();
4101 i != m_clients.end(); ++i)
4103 RemoteClient *client = i->second;
4104 client->SetBlockNotSent(p);
4108 void Server::SendBlockNoLock(u16 peer_id, MapBlock *block, u8 ver, u16 net_proto_version)
4110 DSTACK(__FUNCTION_NAME);
4112 v3s16 p = block->getPos();
4116 bool completely_air = true;
4117 for(s16 z0=0; z0<MAP_BLOCKSIZE; z0++)
4118 for(s16 x0=0; x0<MAP_BLOCKSIZE; x0++)
4119 for(s16 y0=0; y0<MAP_BLOCKSIZE; y0++)
4121 if(block->getNodeNoEx(v3s16(x0,y0,z0)).d != CONTENT_AIR)
4123 completely_air = false;
4124 x0 = y0 = z0 = MAP_BLOCKSIZE; // Break out
4129 infostream<<"Server: Sending block ("<<p.X<<","<<p.Y<<","<<p.Z<<"): ";
4131 infostream<<"[completely air] ";
4132 infostream<<std::endl;
4136 Create a packet with the block in the right format
4139 std::ostringstream os(std::ios_base::binary);
4140 block->serialize(os, ver, false);
4141 block->serializeNetworkSpecific(os, net_proto_version);
4142 std::string s = os.str();
4143 SharedBuffer<u8> blockdata((u8*)s.c_str(), s.size());
4145 u32 replysize = 8 + blockdata.getSize();
4146 SharedBuffer<u8> reply(replysize);
4147 writeU16(&reply[0], TOCLIENT_BLOCKDATA);
4148 writeS16(&reply[2], p.X);
4149 writeS16(&reply[4], p.Y);
4150 writeS16(&reply[6], p.Z);
4151 memcpy(&reply[8], *blockdata, blockdata.getSize());
4153 /*infostream<<"Server: Sending block ("<<p.X<<","<<p.Y<<","<<p.Z<<")"
4154 <<": \tpacket size: "<<replysize<<std::endl;*/
4159 m_con.Send(peer_id, 1, reply, true);
4162 void Server::SendBlocks(float dtime)
4164 DSTACK(__FUNCTION_NAME);
4166 JMutexAutoLock envlock(m_env_mutex);
4167 JMutexAutoLock conlock(m_con_mutex);
4169 ScopeProfiler sp(g_profiler, "Server: sel and send blocks to clients");
4171 std::vector<PrioritySortedBlockTransfer> queue;
4173 s32 total_sending = 0;
4176 ScopeProfiler sp(g_profiler, "Server: selecting blocks for sending");
4178 for(std::map<u16, RemoteClient*>::iterator
4179 i = m_clients.begin();
4180 i != m_clients.end(); ++i)
4182 RemoteClient *client = i->second;
4183 assert(client->peer_id == i->first);
4185 // If definitions and textures have not been sent, don't
4186 // send MapBlocks either
4187 if(!client->definitions_sent)
4190 total_sending += client->SendingCount();
4192 if(client->serialization_version == SER_FMT_VER_INVALID)
4195 client->GetNextBlocks(this, dtime, queue);
4200 // Lowest priority number comes first.
4201 // Lowest is most important.
4202 std::sort(queue.begin(), queue.end());
4204 for(u32 i=0; i<queue.size(); i++)
4206 //TODO: Calculate limit dynamically
4207 if(total_sending >= g_settings->getS32
4208 ("max_simultaneous_block_sends_server_total"))
4211 PrioritySortedBlockTransfer q = queue[i];
4213 MapBlock *block = NULL;
4216 block = m_env->getMap().getBlockNoCreate(q.pos);
4218 catch(InvalidPositionException &e)
4223 RemoteClient *client = getClient(q.peer_id);
4225 SendBlockNoLock(q.peer_id, block, client->serialization_version, client->net_proto_version);
4227 client->SentBlock(q.pos);
4233 void Server::fillMediaCache()
4235 DSTACK(__FUNCTION_NAME);
4237 infostream<<"Server: Calculating media file checksums"<<std::endl;
4239 // Collect all media file paths
4240 std::list<std::string> paths;
4241 for(std::vector<ModSpec>::iterator i = m_mods.begin();
4242 i != m_mods.end(); i++){
4243 const ModSpec &mod = *i;
4244 paths.push_back(mod.path + DIR_DELIM + "textures");
4245 paths.push_back(mod.path + DIR_DELIM + "sounds");
4246 paths.push_back(mod.path + DIR_DELIM + "media");
4247 paths.push_back(mod.path + DIR_DELIM + "models");
4249 std::string path_all = "textures";
4250 paths.push_back(path_all + DIR_DELIM + "all");
4252 // Collect media file information from paths into cache
4253 for(std::list<std::string>::iterator i = paths.begin();
4254 i != paths.end(); i++)
4256 std::string mediapath = *i;
4257 std::vector<fs::DirListNode> dirlist = fs::GetDirListing(mediapath);
4258 for(u32 j=0; j<dirlist.size(); j++){
4259 if(dirlist[j].dir) // Ignode dirs
4261 std::string filename = dirlist[j].name;
4262 // If name contains illegal characters, ignore the file
4263 if(!string_allowed(filename, TEXTURENAME_ALLOWED_CHARS)){
4264 infostream<<"Server: ignoring illegal file name: \""
4265 <<filename<<"\""<<std::endl;
4268 // If name is not in a supported format, ignore it
4269 const char *supported_ext[] = {
4270 ".png", ".jpg", ".bmp", ".tga",
4271 ".pcx", ".ppm", ".psd", ".wal", ".rgb",
4273 ".x", ".b3d", ".md2", ".obj",
4276 if(removeStringEnd(filename, supported_ext) == ""){
4277 infostream<<"Server: ignoring unsupported file extension: \""
4278 <<filename<<"\""<<std::endl;
4281 // Ok, attempt to load the file and add to cache
4282 std::string filepath = mediapath + DIR_DELIM + filename;
4284 std::ifstream fis(filepath.c_str(), std::ios_base::binary);
4285 if(fis.good() == false){
4286 errorstream<<"Server::fillMediaCache(): Could not open \""
4287 <<filename<<"\" for reading"<<std::endl;
4290 std::ostringstream tmp_os(std::ios_base::binary);
4294 fis.read(buf, 1024);
4295 std::streamsize len = fis.gcount();
4296 tmp_os.write(buf, len);
4305 errorstream<<"Server::fillMediaCache(): Failed to read \""
4306 <<filename<<"\""<<std::endl;
4309 if(tmp_os.str().length() == 0){
4310 errorstream<<"Server::fillMediaCache(): Empty file \""
4311 <<filepath<<"\""<<std::endl;
4316 sha1.addBytes(tmp_os.str().c_str(), tmp_os.str().length());
4318 unsigned char *digest = sha1.getDigest();
4319 std::string sha1_base64 = base64_encode(digest, 20);
4320 std::string sha1_hex = hex_encode((char*)digest, 20);
4324 this->m_media[filename] = MediaInfo(filepath, sha1_base64);
4325 verbosestream<<"Server: "<<sha1_hex<<" is "<<filename<<std::endl;
4330 struct SendableMediaAnnouncement
4333 std::string sha1_digest;
4335 SendableMediaAnnouncement(const std::string name_="",
4336 const std::string sha1_digest_=""):
4338 sha1_digest(sha1_digest_)
4342 void Server::sendMediaAnnouncement(u16 peer_id)
4344 DSTACK(__FUNCTION_NAME);
4346 verbosestream<<"Server: Announcing files to id("<<peer_id<<")"
4349 std::list<SendableMediaAnnouncement> file_announcements;
4351 for(std::map<std::string, MediaInfo>::iterator i = m_media.begin();
4352 i != m_media.end(); i++){
4354 file_announcements.push_back(
4355 SendableMediaAnnouncement(i->first, i->second.sha1_digest));
4359 std::ostringstream os(std::ios_base::binary);
4367 u16 length of sha1_digest
4372 writeU16(os, TOCLIENT_ANNOUNCE_MEDIA);
4373 writeU16(os, file_announcements.size());
4375 for(std::list<SendableMediaAnnouncement>::iterator
4376 j = file_announcements.begin();
4377 j != file_announcements.end(); ++j){
4378 os<<serializeString(j->name);
4379 os<<serializeString(j->sha1_digest);
4381 os<<serializeString(g_settings->get("remote_media"));
4384 std::string s = os.str();
4385 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
4388 m_con.Send(peer_id, 0, data, true);
4391 struct SendableMedia
4397 SendableMedia(const std::string &name_="", const std::string path_="",
4398 const std::string &data_=""):
4405 void Server::sendRequestedMedia(u16 peer_id,
4406 const std::list<MediaRequest> &tosend)
4408 DSTACK(__FUNCTION_NAME);
4410 verbosestream<<"Server::sendRequestedMedia(): "
4411 <<"Sending files to client"<<std::endl;
4415 // Put 5kB in one bunch (this is not accurate)
4416 u32 bytes_per_bunch = 5000;
4418 std::vector< std::list<SendableMedia> > file_bunches;
4419 file_bunches.push_back(std::list<SendableMedia>());
4421 u32 file_size_bunch_total = 0;
4423 for(std::list<MediaRequest>::const_iterator i = tosend.begin();
4424 i != tosend.end(); ++i)
4426 if(m_media.find(i->name) == m_media.end()){
4427 errorstream<<"Server::sendRequestedMedia(): Client asked for "
4428 <<"unknown file \""<<(i->name)<<"\""<<std::endl;
4432 //TODO get path + name
4433 std::string tpath = m_media[(*i).name].path;
4436 std::ifstream fis(tpath.c_str(), std::ios_base::binary);
4437 if(fis.good() == false){
4438 errorstream<<"Server::sendRequestedMedia(): Could not open \""
4439 <<tpath<<"\" for reading"<<std::endl;
4442 std::ostringstream tmp_os(std::ios_base::binary);
4446 fis.read(buf, 1024);
4447 std::streamsize len = fis.gcount();
4448 tmp_os.write(buf, len);
4449 file_size_bunch_total += len;
4458 errorstream<<"Server::sendRequestedMedia(): Failed to read \""
4459 <<(*i).name<<"\""<<std::endl;
4462 /*infostream<<"Server::sendRequestedMedia(): Loaded \""
4463 <<tname<<"\""<<std::endl;*/
4465 file_bunches[file_bunches.size()-1].push_back(
4466 SendableMedia((*i).name, tpath, tmp_os.str()));
4468 // Start next bunch if got enough data
4469 if(file_size_bunch_total >= bytes_per_bunch){
4470 file_bunches.push_back(std::list<SendableMedia>());
4471 file_size_bunch_total = 0;
4476 /* Create and send packets */
4478 u32 num_bunches = file_bunches.size();
4479 for(u32 i=0; i<num_bunches; i++)
4481 std::ostringstream os(std::ios_base::binary);
4485 u16 total number of texture bunches
4486 u16 index of this bunch
4487 u32 number of files in this bunch
4496 writeU16(os, TOCLIENT_MEDIA);
4497 writeU16(os, num_bunches);
4499 writeU32(os, file_bunches[i].size());
4501 for(std::list<SendableMedia>::iterator
4502 j = file_bunches[i].begin();
4503 j != file_bunches[i].end(); ++j){
4504 os<<serializeString(j->name);
4505 os<<serializeLongString(j->data);
4509 std::string s = os.str();
4510 verbosestream<<"Server::sendRequestedMedia(): bunch "
4511 <<i<<"/"<<num_bunches
4512 <<" files="<<file_bunches[i].size()
4513 <<" size=" <<s.size()<<std::endl;
4514 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
4516 m_con.Send(peer_id, 0, data, true);
4520 void Server::sendDetachedInventory(const std::string &name, u16 peer_id)
4522 if(m_detached_inventories.count(name) == 0){
4523 errorstream<<__FUNCTION_NAME<<": \""<<name<<"\" not found"<<std::endl;
4526 Inventory *inv = m_detached_inventories[name];
4528 std::ostringstream os(std::ios_base::binary);
4529 writeU16(os, TOCLIENT_DETACHED_INVENTORY);
4530 os<<serializeString(name);
4534 std::string s = os.str();
4535 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
4537 m_con.Send(peer_id, 0, data, true);
4540 void Server::sendDetachedInventoryToAll(const std::string &name)
4542 DSTACK(__FUNCTION_NAME);
4544 for(std::map<u16, RemoteClient*>::iterator
4545 i = m_clients.begin();
4546 i != m_clients.end(); ++i){
4547 RemoteClient *client = i->second;
4548 sendDetachedInventory(name, client->peer_id);
4552 void Server::sendDetachedInventories(u16 peer_id)
4554 DSTACK(__FUNCTION_NAME);
4556 for(std::map<std::string, Inventory*>::iterator
4557 i = m_detached_inventories.begin();
4558 i != m_detached_inventories.end(); i++){
4559 const std::string &name = i->first;
4560 //Inventory *inv = i->second;
4561 sendDetachedInventory(name, peer_id);
4569 void Server::DiePlayer(u16 peer_id)
4571 DSTACK(__FUNCTION_NAME);
4573 PlayerSAO *playersao = getPlayerSAO(peer_id);
4576 infostream<<"Server::DiePlayer(): Player "
4577 <<playersao->getPlayer()->getName()
4578 <<" dies"<<std::endl;
4580 playersao->setHP(0);
4582 // Trigger scripted stuff
4583 m_script->on_dieplayer(playersao);
4585 SendPlayerHP(peer_id);
4586 SendDeathscreen(m_con, peer_id, false, v3f(0,0,0));
4589 void Server::RespawnPlayer(u16 peer_id)
4591 DSTACK(__FUNCTION_NAME);
4593 PlayerSAO *playersao = getPlayerSAO(peer_id);
4596 infostream<<"Server::RespawnPlayer(): Player "
4597 <<playersao->getPlayer()->getName()
4598 <<" respawns"<<std::endl;
4600 playersao->setHP(PLAYER_MAX_HP);
4602 bool repositioned = m_script->on_respawnplayer(playersao);
4604 v3f pos = findSpawnPos(m_env->getServerMap());
4605 playersao->setPos(pos);
4609 void Server::UpdateCrafting(u16 peer_id)
4611 DSTACK(__FUNCTION_NAME);
4613 Player* player = m_env->getPlayer(peer_id);
4616 // Get a preview for crafting
4618 getCraftingResult(&player->inventory, preview, false, this);
4620 // Put the new preview in
4621 InventoryList *plist = player->inventory.getList("craftpreview");
4623 assert(plist->getSize() >= 1);
4624 plist->changeItem(0, preview);
4627 RemoteClient* Server::getClient(u16 peer_id)
4629 DSTACK(__FUNCTION_NAME);
4630 //JMutexAutoLock lock(m_con_mutex);
4631 std::map<u16, RemoteClient*>::iterator n;
4632 n = m_clients.find(peer_id);
4633 // A client should exist for all peers
4634 assert(n != m_clients.end());
4638 std::wstring Server::getStatusString()
4640 std::wostringstream os(std::ios_base::binary);
4643 os<<L"version="<<narrow_to_wide(VERSION_STRING);
4645 os<<L", uptime="<<m_uptime.get();
4647 os<<L", max_lag="<<m_env->getMaxLagEstimate();
4648 // Information about clients
4649 std::map<u16, RemoteClient*>::iterator i;
4652 for(i = m_clients.begin(), first = true;
4653 i != m_clients.end(); ++i)
4655 // Get client and check that it is valid
4656 RemoteClient *client = i->second;
4657 assert(client->peer_id == i->first);
4658 if(client->serialization_version == SER_FMT_VER_INVALID)
4661 Player *player = m_env->getPlayer(client->peer_id);
4662 // Get name of player
4663 std::wstring name = L"unknown";
4665 name = narrow_to_wide(player->getName());
4666 // Add name to information string
4674 if(((ServerMap*)(&m_env->getMap()))->isSavingEnabled() == false)
4675 os<<std::endl<<L"# Server: "<<" WARNING: Map saving is disabled.";
4676 if(g_settings->get("motd") != "")
4677 os<<std::endl<<L"# Server: "<<narrow_to_wide(g_settings->get("motd"));
4681 std::set<std::string> Server::getPlayerEffectivePrivs(const std::string &name)
4683 std::set<std::string> privs;
4684 m_script->getAuth(name, NULL, &privs);
4688 bool Server::checkPriv(const std::string &name, const std::string &priv)
4690 std::set<std::string> privs = getPlayerEffectivePrivs(name);
4691 return (privs.count(priv) != 0);
4694 void Server::reportPrivsModified(const std::string &name)
4697 for(std::map<u16, RemoteClient*>::iterator
4698 i = m_clients.begin();
4699 i != m_clients.end(); ++i){
4700 RemoteClient *client = i->second;
4701 Player *player = m_env->getPlayer(client->peer_id);
4702 reportPrivsModified(player->getName());
4705 Player *player = m_env->getPlayer(name.c_str());
4708 SendPlayerPrivileges(player->peer_id);
4709 PlayerSAO *sao = player->getPlayerSAO();
4712 sao->updatePrivileges(
4713 getPlayerEffectivePrivs(name),
4718 void Server::reportInventoryFormspecModified(const std::string &name)
4720 Player *player = m_env->getPlayer(name.c_str());
4723 SendPlayerInventoryFormspec(player->peer_id);
4726 // Saves g_settings to configpath given at initialization
4727 void Server::saveConfig()
4729 if(m_path_config != "")
4730 g_settings->updateConfigFile(m_path_config.c_str());
4733 void Server::notifyPlayer(const char *name, const std::wstring msg, const bool prepend = true)
4735 Player *player = m_env->getPlayer(name);
4739 SendChatMessage(player->peer_id, std::wstring(L"Server -!- ")+msg);
4741 SendChatMessage(player->peer_id, msg);
4744 bool Server::showFormspec(const char *playername, const std::string &formspec, const std::string &formname)
4746 Player *player = m_env->getPlayer(playername);
4750 infostream<<"showFormspec: couldn't find player:"<<playername<<std::endl;
4754 SendShowFormspecMessage(player->peer_id, formspec, formname);
4758 u32 Server::hudAdd(Player *player, HudElement *form) {
4762 u32 id = hud_get_free_id(player);
4763 if (id < player->hud.size())
4764 player->hud[id] = form;
4766 player->hud.push_back(form);
4768 SendHUDAdd(player->peer_id, id, form);
4772 bool Server::hudRemove(Player *player, u32 id) {
4773 if (!player || id >= player->hud.size() || !player->hud[id])
4776 delete player->hud[id];
4777 player->hud[id] = NULL;
4779 SendHUDRemove(player->peer_id, id);
4783 bool Server::hudChange(Player *player, u32 id, HudElementStat stat, void *data) {
4787 SendHUDChange(player->peer_id, id, stat, data);
4791 bool Server::hudSetFlags(Player *player, u32 flags, u32 mask) {
4795 SendHUDSetFlags(player->peer_id, flags, mask);
4799 bool Server::hudSetHotbarItemcount(Player *player, s32 hotbar_itemcount) {
4802 if (hotbar_itemcount <= 0 || hotbar_itemcount > HUD_HOTBAR_ITEMCOUNT_MAX)
4805 std::ostringstream os(std::ios::binary);
4806 writeS32(os, hotbar_itemcount);
4807 SendHUDSetParam(player->peer_id, HUD_PARAM_HOTBAR_ITEMCOUNT, os.str());
4811 void Server::notifyPlayers(const std::wstring msg)
4813 BroadcastChatMessage(msg);
4816 void Server::spawnParticle(const char *playername, v3f pos,
4817 v3f velocity, v3f acceleration,
4818 float expirationtime, float size, bool
4819 collisiondetection, std::string texture)
4821 Player *player = m_env->getPlayer(playername);
4824 SendSpawnParticle(player->peer_id, pos, velocity, acceleration,
4825 expirationtime, size, collisiondetection, texture);
4828 void Server::spawnParticleAll(v3f pos, v3f velocity, v3f acceleration,
4829 float expirationtime, float size,
4830 bool collisiondetection, std::string texture)
4832 SendSpawnParticleAll(pos, velocity, acceleration,
4833 expirationtime, size, collisiondetection, texture);
4836 u32 Server::addParticleSpawner(const char *playername,
4837 u16 amount, float spawntime,
4838 v3f minpos, v3f maxpos,
4839 v3f minvel, v3f maxvel,
4840 v3f minacc, v3f maxacc,
4841 float minexptime, float maxexptime,
4842 float minsize, float maxsize,
4843 bool collisiondetection, std::string texture)
4845 Player *player = m_env->getPlayer(playername);
4850 for(;;) // look for unused particlespawner id
4853 if (std::find(m_particlespawner_ids.begin(),
4854 m_particlespawner_ids.end(), id)
4855 == m_particlespawner_ids.end())
4857 m_particlespawner_ids.push_back(id);
4862 SendAddParticleSpawner(player->peer_id, amount, spawntime,
4863 minpos, maxpos, minvel, maxvel, minacc, maxacc,
4864 minexptime, maxexptime, minsize, maxsize,
4865 collisiondetection, texture, id);
4870 u32 Server::addParticleSpawnerAll(u16 amount, float spawntime,
4871 v3f minpos, v3f maxpos,
4872 v3f minvel, v3f maxvel,
4873 v3f minacc, v3f maxacc,
4874 float minexptime, float maxexptime,
4875 float minsize, float maxsize,
4876 bool collisiondetection, std::string texture)
4879 for(;;) // look for unused particlespawner id
4882 if (std::find(m_particlespawner_ids.begin(),
4883 m_particlespawner_ids.end(), id)
4884 == m_particlespawner_ids.end())
4886 m_particlespawner_ids.push_back(id);
4891 SendAddParticleSpawnerAll(amount, spawntime,
4892 minpos, maxpos, minvel, maxvel, minacc, maxacc,
4893 minexptime, maxexptime, minsize, maxsize,
4894 collisiondetection, texture, id);
4899 void Server::deleteParticleSpawner(const char *playername, u32 id)
4901 Player *player = m_env->getPlayer(playername);
4905 m_particlespawner_ids.erase(
4906 std::remove(m_particlespawner_ids.begin(),
4907 m_particlespawner_ids.end(), id),
4908 m_particlespawner_ids.end());
4909 SendDeleteParticleSpawner(player->peer_id, id);
4912 void Server::deleteParticleSpawnerAll(u32 id)
4914 m_particlespawner_ids.erase(
4915 std::remove(m_particlespawner_ids.begin(),
4916 m_particlespawner_ids.end(), id),
4917 m_particlespawner_ids.end());
4918 SendDeleteParticleSpawnerAll(id);
4921 void Server::queueBlockEmerge(v3s16 blockpos, bool allow_generate)
4923 m_emerge->enqueueBlockEmerge(PEER_ID_INEXISTENT, blockpos, allow_generate);
4926 Inventory* Server::createDetachedInventory(const std::string &name)
4928 if(m_detached_inventories.count(name) > 0){
4929 infostream<<"Server clearing detached inventory \""<<name<<"\""<<std::endl;
4930 delete m_detached_inventories[name];
4932 infostream<<"Server creating detached inventory \""<<name<<"\""<<std::endl;
4934 Inventory *inv = new Inventory(m_itemdef);
4936 m_detached_inventories[name] = inv;
4937 sendDetachedInventoryToAll(name);
4944 BoolScopeSet(bool *dst, bool val):
4947 m_orig_state = *m_dst;
4952 *m_dst = m_orig_state;
4959 // actions: time-reversed list
4960 // Return value: success/failure
4961 bool Server::rollbackRevertActions(const std::list<RollbackAction> &actions,
4962 std::list<std::string> *log)
4964 infostream<<"Server::rollbackRevertActions(len="<<actions.size()<<")"<<std::endl;
4965 ServerMap *map = (ServerMap*)(&m_env->getMap());
4966 // Disable rollback report sink while reverting
4967 BoolScopeSet rollback_scope_disable(&m_rollback_sink_enabled, false);
4969 // Fail if no actions to handle
4970 if(actions.empty()){
4971 log->push_back("Nothing to do.");
4978 for(std::list<RollbackAction>::const_iterator
4979 i = actions.begin();
4980 i != actions.end(); i++)
4982 const RollbackAction &action = *i;
4984 bool success = action.applyRevert(map, this, this);
4987 std::ostringstream os;
4988 os<<"Revert of step ("<<num_tried<<") "<<action.toString()<<" failed";
4989 infostream<<"Map::rollbackRevertActions(): "<<os.str()<<std::endl;
4991 log->push_back(os.str());
4993 std::ostringstream os;
4994 os<<"Successfully reverted step ("<<num_tried<<") "<<action.toString();
4995 infostream<<"Map::rollbackRevertActions(): "<<os.str()<<std::endl;
4997 log->push_back(os.str());
5001 infostream<<"Map::rollbackRevertActions(): "<<num_failed<<"/"<<num_tried
5002 <<" failed"<<std::endl;
5004 // Call it done if less than half failed
5005 return num_failed <= num_tried/2;
5008 // IGameDef interface
5010 IItemDefManager* Server::getItemDefManager()
5014 INodeDefManager* Server::getNodeDefManager()
5018 ICraftDefManager* Server::getCraftDefManager()
5022 ITextureSource* Server::getTextureSource()
5026 IShaderSource* Server::getShaderSource()
5030 u16 Server::allocateUnknownNodeId(const std::string &name)
5032 return m_nodedef->allocateDummy(name);
5034 ISoundManager* Server::getSoundManager()
5036 return &dummySoundManager;
5038 MtEventManager* Server::getEventManager()
5042 IRollbackReportSink* Server::getRollbackReportSink()
5044 if(!m_enable_rollback_recording)
5046 if(!m_rollback_sink_enabled)
5051 IWritableItemDefManager* Server::getWritableItemDefManager()
5055 IWritableNodeDefManager* Server::getWritableNodeDefManager()
5059 IWritableCraftDefManager* Server::getWritableCraftDefManager()
5064 const ModSpec* Server::getModSpec(const std::string &modname)
5066 for(std::vector<ModSpec>::iterator i = m_mods.begin();
5067 i != m_mods.end(); i++){
5068 const ModSpec &mod = *i;
5069 if(mod.name == modname)
5074 void Server::getModNames(std::list<std::string> &modlist)
5076 for(std::vector<ModSpec>::iterator i = m_mods.begin(); i != m_mods.end(); i++)
5078 modlist.push_back(i->name);
5081 std::string Server::getBuiltinLuaPath()
5083 return porting::path_share + DIR_DELIM + "builtin";
5086 v3f findSpawnPos(ServerMap &map)
5088 //return v3f(50,50,50)*BS;
5093 nodepos = v2s16(0,0);
5098 s16 water_level = map.m_mgparams->water_level;
5100 // Try to find a good place a few times
5101 for(s32 i=0; i<1000; i++)
5104 // We're going to try to throw the player to this position
5105 v2s16 nodepos2d = v2s16(
5106 -range + (myrand() % (range * 2)),
5107 -range + (myrand() % (range * 2)));
5109 // Get ground height at point
5110 s16 groundheight = map.findGroundLevel(nodepos2d);
5111 if (groundheight <= water_level) // Don't go underwater
5113 if (groundheight > water_level + 6) // Don't go to high places
5116 nodepos = v3s16(nodepos2d.X, groundheight, nodepos2d.Y);
5117 bool is_good = false;
5119 for (s32 i = 0; i < 10; i++) {
5120 v3s16 blockpos = getNodeBlockPos(nodepos);
5121 map.emergeBlock(blockpos, true);
5122 content_t c = map.getNodeNoEx(nodepos).getContent();
5123 if (c == CONTENT_AIR || c == CONTENT_IGNORE) {
5125 if (air_count >= 2){
5133 // Found a good place
5134 //infostream<<"Searched through "<<i<<" places."<<std::endl;
5140 return intToFloat(nodepos, BS);
5143 PlayerSAO* Server::emergePlayer(const char *name, u16 peer_id)
5145 RemotePlayer *player = NULL;
5146 bool newplayer = false;
5149 Try to get an existing player
5151 player = static_cast<RemotePlayer*>(m_env->getPlayer(name));
5153 // If player is already connected, cancel
5154 if(player != NULL && player->peer_id != 0)
5156 infostream<<"emergePlayer(): Player already connected"<<std::endl;
5161 If player with the wanted peer_id already exists, cancel.
5163 if(m_env->getPlayer(peer_id) != NULL)
5165 infostream<<"emergePlayer(): Player with wrong name but same"
5166 " peer_id already exists"<<std::endl;
5171 Create a new player if it doesn't exist yet
5176 player = new RemotePlayer(this);
5177 player->updateName(name);
5179 /* Set player position */
5180 infostream<<"Server: Finding spawn place for player \""
5181 <<name<<"\""<<std::endl;
5182 v3f pos = findSpawnPos(m_env->getServerMap());
5183 player->setPosition(pos);
5185 /* Add player to environment */
5186 m_env->addPlayer(player);
5190 Create a new player active object
5192 PlayerSAO *playersao = new PlayerSAO(m_env, player, peer_id,
5193 getPlayerEffectivePrivs(player->getName()),
5196 /* Clean up old HUD elements from previous sessions */
5197 player->hud.clear();
5199 /* Add object to environment */
5200 m_env->addActiveObject(playersao);
5204 m_script->on_newplayer(playersao);
5206 m_script->on_joinplayer(playersao);
5211 void Server::handlePeerChange(PeerChange &c)
5213 JMutexAutoLock envlock(m_env_mutex);
5214 JMutexAutoLock conlock(m_con_mutex);
5216 if(c.type == PEER_ADDED)
5223 std::map<u16, RemoteClient*>::iterator n;
5224 n = m_clients.find(c.peer_id);
5225 // The client shouldn't already exist
5226 assert(n == m_clients.end());
5229 RemoteClient *client = new RemoteClient();
5230 client->peer_id = c.peer_id;
5231 m_clients[client->peer_id] = client;
5234 else if(c.type == PEER_REMOVED)
5241 std::map<u16, RemoteClient*>::iterator n;
5242 n = m_clients.find(c.peer_id);
5243 // The client should exist
5244 assert(n != m_clients.end());
5247 Mark objects to be not known by the client
5249 RemoteClient *client = n->second;
5251 for(std::set<u16>::iterator
5252 i = client->m_known_objects.begin();
5253 i != client->m_known_objects.end(); ++i)
5257 ServerActiveObject* obj = m_env->getActiveObject(id);
5259 if(obj && obj->m_known_by_count > 0)
5260 obj->m_known_by_count--;
5264 Clear references to playing sounds
5266 for(std::map<s32, ServerPlayingSound>::iterator
5267 i = m_playing_sounds.begin();
5268 i != m_playing_sounds.end();)
5270 ServerPlayingSound &psound = i->second;
5271 psound.clients.erase(c.peer_id);
5272 if(psound.clients.size() == 0)
5273 m_playing_sounds.erase(i++);
5278 Player *player = m_env->getPlayer(c.peer_id);
5280 // Collect information about leaving in chat
5281 std::wstring message;
5285 std::wstring name = narrow_to_wide(player->getName());
5288 message += L" left the game.";
5290 message += L" (timed out)";
5294 /* Run scripts and remove from environment */
5298 PlayerSAO *playersao = player->getPlayerSAO();
5301 m_script->on_leaveplayer(playersao);
5303 playersao->disconnected();
5313 std::ostringstream os(std::ios_base::binary);
5314 for(std::map<u16, RemoteClient*>::iterator
5315 i = m_clients.begin();
5316 i != m_clients.end(); ++i)
5318 RemoteClient *client = i->second;
5319 assert(client->peer_id == i->first);
5320 if(client->serialization_version == SER_FMT_VER_INVALID)
5323 Player *player = m_env->getPlayer(client->peer_id);
5326 // Get name of player
5327 os<<player->getName()<<" ";
5330 actionstream<<player->getName()<<" "
5331 <<(c.timeout?"times out.":"leaves game.")
5332 <<" List of players: "
5333 <<os.str()<<std::endl;
5338 delete m_clients[c.peer_id];
5339 m_clients.erase(c.peer_id);
5341 // Send player info to all remaining clients
5342 //SendPlayerInfos();
5344 // Send leave chat message to all remaining clients
5345 if(message.length() != 0)
5346 BroadcastChatMessage(message);
5355 void Server::handlePeerChanges()
5357 while(m_peer_change_queue.size() > 0)
5359 PeerChange c = m_peer_change_queue.pop_front();
5361 verbosestream<<"Server: Handling peer change: "
5362 <<"id="<<c.peer_id<<", timeout="<<c.timeout
5365 handlePeerChange(c);
5369 void dedicated_server_loop(Server &server, bool &kill)
5371 DSTACK(__FUNCTION_NAME);
5373 verbosestream<<"dedicated_server_loop()"<<std::endl;
5375 IntervalLimiter m_profiler_interval;
5379 float steplen = g_settings->getFloat("dedicated_server_step");
5380 // This is kind of a hack but can be done like this
5381 // because server.step() is very light
5383 ScopeProfiler sp(g_profiler, "dedicated server sleep");
5384 sleep_ms((int)(steplen*1000.0));
5386 server.step(steplen);
5388 if(server.getShutdownRequested() || kill)
5390 infostream<<"Dedicated server quitting"<<std::endl;
5392 if(g_settings->getBool("server_announce") == true)
5393 ServerList::sendAnnounce("delete");
5401 float profiler_print_interval =
5402 g_settings->getFloat("profiler_print_interval");
5403 if(profiler_print_interval != 0)
5405 if(m_profiler_interval.step(steplen, profiler_print_interval))
5407 infostream<<"Profiler:"<<std::endl;
5408 g_profiler->print(infostream);
5409 g_profiler->clear();