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 bool cheated = playersao->checkMovementCheat();
2257 m_script->on_cheat(playersao, "moved_too_fast");
2260 /*infostream<<"Server::ProcessData(): Moved player "<<peer_id<<" to "
2261 <<"("<<position.X<<","<<position.Y<<","<<position.Z<<")"
2262 <<" pitch="<<pitch<<" yaw="<<yaw<<std::endl;*/
2264 else if(command == TOSERVER_GOTBLOCKS)
2277 u16 count = data[2];
2278 for(u16 i=0; i<count; i++)
2280 if((s16)datasize < 2+1+(i+1)*6)
2281 throw con::InvalidIncomingDataException
2282 ("GOTBLOCKS length is too short");
2283 v3s16 p = readV3S16(&data[2+1+i*6]);
2284 /*infostream<<"Server: GOTBLOCKS ("
2285 <<p.X<<","<<p.Y<<","<<p.Z<<")"<<std::endl;*/
2286 RemoteClient *client = getClient(peer_id);
2287 client->GotBlock(p);
2290 else if(command == TOSERVER_DELETEDBLOCKS)
2303 u16 count = data[2];
2304 for(u16 i=0; i<count; i++)
2306 if((s16)datasize < 2+1+(i+1)*6)
2307 throw con::InvalidIncomingDataException
2308 ("DELETEDBLOCKS length is too short");
2309 v3s16 p = readV3S16(&data[2+1+i*6]);
2310 /*infostream<<"Server: DELETEDBLOCKS ("
2311 <<p.X<<","<<p.Y<<","<<p.Z<<")"<<std::endl;*/
2312 RemoteClient *client = getClient(peer_id);
2313 client->SetBlockNotSent(p);
2316 else if(command == TOSERVER_CLICK_OBJECT)
2318 infostream<<"Server: CLICK_OBJECT not supported anymore"<<std::endl;
2321 else if(command == TOSERVER_CLICK_ACTIVEOBJECT)
2323 infostream<<"Server: CLICK_ACTIVEOBJECT not supported anymore"<<std::endl;
2326 else if(command == TOSERVER_GROUND_ACTION)
2328 infostream<<"Server: GROUND_ACTION not supported anymore"<<std::endl;
2332 else if(command == TOSERVER_RELEASE)
2334 infostream<<"Server: RELEASE not supported anymore"<<std::endl;
2337 else if(command == TOSERVER_SIGNTEXT)
2339 infostream<<"Server: SIGNTEXT not supported anymore"
2343 else if(command == TOSERVER_SIGNNODETEXT)
2345 infostream<<"Server: SIGNNODETEXT not supported anymore"
2349 else if(command == TOSERVER_INVENTORY_ACTION)
2351 // Strip command and create a stream
2352 std::string datastring((char*)&data[2], datasize-2);
2353 verbosestream<<"TOSERVER_INVENTORY_ACTION: data="<<datastring<<std::endl;
2354 std::istringstream is(datastring, std::ios_base::binary);
2356 InventoryAction *a = InventoryAction::deSerialize(is);
2359 infostream<<"TOSERVER_INVENTORY_ACTION: "
2360 <<"InventoryAction::deSerialize() returned NULL"
2365 // If something goes wrong, this player is to blame
2366 RollbackScopeActor rollback_scope(m_rollback,
2367 std::string("player:")+player->getName());
2370 Note: Always set inventory not sent, to repair cases
2371 where the client made a bad prediction.
2375 Handle restrictions and special cases of the move action
2377 if(a->getType() == IACTION_MOVE)
2379 IMoveAction *ma = (IMoveAction*)a;
2381 ma->from_inv.applyCurrentPlayer(player->getName());
2382 ma->to_inv.applyCurrentPlayer(player->getName());
2384 setInventoryModified(ma->from_inv);
2385 setInventoryModified(ma->to_inv);
2387 bool from_inv_is_current_player =
2388 (ma->from_inv.type == InventoryLocation::PLAYER) &&
2389 (ma->from_inv.name == player->getName());
2391 bool to_inv_is_current_player =
2392 (ma->to_inv.type == InventoryLocation::PLAYER) &&
2393 (ma->to_inv.name == player->getName());
2396 Disable moving items out of craftpreview
2398 if(ma->from_list == "craftpreview")
2400 infostream<<"Ignoring IMoveAction from "
2401 <<(ma->from_inv.dump())<<":"<<ma->from_list
2402 <<" to "<<(ma->to_inv.dump())<<":"<<ma->to_list
2403 <<" because src is "<<ma->from_list<<std::endl;
2409 Disable moving items into craftresult and craftpreview
2411 if(ma->to_list == "craftpreview" || ma->to_list == "craftresult")
2413 infostream<<"Ignoring IMoveAction from "
2414 <<(ma->from_inv.dump())<<":"<<ma->from_list
2415 <<" to "<<(ma->to_inv.dump())<<":"<<ma->to_list
2416 <<" because dst is "<<ma->to_list<<std::endl;
2421 // Disallow moving items in elsewhere than player's inventory
2422 // if not allowed to interact
2423 if(!checkPriv(player->getName(), "interact") &&
2424 (!from_inv_is_current_player ||
2425 !to_inv_is_current_player))
2427 infostream<<"Cannot move outside of player's inventory: "
2428 <<"No interact privilege"<<std::endl;
2434 Handle restrictions and special cases of the drop action
2436 else if(a->getType() == IACTION_DROP)
2438 IDropAction *da = (IDropAction*)a;
2440 da->from_inv.applyCurrentPlayer(player->getName());
2442 setInventoryModified(da->from_inv);
2445 Disable dropping items out of craftpreview
2447 if(da->from_list == "craftpreview")
2449 infostream<<"Ignoring IDropAction from "
2450 <<(da->from_inv.dump())<<":"<<da->from_list
2451 <<" because src is "<<da->from_list<<std::endl;
2456 // Disallow dropping items if not allowed to interact
2457 if(!checkPriv(player->getName(), "interact"))
2464 Handle restrictions and special cases of the craft action
2466 else if(a->getType() == IACTION_CRAFT)
2468 ICraftAction *ca = (ICraftAction*)a;
2470 ca->craft_inv.applyCurrentPlayer(player->getName());
2472 setInventoryModified(ca->craft_inv);
2474 //bool craft_inv_is_current_player =
2475 // (ca->craft_inv.type == InventoryLocation::PLAYER) &&
2476 // (ca->craft_inv.name == player->getName());
2478 // Disallow crafting if not allowed to interact
2479 if(!checkPriv(player->getName(), "interact"))
2481 infostream<<"Cannot craft: "
2482 <<"No interact privilege"<<std::endl;
2489 a->apply(this, playersao, this);
2493 else if(command == TOSERVER_CHAT_MESSAGE)
2501 std::string datastring((char*)&data[2], datasize-2);
2502 std::istringstream is(datastring, std::ios_base::binary);
2505 is.read((char*)buf, 2);
2506 u16 len = readU16(buf);
2508 std::wstring message;
2509 for(u16 i=0; i<len; i++)
2511 is.read((char*)buf, 2);
2512 message += (wchar_t)readU16(buf);
2515 // If something goes wrong, this player is to blame
2516 RollbackScopeActor rollback_scope(m_rollback,
2517 std::string("player:")+player->getName());
2519 // Get player name of this client
2520 std::wstring name = narrow_to_wide(player->getName());
2523 bool ate = m_script->on_chat_message(player->getName(),
2524 wide_to_narrow(message));
2525 // If script ate the message, don't proceed
2529 // Line to send to players
2531 // Whether to send to the player that sent the line
2532 bool send_to_sender = false;
2533 // Whether to send to other players
2534 bool send_to_others = false;
2536 // Commands are implemented in Lua, so only catch invalid
2537 // commands that were not "eaten" and send an error back
2538 if(message[0] == L'/')
2540 message = message.substr(1);
2541 send_to_sender = true;
2542 if(message.length() == 0)
2543 line += L"-!- Empty command";
2545 line += L"-!- Invalid command: " + str_split(message, L' ')[0];
2549 if(checkPriv(player->getName(), "shout")){
2554 send_to_others = true;
2556 line += L"-!- You don't have permission to shout.";
2557 send_to_sender = true;
2564 actionstream<<"CHAT: "<<wide_to_narrow(line)<<std::endl;
2567 Send the message to clients
2569 for(std::map<u16, RemoteClient*>::iterator
2570 i = m_clients.begin();
2571 i != m_clients.end(); ++i)
2573 // Get client and check that it is valid
2574 RemoteClient *client = i->second;
2575 assert(client->peer_id == i->first);
2576 if(client->serialization_version == SER_FMT_VER_INVALID)
2580 bool sender_selected = (peer_id == client->peer_id);
2581 if(sender_selected == true && send_to_sender == false)
2583 if(sender_selected == false && send_to_others == false)
2586 SendChatMessage(client->peer_id, line);
2590 else if(command == TOSERVER_DAMAGE)
2592 std::string datastring((char*)&data[2], datasize-2);
2593 std::istringstream is(datastring, std::ios_base::binary);
2594 u8 damage = readU8(is);
2596 if(g_settings->getBool("enable_damage"))
2598 actionstream<<player->getName()<<" damaged by "
2599 <<(int)damage<<" hp at "<<PP(player->getPosition()/BS)
2602 playersao->setHP(playersao->getHP() - damage);
2604 if(playersao->getHP() == 0 && playersao->m_hp_not_sent)
2607 if(playersao->m_hp_not_sent)
2608 SendPlayerHP(peer_id);
2611 else if(command == TOSERVER_BREATH)
2613 std::string datastring((char*)&data[2], datasize-2);
2614 std::istringstream is(datastring, std::ios_base::binary);
2615 u16 breath = readU16(is);
2616 playersao->setBreath(breath);
2618 else if(command == TOSERVER_PASSWORD)
2621 [0] u16 TOSERVER_PASSWORD
2622 [2] u8[28] old password
2623 [30] u8[28] new password
2626 if(datasize != 2+PASSWORD_SIZE*2)
2628 /*char password[PASSWORD_SIZE];
2629 for(u32 i=0; i<PASSWORD_SIZE-1; i++)
2630 password[i] = data[2+i];
2631 password[PASSWORD_SIZE-1] = 0;*/
2633 for(u32 i=0; i<PASSWORD_SIZE-1; i++)
2641 for(u32 i=0; i<PASSWORD_SIZE-1; i++)
2643 char c = data[2+PASSWORD_SIZE+i];
2649 if(!base64_is_valid(newpwd)){
2650 infostream<<"Server: "<<player->getName()<<" supplied invalid password hash"<<std::endl;
2651 // Wrong old password supplied!!
2652 SendChatMessage(peer_id, L"Invalid new password hash supplied. Password NOT changed.");
2656 infostream<<"Server: Client requests a password change from "
2657 <<"'"<<oldpwd<<"' to '"<<newpwd<<"'"<<std::endl;
2659 std::string playername = player->getName();
2661 std::string checkpwd;
2662 m_script->getAuth(playername, &checkpwd, NULL);
2664 if(oldpwd != checkpwd)
2666 infostream<<"Server: invalid old password"<<std::endl;
2667 // Wrong old password supplied!!
2668 SendChatMessage(peer_id, L"Invalid old password supplied. Password NOT changed.");
2672 bool success = m_script->setPassword(playername, newpwd);
2674 actionstream<<player->getName()<<" changes password"<<std::endl;
2675 SendChatMessage(peer_id, L"Password change successful.");
2677 actionstream<<player->getName()<<" tries to change password but "
2678 <<"it fails"<<std::endl;
2679 SendChatMessage(peer_id, L"Password change failed or inavailable.");
2682 else if(command == TOSERVER_PLAYERITEM)
2687 u16 item = readU16(&data[2]);
2688 playersao->setWieldIndex(item);
2690 else if(command == TOSERVER_RESPAWN)
2692 if(player->hp != 0 || !g_settings->getBool("enable_damage"))
2695 RespawnPlayer(peer_id);
2697 actionstream<<player->getName()<<" respawns at "
2698 <<PP(player->getPosition()/BS)<<std::endl;
2700 // ActiveObject is added to environment in AsyncRunStep after
2701 // the previous addition has been succesfully removed
2703 else if(command == TOSERVER_REQUEST_MEDIA) {
2704 std::string datastring((char*)&data[2], datasize-2);
2705 std::istringstream is(datastring, std::ios_base::binary);
2707 std::list<MediaRequest> tosend;
2708 u16 numfiles = readU16(is);
2710 infostream<<"Sending "<<numfiles<<" files to "
2711 <<getPlayerName(peer_id)<<std::endl;
2712 verbosestream<<"TOSERVER_REQUEST_MEDIA: "<<std::endl;
2714 for(int i = 0; i < numfiles; i++) {
2715 std::string name = deSerializeString(is);
2716 tosend.push_back(MediaRequest(name));
2717 verbosestream<<"TOSERVER_REQUEST_MEDIA: requested file "
2721 sendRequestedMedia(peer_id, tosend);
2723 // Now the client should know about everything
2724 // (definitions and files)
2725 getClient(peer_id)->definitions_sent = true;
2727 else if(command == TOSERVER_RECEIVED_MEDIA) {
2728 getClient(peer_id)->definitions_sent = true;
2730 else if(command == TOSERVER_INTERACT)
2732 std::string datastring((char*)&data[2], datasize-2);
2733 std::istringstream is(datastring, std::ios_base::binary);
2739 [5] u32 length of the next item
2740 [9] serialized PointedThing
2742 0: start digging (from undersurface) or use
2743 1: stop digging (all parameters ignored)
2744 2: digging completed
2745 3: place block or item (to abovesurface)
2748 u8 action = readU8(is);
2749 u16 item_i = readU16(is);
2750 std::istringstream tmp_is(deSerializeLongString(is), std::ios::binary);
2751 PointedThing pointed;
2752 pointed.deSerialize(tmp_is);
2754 verbosestream<<"TOSERVER_INTERACT: action="<<(int)action<<", item="
2755 <<item_i<<", pointed="<<pointed.dump()<<std::endl;
2759 verbosestream<<"TOSERVER_INTERACT: "<<player->getName()
2760 <<" tried to interact, but is dead!"<<std::endl;
2764 v3f player_pos = playersao->getLastGoodPosition();
2766 // Update wielded item
2767 playersao->setWieldIndex(item_i);
2769 // Get pointed to node (undefined if not POINTEDTYPE_NODE)
2770 v3s16 p_under = pointed.node_undersurface;
2771 v3s16 p_above = pointed.node_abovesurface;
2773 // Get pointed to object (NULL if not POINTEDTYPE_OBJECT)
2774 ServerActiveObject *pointed_object = NULL;
2775 if(pointed.type == POINTEDTHING_OBJECT)
2777 pointed_object = m_env->getActiveObject(pointed.object_id);
2778 if(pointed_object == NULL)
2780 verbosestream<<"TOSERVER_INTERACT: "
2781 "pointed object is NULL"<<std::endl;
2787 v3f pointed_pos_under = player_pos;
2788 v3f pointed_pos_above = player_pos;
2789 if(pointed.type == POINTEDTHING_NODE)
2791 pointed_pos_under = intToFloat(p_under, BS);
2792 pointed_pos_above = intToFloat(p_above, BS);
2794 else if(pointed.type == POINTEDTHING_OBJECT)
2796 pointed_pos_under = pointed_object->getBasePosition();
2797 pointed_pos_above = pointed_pos_under;
2801 Check that target is reasonably close
2802 (only when digging or placing things)
2804 if(action == 0 || action == 2 || action == 3)
2806 float d = player_pos.getDistanceFrom(pointed_pos_under);
2807 float max_d = BS * 14; // Just some large enough value
2809 actionstream<<"Player "<<player->getName()
2810 <<" tried to access "<<pointed.dump()
2812 <<"d="<<d<<", max_d="<<max_d
2813 <<". ignoring."<<std::endl;
2814 // Re-send block to revert change on client-side
2815 RemoteClient *client = getClient(peer_id);
2816 v3s16 blockpos = getNodeBlockPos(floatToInt(pointed_pos_under, BS));
2817 client->SetBlockNotSent(blockpos);
2819 m_script->on_cheat(playersao, "interacted_too_far");
2826 Make sure the player is allowed to do it
2828 if(!checkPriv(player->getName(), "interact"))
2830 actionstream<<player->getName()<<" attempted to interact with "
2831 <<pointed.dump()<<" without 'interact' privilege"
2833 // Re-send block to revert change on client-side
2834 RemoteClient *client = getClient(peer_id);
2835 // Digging completed -> under
2837 v3s16 blockpos = getNodeBlockPos(floatToInt(pointed_pos_under, BS));
2838 client->SetBlockNotSent(blockpos);
2840 // Placement -> above
2842 v3s16 blockpos = getNodeBlockPos(floatToInt(pointed_pos_above, BS));
2843 client->SetBlockNotSent(blockpos);
2849 If something goes wrong, this player is to blame
2851 RollbackScopeActor rollback_scope(m_rollback,
2852 std::string("player:")+player->getName());
2855 0: start digging or punch object
2859 if(pointed.type == POINTEDTHING_NODE)
2862 NOTE: This can be used in the future to check if
2863 somebody is cheating, by checking the timing.
2865 MapNode n(CONTENT_IGNORE);
2868 n = m_env->getMap().getNode(p_under);
2870 catch(InvalidPositionException &e)
2872 infostream<<"Server: Not punching: Node not found."
2873 <<" Adding block to emerge queue."
2875 m_emerge->enqueueBlockEmerge(peer_id, getNodeBlockPos(p_above), false);
2877 if(n.getContent() != CONTENT_IGNORE)
2878 m_script->node_on_punch(p_under, n, playersao);
2880 playersao->noCheatDigStart(p_under);
2882 else if(pointed.type == POINTEDTHING_OBJECT)
2884 // Skip if object has been removed
2885 if(pointed_object->m_removed)
2888 actionstream<<player->getName()<<" punches object "
2889 <<pointed.object_id<<": "
2890 <<pointed_object->getDescription()<<std::endl;
2892 ItemStack punchitem = playersao->getWieldedItem();
2893 ToolCapabilities toolcap =
2894 punchitem.getToolCapabilities(m_itemdef);
2895 v3f dir = (pointed_object->getBasePosition() -
2896 (player->getPosition() + player->getEyeOffset())
2898 float time_from_last_punch =
2899 playersao->resetTimeFromLastPunch();
2900 pointed_object->punch(dir, &toolcap, playersao,
2901 time_from_last_punch);
2909 else if(action == 1)
2914 2: Digging completed
2916 else if(action == 2)
2918 // Only digging of nodes
2919 if(pointed.type == POINTEDTHING_NODE)
2921 MapNode n(CONTENT_IGNORE);
2924 n = m_env->getMap().getNode(p_under);
2926 catch(InvalidPositionException &e)
2928 infostream<<"Server: Not finishing digging: Node not found."
2929 <<" Adding block to emerge queue."
2931 m_emerge->enqueueBlockEmerge(peer_id, getNodeBlockPos(p_above), false);
2934 /* Cheat prevention */
2935 bool is_valid_dig = true;
2936 if(!isSingleplayer() && !g_settings->getBool("disable_anticheat"))
2938 v3s16 nocheat_p = playersao->getNoCheatDigPos();
2939 float nocheat_t = playersao->getNoCheatDigTime();
2940 playersao->noCheatDigEnd();
2941 // If player didn't start digging this, ignore dig
2942 if(nocheat_p != p_under){
2943 infostream<<"Server: NoCheat: "<<player->getName()
2944 <<" started digging "
2945 <<PP(nocheat_p)<<" and completed digging "
2946 <<PP(p_under)<<"; not digging."<<std::endl;
2947 is_valid_dig = false;
2949 m_script->on_cheat(playersao, "finished_unknown_dig");
2951 // Get player's wielded item
2952 ItemStack playeritem;
2953 InventoryList *mlist = playersao->getInventory()->getList("main");
2955 playeritem = mlist->getItem(playersao->getWieldIndex());
2956 ToolCapabilities playeritem_toolcap =
2957 playeritem.getToolCapabilities(m_itemdef);
2958 // Get diggability and expected digging time
2959 DigParams params = getDigParams(m_nodedef->get(n).groups,
2960 &playeritem_toolcap);
2961 // If can't dig, try hand
2962 if(!params.diggable){
2963 const ItemDefinition &hand = m_itemdef->get("");
2964 const ToolCapabilities *tp = hand.tool_capabilities;
2966 params = getDigParams(m_nodedef->get(n).groups, tp);
2968 // If can't dig, ignore dig
2969 if(!params.diggable){
2970 infostream<<"Server: NoCheat: "<<player->getName()
2971 <<" completed digging "<<PP(p_under)
2972 <<", which is not diggable with tool. not digging."
2974 is_valid_dig = false;
2976 m_script->on_cheat(playersao, "dug_unbreakable");
2978 // Check digging time
2979 // If already invalidated, we don't have to
2981 // Well not our problem then
2983 // Clean and long dig
2984 else if(params.time > 2.0 && nocheat_t * 1.2 > params.time){
2985 // All is good, but grab time from pool; don't care if
2986 // it's actually available
2987 playersao->getDigPool().grab(params.time);
2989 // Short or laggy dig
2990 // Try getting the time from pool
2991 else if(playersao->getDigPool().grab(params.time)){
2996 infostream<<"Server: NoCheat: "<<player->getName()
2997 <<" completed digging "<<PP(p_under)
2998 <<"too fast; not digging."<<std::endl;
2999 is_valid_dig = false;
3001 m_script->on_cheat(playersao, "dug_too_fast");
3005 /* Actually dig node */
3007 if(is_valid_dig && n.getContent() != CONTENT_IGNORE)
3008 m_script->node_on_dig(p_under, n, playersao);
3010 // Send unusual result (that is, node not being removed)
3011 if(m_env->getMap().getNodeNoEx(p_under).getContent() != CONTENT_AIR)
3013 // Re-send block to revert change on client-side
3014 RemoteClient *client = getClient(peer_id);
3015 v3s16 blockpos = getNodeBlockPos(floatToInt(pointed_pos_under, BS));
3016 client->SetBlockNotSent(blockpos);
3022 3: place block or right-click object
3024 else if(action == 3)
3026 ItemStack item = playersao->getWieldedItem();
3028 // Reset build time counter
3029 if(pointed.type == POINTEDTHING_NODE &&
3030 item.getDefinition(m_itemdef).type == ITEM_NODE)
3031 getClient(peer_id)->m_time_from_building = 0.0;
3033 if(pointed.type == POINTEDTHING_OBJECT)
3035 // Right click object
3037 // Skip if object has been removed
3038 if(pointed_object->m_removed)
3041 actionstream<<player->getName()<<" right-clicks object "
3042 <<pointed.object_id<<": "
3043 <<pointed_object->getDescription()<<std::endl;
3046 pointed_object->rightClick(playersao);
3048 else if(m_script->item_OnPlace(
3049 item, playersao, pointed))
3051 // Placement was handled in lua
3053 // Apply returned ItemStack
3054 playersao->setWieldedItem(item);
3057 // If item has node placement prediction, always send the
3058 // blocks to make sure the client knows what exactly happened
3059 if(item.getDefinition(m_itemdef).node_placement_prediction != ""){
3060 RemoteClient *client = getClient(peer_id);
3061 v3s16 blockpos = getNodeBlockPos(floatToInt(pointed_pos_above, BS));
3062 client->SetBlockNotSent(blockpos);
3063 v3s16 blockpos2 = getNodeBlockPos(floatToInt(pointed_pos_under, BS));
3064 if(blockpos2 != blockpos){
3065 client->SetBlockNotSent(blockpos2);
3073 else if(action == 4)
3075 ItemStack item = playersao->getWieldedItem();
3077 actionstream<<player->getName()<<" uses "<<item.name
3078 <<", pointing at "<<pointed.dump()<<std::endl;
3080 if(m_script->item_OnUse(
3081 item, playersao, pointed))
3083 // Apply returned ItemStack
3084 playersao->setWieldedItem(item);
3091 Catch invalid actions
3095 infostream<<"WARNING: Server: Invalid action "
3096 <<action<<std::endl;
3099 else if(command == TOSERVER_REMOVED_SOUNDS)
3101 std::string datastring((char*)&data[2], datasize-2);
3102 std::istringstream is(datastring, std::ios_base::binary);
3104 int num = readU16(is);
3105 for(int k=0; k<num; k++){
3106 s32 id = readS32(is);
3107 std::map<s32, ServerPlayingSound>::iterator i =
3108 m_playing_sounds.find(id);
3109 if(i == m_playing_sounds.end())
3111 ServerPlayingSound &psound = i->second;
3112 psound.clients.erase(peer_id);
3113 if(psound.clients.size() == 0)
3114 m_playing_sounds.erase(i++);
3117 else if(command == TOSERVER_NODEMETA_FIELDS)
3119 std::string datastring((char*)&data[2], datasize-2);
3120 std::istringstream is(datastring, std::ios_base::binary);
3122 v3s16 p = readV3S16(is);
3123 std::string formname = deSerializeString(is);
3124 int num = readU16(is);
3125 std::map<std::string, std::string> fields;
3126 for(int k=0; k<num; k++){
3127 std::string fieldname = deSerializeString(is);
3128 std::string fieldvalue = deSerializeLongString(is);
3129 fields[fieldname] = fieldvalue;
3132 // If something goes wrong, this player is to blame
3133 RollbackScopeActor rollback_scope(m_rollback,
3134 std::string("player:")+player->getName());
3136 // Check the target node for rollback data; leave others unnoticed
3137 RollbackNode rn_old(&m_env->getMap(), p, this);
3139 m_script->node_on_receive_fields(p, formname, fields,playersao);
3141 // Report rollback data
3142 RollbackNode rn_new(&m_env->getMap(), p, this);
3143 if(rollback() && rn_new != rn_old){
3144 RollbackAction action;
3145 action.setSetNode(p, rn_old, rn_new);
3146 rollback()->reportAction(action);
3149 else if(command == TOSERVER_INVENTORY_FIELDS)
3151 std::string datastring((char*)&data[2], datasize-2);
3152 std::istringstream is(datastring, std::ios_base::binary);
3154 std::string formname = deSerializeString(is);
3155 int num = readU16(is);
3156 std::map<std::string, std::string> fields;
3157 for(int k=0; k<num; k++){
3158 std::string fieldname = deSerializeString(is);
3159 std::string fieldvalue = deSerializeLongString(is);
3160 fields[fieldname] = fieldvalue;
3163 m_script->on_playerReceiveFields(playersao, formname, fields);
3167 infostream<<"Server::ProcessData(): Ignoring "
3168 "unknown command "<<command<<std::endl;
3172 catch(SendFailedException &e)
3174 errorstream<<"Server::ProcessData(): SendFailedException: "
3180 void Server::onMapEditEvent(MapEditEvent *event)
3182 //infostream<<"Server::onMapEditEvent()"<<std::endl;
3183 if(m_ignore_map_edit_events)
3185 if(m_ignore_map_edit_events_area.contains(event->getArea()))
3187 MapEditEvent *e = event->clone();
3188 m_unsent_map_edit_queue.push_back(e);
3191 Inventory* Server::getInventory(const InventoryLocation &loc)
3194 case InventoryLocation::UNDEFINED:
3197 case InventoryLocation::CURRENT_PLAYER:
3200 case InventoryLocation::PLAYER:
3202 Player *player = m_env->getPlayer(loc.name.c_str());
3205 PlayerSAO *playersao = player->getPlayerSAO();
3208 return playersao->getInventory();
3211 case InventoryLocation::NODEMETA:
3213 NodeMetadata *meta = m_env->getMap().getNodeMetadata(loc.p);
3216 return meta->getInventory();
3219 case InventoryLocation::DETACHED:
3221 if(m_detached_inventories.count(loc.name) == 0)
3223 return m_detached_inventories[loc.name];
3231 void Server::setInventoryModified(const InventoryLocation &loc)
3234 case InventoryLocation::UNDEFINED:
3237 case InventoryLocation::PLAYER:
3239 Player *player = m_env->getPlayer(loc.name.c_str());
3242 PlayerSAO *playersao = player->getPlayerSAO();
3245 playersao->m_inventory_not_sent = true;
3246 playersao->m_wielded_item_not_sent = true;
3249 case InventoryLocation::NODEMETA:
3251 v3s16 blockpos = getNodeBlockPos(loc.p);
3253 MapBlock *block = m_env->getMap().getBlockNoCreateNoEx(blockpos);
3255 block->raiseModified(MOD_STATE_WRITE_NEEDED);
3257 setBlockNotSent(blockpos);
3260 case InventoryLocation::DETACHED:
3262 sendDetachedInventoryToAll(loc.name);
3270 //std::list<PlayerInfo> Server::getPlayerInfo()
3272 // DSTACK(__FUNCTION_NAME);
3273 // JMutexAutoLock envlock(m_env_mutex);
3274 // JMutexAutoLock conlock(m_con_mutex);
3276 // std::list<PlayerInfo> list;
3278 // std::list<Player*> players = m_env->getPlayers();
3280 // std::list<Player*>::iterator i;
3281 // for(i = players.begin();
3282 // i != players.end(); ++i)
3286 // Player *player = *i;
3289 // // Copy info from connection to info struct
3290 // info.id = player->peer_id;
3291 // info.address = m_con.GetPeerAddress(player->peer_id);
3292 // info.avg_rtt = m_con.GetPeerAvgRTT(player->peer_id);
3294 // catch(con::PeerNotFoundException &e)
3296 // // Set dummy peer info
3298 // info.address = Address(0,0,0,0,0);
3299 // info.avg_rtt = 0.0;
3302 // snprintf(info.name, PLAYERNAME_SIZE, "%s", player->getName());
3303 // info.position = player->getPosition();
3305 // list.push_back(info);
3312 void Server::peerAdded(con::Peer *peer)
3314 DSTACK(__FUNCTION_NAME);
3315 verbosestream<<"Server::peerAdded(): peer->id="
3316 <<peer->id<<std::endl;
3319 c.type = PEER_ADDED;
3320 c.peer_id = peer->id;
3322 m_peer_change_queue.push_back(c);
3325 void Server::deletingPeer(con::Peer *peer, bool timeout)
3327 DSTACK(__FUNCTION_NAME);
3328 verbosestream<<"Server::deletingPeer(): peer->id="
3329 <<peer->id<<", timeout="<<timeout<<std::endl;
3332 c.type = PEER_REMOVED;
3333 c.peer_id = peer->id;
3334 c.timeout = timeout;
3335 m_peer_change_queue.push_back(c);
3342 void Server::SendMovement(con::Connection &con, u16 peer_id)
3344 DSTACK(__FUNCTION_NAME);
3345 std::ostringstream os(std::ios_base::binary);
3347 writeU16(os, TOCLIENT_MOVEMENT);
3348 writeF1000(os, g_settings->getFloat("movement_acceleration_default"));
3349 writeF1000(os, g_settings->getFloat("movement_acceleration_air"));
3350 writeF1000(os, g_settings->getFloat("movement_acceleration_fast"));
3351 writeF1000(os, g_settings->getFloat("movement_speed_walk"));
3352 writeF1000(os, g_settings->getFloat("movement_speed_crouch"));
3353 writeF1000(os, g_settings->getFloat("movement_speed_fast"));
3354 writeF1000(os, g_settings->getFloat("movement_speed_climb"));
3355 writeF1000(os, g_settings->getFloat("movement_speed_jump"));
3356 writeF1000(os, g_settings->getFloat("movement_liquid_fluidity"));
3357 writeF1000(os, g_settings->getFloat("movement_liquid_fluidity_smooth"));
3358 writeF1000(os, g_settings->getFloat("movement_liquid_sink"));
3359 writeF1000(os, g_settings->getFloat("movement_gravity"));
3362 std::string s = os.str();
3363 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3365 con.Send(peer_id, 0, data, true);
3368 void Server::SendHP(con::Connection &con, u16 peer_id, u8 hp)
3370 DSTACK(__FUNCTION_NAME);
3371 std::ostringstream os(std::ios_base::binary);
3373 writeU16(os, TOCLIENT_HP);
3377 std::string s = os.str();
3378 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3380 con.Send(peer_id, 0, data, true);
3383 void Server::SendBreath(con::Connection &con, u16 peer_id, u16 breath)
3385 DSTACK(__FUNCTION_NAME);
3386 std::ostringstream os(std::ios_base::binary);
3388 writeU16(os, TOCLIENT_BREATH);
3389 writeU16(os, breath);
3392 std::string s = os.str();
3393 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3395 con.Send(peer_id, 0, data, true);
3398 void Server::SendAccessDenied(con::Connection &con, u16 peer_id,
3399 const std::wstring &reason)
3401 DSTACK(__FUNCTION_NAME);
3402 std::ostringstream os(std::ios_base::binary);
3404 writeU16(os, TOCLIENT_ACCESS_DENIED);
3405 os<<serializeWideString(reason);
3408 std::string s = os.str();
3409 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3411 con.Send(peer_id, 0, data, true);
3414 void Server::SendDeathscreen(con::Connection &con, u16 peer_id,
3415 bool set_camera_point_target, v3f camera_point_target)
3417 DSTACK(__FUNCTION_NAME);
3418 std::ostringstream os(std::ios_base::binary);
3420 writeU16(os, TOCLIENT_DEATHSCREEN);
3421 writeU8(os, set_camera_point_target);
3422 writeV3F1000(os, camera_point_target);
3425 std::string s = os.str();
3426 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3428 con.Send(peer_id, 0, data, true);
3431 void Server::SendItemDef(con::Connection &con, u16 peer_id,
3432 IItemDefManager *itemdef, u16 protocol_version)
3434 DSTACK(__FUNCTION_NAME);
3435 std::ostringstream os(std::ios_base::binary);
3439 u32 length of the next item
3440 zlib-compressed serialized ItemDefManager
3442 writeU16(os, TOCLIENT_ITEMDEF);
3443 std::ostringstream tmp_os(std::ios::binary);
3444 itemdef->serialize(tmp_os, protocol_version);
3445 std::ostringstream tmp_os2(std::ios::binary);
3446 compressZlib(tmp_os.str(), tmp_os2);
3447 os<<serializeLongString(tmp_os2.str());
3450 std::string s = os.str();
3451 verbosestream<<"Server: Sending item definitions to id("<<peer_id
3452 <<"): size="<<s.size()<<std::endl;
3453 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3455 con.Send(peer_id, 0, data, true);
3458 void Server::SendNodeDef(con::Connection &con, u16 peer_id,
3459 INodeDefManager *nodedef, u16 protocol_version)
3461 DSTACK(__FUNCTION_NAME);
3462 std::ostringstream os(std::ios_base::binary);
3466 u32 length of the next item
3467 zlib-compressed serialized NodeDefManager
3469 writeU16(os, TOCLIENT_NODEDEF);
3470 std::ostringstream tmp_os(std::ios::binary);
3471 nodedef->serialize(tmp_os, protocol_version);
3472 std::ostringstream tmp_os2(std::ios::binary);
3473 compressZlib(tmp_os.str(), tmp_os2);
3474 os<<serializeLongString(tmp_os2.str());
3477 std::string s = os.str();
3478 verbosestream<<"Server: Sending node definitions to id("<<peer_id
3479 <<"): size="<<s.size()<<std::endl;
3480 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3482 con.Send(peer_id, 0, data, true);
3486 Non-static send methods
3489 void Server::SendInventory(u16 peer_id)
3491 DSTACK(__FUNCTION_NAME);
3493 PlayerSAO *playersao = getPlayerSAO(peer_id);
3496 playersao->m_inventory_not_sent = false;
3502 std::ostringstream os;
3503 playersao->getInventory()->serialize(os);
3505 std::string s = os.str();
3507 SharedBuffer<u8> data(s.size()+2);
3508 writeU16(&data[0], TOCLIENT_INVENTORY);
3509 memcpy(&data[2], s.c_str(), s.size());
3512 m_con.Send(peer_id, 0, data, true);
3515 void Server::SendChatMessage(u16 peer_id, const std::wstring &message)
3517 DSTACK(__FUNCTION_NAME);
3519 std::ostringstream os(std::ios_base::binary);
3523 writeU16(buf, TOCLIENT_CHAT_MESSAGE);
3524 os.write((char*)buf, 2);
3527 writeU16(buf, message.size());
3528 os.write((char*)buf, 2);
3531 for(u32 i=0; i<message.size(); i++)
3535 os.write((char*)buf, 2);
3539 std::string s = os.str();
3540 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3542 m_con.Send(peer_id, 0, data, true);
3545 void Server::SendShowFormspecMessage(u16 peer_id, const std::string formspec,
3546 const std::string formname)
3548 DSTACK(__FUNCTION_NAME);
3550 std::ostringstream os(std::ios_base::binary);
3554 writeU16(buf, TOCLIENT_SHOW_FORMSPEC);
3555 os.write((char*)buf, 2);
3556 os<<serializeLongString(formspec);
3557 os<<serializeString(formname);
3560 std::string s = os.str();
3561 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3563 m_con.Send(peer_id, 0, data, true);
3566 // Spawns a particle on peer with peer_id
3567 void Server::SendSpawnParticle(u16 peer_id, v3f pos, v3f velocity, v3f acceleration,
3568 float expirationtime, float size, bool collisiondetection,
3569 std::string texture)
3571 DSTACK(__FUNCTION_NAME);
3573 std::ostringstream os(std::ios_base::binary);
3574 writeU16(os, TOCLIENT_SPAWN_PARTICLE);
3575 writeV3F1000(os, pos);
3576 writeV3F1000(os, velocity);
3577 writeV3F1000(os, acceleration);
3578 writeF1000(os, expirationtime);
3579 writeF1000(os, size);
3580 writeU8(os, collisiondetection);
3581 os<<serializeLongString(texture);
3584 std::string s = os.str();
3585 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3587 m_con.Send(peer_id, 0, data, true);
3590 // Spawns a particle on all peers
3591 void Server::SendSpawnParticleAll(v3f pos, v3f velocity, v3f acceleration,
3592 float expirationtime, float size, bool collisiondetection,
3593 std::string texture)
3595 for(std::map<u16, RemoteClient*>::iterator
3596 i = m_clients.begin();
3597 i != m_clients.end(); i++)
3599 // Get client and check that it is valid
3600 RemoteClient *client = i->second;
3601 assert(client->peer_id == i->first);
3602 if(client->serialization_version == SER_FMT_VER_INVALID)
3605 SendSpawnParticle(client->peer_id, pos, velocity, acceleration,
3606 expirationtime, size, collisiondetection, texture);
3610 // Adds a ParticleSpawner on peer with peer_id
3611 void Server::SendAddParticleSpawner(u16 peer_id, u16 amount, float spawntime, v3f minpos, v3f maxpos,
3612 v3f minvel, v3f maxvel, v3f minacc, v3f maxacc, float minexptime, float maxexptime,
3613 float minsize, float maxsize, bool collisiondetection, std::string texture, u32 id)
3615 DSTACK(__FUNCTION_NAME);
3617 std::ostringstream os(std::ios_base::binary);
3618 writeU16(os, TOCLIENT_ADD_PARTICLESPAWNER);
3620 writeU16(os, amount);
3621 writeF1000(os, spawntime);
3622 writeV3F1000(os, minpos);
3623 writeV3F1000(os, maxpos);
3624 writeV3F1000(os, minvel);
3625 writeV3F1000(os, maxvel);
3626 writeV3F1000(os, minacc);
3627 writeV3F1000(os, maxacc);
3628 writeF1000(os, minexptime);
3629 writeF1000(os, maxexptime);
3630 writeF1000(os, minsize);
3631 writeF1000(os, maxsize);
3632 writeU8(os, collisiondetection);
3633 os<<serializeLongString(texture);
3637 std::string s = os.str();
3638 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3640 m_con.Send(peer_id, 0, data, true);
3643 // Adds a ParticleSpawner on all peers
3644 void Server::SendAddParticleSpawnerAll(u16 amount, float spawntime, v3f minpos, v3f maxpos,
3645 v3f minvel, v3f maxvel, v3f minacc, v3f maxacc, float minexptime, float maxexptime,
3646 float minsize, float maxsize, bool collisiondetection, std::string texture, u32 id)
3648 for(std::map<u16, RemoteClient*>::iterator
3649 i = m_clients.begin();
3650 i != m_clients.end(); i++)
3652 // Get client and check that it is valid
3653 RemoteClient *client = i->second;
3654 assert(client->peer_id == i->first);
3655 if(client->serialization_version == SER_FMT_VER_INVALID)
3658 SendAddParticleSpawner(client->peer_id, amount, spawntime,
3659 minpos, maxpos, minvel, maxvel, minacc, maxacc,
3660 minexptime, maxexptime, minsize, maxsize, collisiondetection, texture, id);
3664 void Server::SendDeleteParticleSpawner(u16 peer_id, u32 id)
3666 DSTACK(__FUNCTION_NAME);
3668 std::ostringstream os(std::ios_base::binary);
3669 writeU16(os, TOCLIENT_DELETE_PARTICLESPAWNER);
3674 std::string s = os.str();
3675 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3677 m_con.Send(peer_id, 0, data, true);
3680 void Server::SendDeleteParticleSpawnerAll(u32 id)
3682 for(std::map<u16, RemoteClient*>::iterator
3683 i = m_clients.begin();
3684 i != m_clients.end(); i++)
3686 // Get client and check that it is valid
3687 RemoteClient *client = i->second;
3688 assert(client->peer_id == i->first);
3689 if(client->serialization_version == SER_FMT_VER_INVALID)
3692 SendDeleteParticleSpawner(client->peer_id, id);
3696 void Server::SendHUDAdd(u16 peer_id, u32 id, HudElement *form)
3698 std::ostringstream os(std::ios_base::binary);
3701 writeU16(os, TOCLIENT_HUDADD);
3703 writeU8(os, (u8)form->type);
3704 writeV2F1000(os, form->pos);
3705 os << serializeString(form->name);
3706 writeV2F1000(os, form->scale);
3707 os << serializeString(form->text);
3708 writeU32(os, form->number);
3709 writeU32(os, form->item);
3710 writeU32(os, form->dir);
3711 writeV2F1000(os, form->align);
3712 writeV2F1000(os, form->offset);
3715 std::string s = os.str();
3716 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3718 m_con.Send(peer_id, 0, data, true);
3721 void Server::SendHUDRemove(u16 peer_id, u32 id)
3723 std::ostringstream os(std::ios_base::binary);
3726 writeU16(os, TOCLIENT_HUDRM);
3730 std::string s = os.str();
3731 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3733 m_con.Send(peer_id, 0, data, true);
3736 void Server::SendHUDChange(u16 peer_id, u32 id, HudElementStat stat, void *value)
3738 std::ostringstream os(std::ios_base::binary);
3741 writeU16(os, TOCLIENT_HUDCHANGE);
3743 writeU8(os, (u8)stat);
3746 case HUD_STAT_SCALE:
3747 case HUD_STAT_ALIGN:
3748 case HUD_STAT_OFFSET:
3749 writeV2F1000(os, *(v2f *)value);
3753 os << serializeString(*(std::string *)value);
3755 case HUD_STAT_NUMBER:
3759 writeU32(os, *(u32 *)value);
3764 std::string s = os.str();
3765 SharedBuffer<u8> data((u8 *)s.c_str(), s.size());
3767 m_con.Send(peer_id, 0, data, true);
3770 void Server::SendHUDSetFlags(u16 peer_id, u32 flags, u32 mask)
3772 std::ostringstream os(std::ios_base::binary);
3775 writeU16(os, TOCLIENT_HUD_SET_FLAGS);
3776 writeU32(os, flags);
3780 std::string s = os.str();
3781 SharedBuffer<u8> data((u8 *)s.c_str(), s.size());
3783 m_con.Send(peer_id, 0, data, true);
3786 void Server::SendHUDSetParam(u16 peer_id, u16 param, const std::string &value)
3788 std::ostringstream os(std::ios_base::binary);
3791 writeU16(os, TOCLIENT_HUD_SET_PARAM);
3792 writeU16(os, param);
3793 os<<serializeString(value);
3796 std::string s = os.str();
3797 SharedBuffer<u8> data((u8 *)s.c_str(), s.size());
3799 m_con.Send(peer_id, 0, data, true);
3802 void Server::BroadcastChatMessage(const std::wstring &message)
3804 for(std::map<u16, RemoteClient*>::iterator
3805 i = m_clients.begin();
3806 i != m_clients.end(); ++i)
3808 // Get client and check that it is valid
3809 RemoteClient *client = i->second;
3810 assert(client->peer_id == i->first);
3811 if(client->serialization_version == SER_FMT_VER_INVALID)
3814 SendChatMessage(client->peer_id, message);
3818 void Server::SendPlayerHP(u16 peer_id)
3820 DSTACK(__FUNCTION_NAME);
3821 PlayerSAO *playersao = getPlayerSAO(peer_id);
3823 playersao->m_hp_not_sent = false;
3824 SendHP(m_con, peer_id, playersao->getHP());
3827 void Server::SendPlayerBreath(u16 peer_id)
3829 DSTACK(__FUNCTION_NAME);
3830 PlayerSAO *playersao = getPlayerSAO(peer_id);
3832 playersao->m_breath_not_sent = false;
3833 SendBreath(m_con, peer_id, playersao->getBreath());
3836 void Server::SendMovePlayer(u16 peer_id)
3838 DSTACK(__FUNCTION_NAME);
3839 Player *player = m_env->getPlayer(peer_id);
3842 std::ostringstream os(std::ios_base::binary);
3843 writeU16(os, TOCLIENT_MOVE_PLAYER);
3844 writeV3F1000(os, player->getPosition());
3845 writeF1000(os, player->getPitch());
3846 writeF1000(os, player->getYaw());
3849 v3f pos = player->getPosition();
3850 f32 pitch = player->getPitch();
3851 f32 yaw = player->getYaw();
3852 verbosestream<<"Server: Sending TOCLIENT_MOVE_PLAYER"
3853 <<" pos=("<<pos.X<<","<<pos.Y<<","<<pos.Z<<")"
3860 std::string s = os.str();
3861 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3863 m_con.Send(peer_id, 0, data, true);
3866 void Server::SendPlayerPrivileges(u16 peer_id)
3868 Player *player = m_env->getPlayer(peer_id);
3870 if(player->peer_id == PEER_ID_INEXISTENT)
3873 std::set<std::string> privs;
3874 m_script->getAuth(player->getName(), NULL, &privs);
3876 std::ostringstream os(std::ios_base::binary);
3877 writeU16(os, TOCLIENT_PRIVILEGES);
3878 writeU16(os, privs.size());
3879 for(std::set<std::string>::const_iterator i = privs.begin();
3880 i != privs.end(); i++){
3881 os<<serializeString(*i);
3885 std::string s = os.str();
3886 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3888 m_con.Send(peer_id, 0, data, true);
3891 void Server::SendPlayerInventoryFormspec(u16 peer_id)
3893 Player *player = m_env->getPlayer(peer_id);
3895 if(player->peer_id == PEER_ID_INEXISTENT)
3898 std::ostringstream os(std::ios_base::binary);
3899 writeU16(os, TOCLIENT_INVENTORY_FORMSPEC);
3900 os<<serializeLongString(player->inventory_formspec);
3903 std::string s = os.str();
3904 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3906 m_con.Send(peer_id, 0, data, true);
3909 s32 Server::playSound(const SimpleSoundSpec &spec,
3910 const ServerSoundParams ¶ms)
3912 // Find out initial position of sound
3913 bool pos_exists = false;
3914 v3f pos = params.getPos(m_env, &pos_exists);
3915 // If position is not found while it should be, cancel sound
3916 if(pos_exists != (params.type != ServerSoundParams::SSP_LOCAL))
3918 // Filter destination clients
3919 std::set<RemoteClient*> dst_clients;
3920 if(params.to_player != "")
3922 Player *player = m_env->getPlayer(params.to_player.c_str());
3924 infostream<<"Server::playSound: Player \""<<params.to_player
3925 <<"\" not found"<<std::endl;
3928 if(player->peer_id == PEER_ID_INEXISTENT){
3929 infostream<<"Server::playSound: Player \""<<params.to_player
3930 <<"\" not connected"<<std::endl;
3933 RemoteClient *client = getClient(player->peer_id);
3934 dst_clients.insert(client);
3938 for(std::map<u16, RemoteClient*>::iterator
3939 i = m_clients.begin(); i != m_clients.end(); ++i)
3941 RemoteClient *client = i->second;
3942 Player *player = m_env->getPlayer(client->peer_id);
3946 if(player->getPosition().getDistanceFrom(pos) >
3947 params.max_hear_distance)
3950 dst_clients.insert(client);
3953 if(dst_clients.size() == 0)
3956 s32 id = m_next_sound_id++;
3957 // The sound will exist as a reference in m_playing_sounds
3958 m_playing_sounds[id] = ServerPlayingSound();
3959 ServerPlayingSound &psound = m_playing_sounds[id];
3960 psound.params = params;
3961 for(std::set<RemoteClient*>::iterator i = dst_clients.begin();
3962 i != dst_clients.end(); i++)
3963 psound.clients.insert((*i)->peer_id);
3965 std::ostringstream os(std::ios_base::binary);
3966 writeU16(os, TOCLIENT_PLAY_SOUND);
3968 os<<serializeString(spec.name);
3969 writeF1000(os, spec.gain * params.gain);
3970 writeU8(os, params.type);
3971 writeV3F1000(os, pos);
3972 writeU16(os, params.object);
3973 writeU8(os, params.loop);
3975 std::string s = os.str();
3976 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3978 for(std::set<RemoteClient*>::iterator i = dst_clients.begin();
3979 i != dst_clients.end(); i++){
3981 m_con.Send((*i)->peer_id, 0, data, true);
3985 void Server::stopSound(s32 handle)
3987 // Get sound reference
3988 std::map<s32, ServerPlayingSound>::iterator i =
3989 m_playing_sounds.find(handle);
3990 if(i == m_playing_sounds.end())
3992 ServerPlayingSound &psound = i->second;
3994 std::ostringstream os(std::ios_base::binary);
3995 writeU16(os, TOCLIENT_STOP_SOUND);
3996 writeS32(os, handle);
3998 std::string s = os.str();
3999 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
4001 for(std::set<u16>::iterator i = psound.clients.begin();
4002 i != psound.clients.end(); i++){
4004 m_con.Send(*i, 0, data, true);
4006 // Remove sound reference
4007 m_playing_sounds.erase(i);
4010 void Server::sendRemoveNode(v3s16 p, u16 ignore_id,
4011 std::list<u16> *far_players, float far_d_nodes)
4013 float maxd = far_d_nodes*BS;
4014 v3f p_f = intToFloat(p, BS);
4018 SharedBuffer<u8> reply(replysize);
4019 writeU16(&reply[0], TOCLIENT_REMOVENODE);
4020 writeS16(&reply[2], p.X);
4021 writeS16(&reply[4], p.Y);
4022 writeS16(&reply[6], p.Z);
4024 for(std::map<u16, RemoteClient*>::iterator
4025 i = m_clients.begin();
4026 i != m_clients.end(); ++i)
4028 // Get client and check that it is valid
4029 RemoteClient *client = i->second;
4030 assert(client->peer_id == i->first);
4031 if(client->serialization_version == SER_FMT_VER_INVALID)
4034 // Don't send if it's the same one
4035 if(client->peer_id == ignore_id)
4041 Player *player = m_env->getPlayer(client->peer_id);
4044 // If player is far away, only set modified blocks not sent
4045 v3f player_pos = player->getPosition();
4046 if(player_pos.getDistanceFrom(p_f) > maxd)
4048 far_players->push_back(client->peer_id);
4055 m_con.Send(client->peer_id, 0, reply, true);
4059 void Server::sendAddNode(v3s16 p, MapNode n, u16 ignore_id,
4060 std::list<u16> *far_players, float far_d_nodes)
4062 float maxd = far_d_nodes*BS;
4063 v3f p_f = intToFloat(p, BS);
4065 for(std::map<u16, RemoteClient*>::iterator
4066 i = m_clients.begin();
4067 i != m_clients.end(); ++i)
4069 // Get client and check that it is valid
4070 RemoteClient *client = i->second;
4071 assert(client->peer_id == i->first);
4072 if(client->serialization_version == SER_FMT_VER_INVALID)
4075 // Don't send if it's the same one
4076 if(client->peer_id == ignore_id)
4082 Player *player = m_env->getPlayer(client->peer_id);
4085 // If player is far away, only set modified blocks not sent
4086 v3f player_pos = player->getPosition();
4087 if(player_pos.getDistanceFrom(p_f) > maxd)
4089 far_players->push_back(client->peer_id);
4096 u32 replysize = 8 + MapNode::serializedLength(client->serialization_version);
4097 SharedBuffer<u8> reply(replysize);
4098 writeU16(&reply[0], TOCLIENT_ADDNODE);
4099 writeS16(&reply[2], p.X);
4100 writeS16(&reply[4], p.Y);
4101 writeS16(&reply[6], p.Z);
4102 n.serialize(&reply[8], client->serialization_version);
4105 m_con.Send(client->peer_id, 0, reply, true);
4109 void Server::setBlockNotSent(v3s16 p)
4111 for(std::map<u16, RemoteClient*>::iterator
4112 i = m_clients.begin();
4113 i != m_clients.end(); ++i)
4115 RemoteClient *client = i->second;
4116 client->SetBlockNotSent(p);
4120 void Server::SendBlockNoLock(u16 peer_id, MapBlock *block, u8 ver, u16 net_proto_version)
4122 DSTACK(__FUNCTION_NAME);
4124 v3s16 p = block->getPos();
4128 bool completely_air = true;
4129 for(s16 z0=0; z0<MAP_BLOCKSIZE; z0++)
4130 for(s16 x0=0; x0<MAP_BLOCKSIZE; x0++)
4131 for(s16 y0=0; y0<MAP_BLOCKSIZE; y0++)
4133 if(block->getNodeNoEx(v3s16(x0,y0,z0)).d != CONTENT_AIR)
4135 completely_air = false;
4136 x0 = y0 = z0 = MAP_BLOCKSIZE; // Break out
4141 infostream<<"Server: Sending block ("<<p.X<<","<<p.Y<<","<<p.Z<<"): ";
4143 infostream<<"[completely air] ";
4144 infostream<<std::endl;
4148 Create a packet with the block in the right format
4151 std::ostringstream os(std::ios_base::binary);
4152 block->serialize(os, ver, false);
4153 block->serializeNetworkSpecific(os, net_proto_version);
4154 std::string s = os.str();
4155 SharedBuffer<u8> blockdata((u8*)s.c_str(), s.size());
4157 u32 replysize = 8 + blockdata.getSize();
4158 SharedBuffer<u8> reply(replysize);
4159 writeU16(&reply[0], TOCLIENT_BLOCKDATA);
4160 writeS16(&reply[2], p.X);
4161 writeS16(&reply[4], p.Y);
4162 writeS16(&reply[6], p.Z);
4163 memcpy(&reply[8], *blockdata, blockdata.getSize());
4165 /*infostream<<"Server: Sending block ("<<p.X<<","<<p.Y<<","<<p.Z<<")"
4166 <<": \tpacket size: "<<replysize<<std::endl;*/
4171 m_con.Send(peer_id, 1, reply, true);
4174 void Server::SendBlocks(float dtime)
4176 DSTACK(__FUNCTION_NAME);
4178 JMutexAutoLock envlock(m_env_mutex);
4179 JMutexAutoLock conlock(m_con_mutex);
4181 ScopeProfiler sp(g_profiler, "Server: sel and send blocks to clients");
4183 std::vector<PrioritySortedBlockTransfer> queue;
4185 s32 total_sending = 0;
4188 ScopeProfiler sp(g_profiler, "Server: selecting blocks for sending");
4190 for(std::map<u16, RemoteClient*>::iterator
4191 i = m_clients.begin();
4192 i != m_clients.end(); ++i)
4194 RemoteClient *client = i->second;
4195 assert(client->peer_id == i->first);
4197 // If definitions and textures have not been sent, don't
4198 // send MapBlocks either
4199 if(!client->definitions_sent)
4202 total_sending += client->SendingCount();
4204 if(client->serialization_version == SER_FMT_VER_INVALID)
4207 client->GetNextBlocks(this, dtime, queue);
4212 // Lowest priority number comes first.
4213 // Lowest is most important.
4214 std::sort(queue.begin(), queue.end());
4216 for(u32 i=0; i<queue.size(); i++)
4218 //TODO: Calculate limit dynamically
4219 if(total_sending >= g_settings->getS32
4220 ("max_simultaneous_block_sends_server_total"))
4223 PrioritySortedBlockTransfer q = queue[i];
4225 MapBlock *block = NULL;
4228 block = m_env->getMap().getBlockNoCreate(q.pos);
4230 catch(InvalidPositionException &e)
4235 RemoteClient *client = getClient(q.peer_id);
4237 SendBlockNoLock(q.peer_id, block, client->serialization_version, client->net_proto_version);
4239 client->SentBlock(q.pos);
4245 void Server::fillMediaCache()
4247 DSTACK(__FUNCTION_NAME);
4249 infostream<<"Server: Calculating media file checksums"<<std::endl;
4251 // Collect all media file paths
4252 std::list<std::string> paths;
4253 for(std::vector<ModSpec>::iterator i = m_mods.begin();
4254 i != m_mods.end(); i++){
4255 const ModSpec &mod = *i;
4256 paths.push_back(mod.path + DIR_DELIM + "textures");
4257 paths.push_back(mod.path + DIR_DELIM + "sounds");
4258 paths.push_back(mod.path + DIR_DELIM + "media");
4259 paths.push_back(mod.path + DIR_DELIM + "models");
4261 std::string path_all = "textures";
4262 paths.push_back(path_all + DIR_DELIM + "all");
4264 // Collect media file information from paths into cache
4265 for(std::list<std::string>::iterator i = paths.begin();
4266 i != paths.end(); i++)
4268 std::string mediapath = *i;
4269 std::vector<fs::DirListNode> dirlist = fs::GetDirListing(mediapath);
4270 for(u32 j=0; j<dirlist.size(); j++){
4271 if(dirlist[j].dir) // Ignode dirs
4273 std::string filename = dirlist[j].name;
4274 // If name contains illegal characters, ignore the file
4275 if(!string_allowed(filename, TEXTURENAME_ALLOWED_CHARS)){
4276 infostream<<"Server: ignoring illegal file name: \""
4277 <<filename<<"\""<<std::endl;
4280 // If name is not in a supported format, ignore it
4281 const char *supported_ext[] = {
4282 ".png", ".jpg", ".bmp", ".tga",
4283 ".pcx", ".ppm", ".psd", ".wal", ".rgb",
4285 ".x", ".b3d", ".md2", ".obj",
4288 if(removeStringEnd(filename, supported_ext) == ""){
4289 infostream<<"Server: ignoring unsupported file extension: \""
4290 <<filename<<"\""<<std::endl;
4293 // Ok, attempt to load the file and add to cache
4294 std::string filepath = mediapath + DIR_DELIM + filename;
4296 std::ifstream fis(filepath.c_str(), std::ios_base::binary);
4297 if(fis.good() == false){
4298 errorstream<<"Server::fillMediaCache(): Could not open \""
4299 <<filename<<"\" for reading"<<std::endl;
4302 std::ostringstream tmp_os(std::ios_base::binary);
4306 fis.read(buf, 1024);
4307 std::streamsize len = fis.gcount();
4308 tmp_os.write(buf, len);
4317 errorstream<<"Server::fillMediaCache(): Failed to read \""
4318 <<filename<<"\""<<std::endl;
4321 if(tmp_os.str().length() == 0){
4322 errorstream<<"Server::fillMediaCache(): Empty file \""
4323 <<filepath<<"\""<<std::endl;
4328 sha1.addBytes(tmp_os.str().c_str(), tmp_os.str().length());
4330 unsigned char *digest = sha1.getDigest();
4331 std::string sha1_base64 = base64_encode(digest, 20);
4332 std::string sha1_hex = hex_encode((char*)digest, 20);
4336 this->m_media[filename] = MediaInfo(filepath, sha1_base64);
4337 verbosestream<<"Server: "<<sha1_hex<<" is "<<filename<<std::endl;
4342 struct SendableMediaAnnouncement
4345 std::string sha1_digest;
4347 SendableMediaAnnouncement(const std::string name_="",
4348 const std::string sha1_digest_=""):
4350 sha1_digest(sha1_digest_)
4354 void Server::sendMediaAnnouncement(u16 peer_id)
4356 DSTACK(__FUNCTION_NAME);
4358 verbosestream<<"Server: Announcing files to id("<<peer_id<<")"
4361 std::list<SendableMediaAnnouncement> file_announcements;
4363 for(std::map<std::string, MediaInfo>::iterator i = m_media.begin();
4364 i != m_media.end(); i++){
4366 file_announcements.push_back(
4367 SendableMediaAnnouncement(i->first, i->second.sha1_digest));
4371 std::ostringstream os(std::ios_base::binary);
4379 u16 length of sha1_digest
4384 writeU16(os, TOCLIENT_ANNOUNCE_MEDIA);
4385 writeU16(os, file_announcements.size());
4387 for(std::list<SendableMediaAnnouncement>::iterator
4388 j = file_announcements.begin();
4389 j != file_announcements.end(); ++j){
4390 os<<serializeString(j->name);
4391 os<<serializeString(j->sha1_digest);
4393 os<<serializeString(g_settings->get("remote_media"));
4396 std::string s = os.str();
4397 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
4400 m_con.Send(peer_id, 0, data, true);
4403 struct SendableMedia
4409 SendableMedia(const std::string &name_="", const std::string path_="",
4410 const std::string &data_=""):
4417 void Server::sendRequestedMedia(u16 peer_id,
4418 const std::list<MediaRequest> &tosend)
4420 DSTACK(__FUNCTION_NAME);
4422 verbosestream<<"Server::sendRequestedMedia(): "
4423 <<"Sending files to client"<<std::endl;
4427 // Put 5kB in one bunch (this is not accurate)
4428 u32 bytes_per_bunch = 5000;
4430 std::vector< std::list<SendableMedia> > file_bunches;
4431 file_bunches.push_back(std::list<SendableMedia>());
4433 u32 file_size_bunch_total = 0;
4435 for(std::list<MediaRequest>::const_iterator i = tosend.begin();
4436 i != tosend.end(); ++i)
4438 if(m_media.find(i->name) == m_media.end()){
4439 errorstream<<"Server::sendRequestedMedia(): Client asked for "
4440 <<"unknown file \""<<(i->name)<<"\""<<std::endl;
4444 //TODO get path + name
4445 std::string tpath = m_media[(*i).name].path;
4448 std::ifstream fis(tpath.c_str(), std::ios_base::binary);
4449 if(fis.good() == false){
4450 errorstream<<"Server::sendRequestedMedia(): Could not open \""
4451 <<tpath<<"\" for reading"<<std::endl;
4454 std::ostringstream tmp_os(std::ios_base::binary);
4458 fis.read(buf, 1024);
4459 std::streamsize len = fis.gcount();
4460 tmp_os.write(buf, len);
4461 file_size_bunch_total += len;
4470 errorstream<<"Server::sendRequestedMedia(): Failed to read \""
4471 <<(*i).name<<"\""<<std::endl;
4474 /*infostream<<"Server::sendRequestedMedia(): Loaded \""
4475 <<tname<<"\""<<std::endl;*/
4477 file_bunches[file_bunches.size()-1].push_back(
4478 SendableMedia((*i).name, tpath, tmp_os.str()));
4480 // Start next bunch if got enough data
4481 if(file_size_bunch_total >= bytes_per_bunch){
4482 file_bunches.push_back(std::list<SendableMedia>());
4483 file_size_bunch_total = 0;
4488 /* Create and send packets */
4490 u32 num_bunches = file_bunches.size();
4491 for(u32 i=0; i<num_bunches; i++)
4493 std::ostringstream os(std::ios_base::binary);
4497 u16 total number of texture bunches
4498 u16 index of this bunch
4499 u32 number of files in this bunch
4508 writeU16(os, TOCLIENT_MEDIA);
4509 writeU16(os, num_bunches);
4511 writeU32(os, file_bunches[i].size());
4513 for(std::list<SendableMedia>::iterator
4514 j = file_bunches[i].begin();
4515 j != file_bunches[i].end(); ++j){
4516 os<<serializeString(j->name);
4517 os<<serializeLongString(j->data);
4521 std::string s = os.str();
4522 verbosestream<<"Server::sendRequestedMedia(): bunch "
4523 <<i<<"/"<<num_bunches
4524 <<" files="<<file_bunches[i].size()
4525 <<" size=" <<s.size()<<std::endl;
4526 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
4528 m_con.Send(peer_id, 0, data, true);
4532 void Server::sendDetachedInventory(const std::string &name, u16 peer_id)
4534 if(m_detached_inventories.count(name) == 0){
4535 errorstream<<__FUNCTION_NAME<<": \""<<name<<"\" not found"<<std::endl;
4538 Inventory *inv = m_detached_inventories[name];
4540 std::ostringstream os(std::ios_base::binary);
4541 writeU16(os, TOCLIENT_DETACHED_INVENTORY);
4542 os<<serializeString(name);
4546 std::string s = os.str();
4547 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
4549 m_con.Send(peer_id, 0, data, true);
4552 void Server::sendDetachedInventoryToAll(const std::string &name)
4554 DSTACK(__FUNCTION_NAME);
4556 for(std::map<u16, RemoteClient*>::iterator
4557 i = m_clients.begin();
4558 i != m_clients.end(); ++i){
4559 RemoteClient *client = i->second;
4560 sendDetachedInventory(name, client->peer_id);
4564 void Server::sendDetachedInventories(u16 peer_id)
4566 DSTACK(__FUNCTION_NAME);
4568 for(std::map<std::string, Inventory*>::iterator
4569 i = m_detached_inventories.begin();
4570 i != m_detached_inventories.end(); i++){
4571 const std::string &name = i->first;
4572 //Inventory *inv = i->second;
4573 sendDetachedInventory(name, peer_id);
4581 void Server::DiePlayer(u16 peer_id)
4583 DSTACK(__FUNCTION_NAME);
4585 PlayerSAO *playersao = getPlayerSAO(peer_id);
4588 infostream<<"Server::DiePlayer(): Player "
4589 <<playersao->getPlayer()->getName()
4590 <<" dies"<<std::endl;
4592 playersao->setHP(0);
4594 // Trigger scripted stuff
4595 m_script->on_dieplayer(playersao);
4597 SendPlayerHP(peer_id);
4598 SendDeathscreen(m_con, peer_id, false, v3f(0,0,0));
4601 void Server::RespawnPlayer(u16 peer_id)
4603 DSTACK(__FUNCTION_NAME);
4605 PlayerSAO *playersao = getPlayerSAO(peer_id);
4608 infostream<<"Server::RespawnPlayer(): Player "
4609 <<playersao->getPlayer()->getName()
4610 <<" respawns"<<std::endl;
4612 playersao->setHP(PLAYER_MAX_HP);
4614 bool repositioned = m_script->on_respawnplayer(playersao);
4616 v3f pos = findSpawnPos(m_env->getServerMap());
4617 playersao->setPos(pos);
4621 void Server::UpdateCrafting(u16 peer_id)
4623 DSTACK(__FUNCTION_NAME);
4625 Player* player = m_env->getPlayer(peer_id);
4628 // Get a preview for crafting
4630 getCraftingResult(&player->inventory, preview, false, this);
4632 // Put the new preview in
4633 InventoryList *plist = player->inventory.getList("craftpreview");
4635 assert(plist->getSize() >= 1);
4636 plist->changeItem(0, preview);
4639 RemoteClient* Server::getClient(u16 peer_id)
4641 DSTACK(__FUNCTION_NAME);
4642 //JMutexAutoLock lock(m_con_mutex);
4643 std::map<u16, RemoteClient*>::iterator n;
4644 n = m_clients.find(peer_id);
4645 // A client should exist for all peers
4646 assert(n != m_clients.end());
4650 std::wstring Server::getStatusString()
4652 std::wostringstream os(std::ios_base::binary);
4655 os<<L"version="<<narrow_to_wide(VERSION_STRING);
4657 os<<L", uptime="<<m_uptime.get();
4659 os<<L", max_lag="<<m_env->getMaxLagEstimate();
4660 // Information about clients
4661 std::map<u16, RemoteClient*>::iterator i;
4664 for(i = m_clients.begin(), first = true;
4665 i != m_clients.end(); ++i)
4667 // Get client and check that it is valid
4668 RemoteClient *client = i->second;
4669 assert(client->peer_id == i->first);
4670 if(client->serialization_version == SER_FMT_VER_INVALID)
4673 Player *player = m_env->getPlayer(client->peer_id);
4674 // Get name of player
4675 std::wstring name = L"unknown";
4677 name = narrow_to_wide(player->getName());
4678 // Add name to information string
4686 if(((ServerMap*)(&m_env->getMap()))->isSavingEnabled() == false)
4687 os<<std::endl<<L"# Server: "<<" WARNING: Map saving is disabled.";
4688 if(g_settings->get("motd") != "")
4689 os<<std::endl<<L"# Server: "<<narrow_to_wide(g_settings->get("motd"));
4693 std::set<std::string> Server::getPlayerEffectivePrivs(const std::string &name)
4695 std::set<std::string> privs;
4696 m_script->getAuth(name, NULL, &privs);
4700 bool Server::checkPriv(const std::string &name, const std::string &priv)
4702 std::set<std::string> privs = getPlayerEffectivePrivs(name);
4703 return (privs.count(priv) != 0);
4706 void Server::reportPrivsModified(const std::string &name)
4709 for(std::map<u16, RemoteClient*>::iterator
4710 i = m_clients.begin();
4711 i != m_clients.end(); ++i){
4712 RemoteClient *client = i->second;
4713 Player *player = m_env->getPlayer(client->peer_id);
4714 reportPrivsModified(player->getName());
4717 Player *player = m_env->getPlayer(name.c_str());
4720 SendPlayerPrivileges(player->peer_id);
4721 PlayerSAO *sao = player->getPlayerSAO();
4724 sao->updatePrivileges(
4725 getPlayerEffectivePrivs(name),
4730 void Server::reportInventoryFormspecModified(const std::string &name)
4732 Player *player = m_env->getPlayer(name.c_str());
4735 SendPlayerInventoryFormspec(player->peer_id);
4738 // Saves g_settings to configpath given at initialization
4739 void Server::saveConfig()
4741 if(m_path_config != "")
4742 g_settings->updateConfigFile(m_path_config.c_str());
4745 void Server::notifyPlayer(const char *name, const std::wstring msg, const bool prepend = true)
4747 Player *player = m_env->getPlayer(name);
4751 SendChatMessage(player->peer_id, std::wstring(L"Server -!- ")+msg);
4753 SendChatMessage(player->peer_id, msg);
4756 bool Server::showFormspec(const char *playername, const std::string &formspec, const std::string &formname)
4758 Player *player = m_env->getPlayer(playername);
4762 infostream<<"showFormspec: couldn't find player:"<<playername<<std::endl;
4766 SendShowFormspecMessage(player->peer_id, formspec, formname);
4770 u32 Server::hudAdd(Player *player, HudElement *form) {
4774 u32 id = hud_get_free_id(player);
4775 if (id < player->hud.size())
4776 player->hud[id] = form;
4778 player->hud.push_back(form);
4780 SendHUDAdd(player->peer_id, id, form);
4784 bool Server::hudRemove(Player *player, u32 id) {
4785 if (!player || id >= player->hud.size() || !player->hud[id])
4788 delete player->hud[id];
4789 player->hud[id] = NULL;
4791 SendHUDRemove(player->peer_id, id);
4795 bool Server::hudChange(Player *player, u32 id, HudElementStat stat, void *data) {
4799 SendHUDChange(player->peer_id, id, stat, data);
4803 bool Server::hudSetFlags(Player *player, u32 flags, u32 mask) {
4807 SendHUDSetFlags(player->peer_id, flags, mask);
4811 bool Server::hudSetHotbarItemcount(Player *player, s32 hotbar_itemcount) {
4814 if (hotbar_itemcount <= 0 || hotbar_itemcount > HUD_HOTBAR_ITEMCOUNT_MAX)
4817 std::ostringstream os(std::ios::binary);
4818 writeS32(os, hotbar_itemcount);
4819 SendHUDSetParam(player->peer_id, HUD_PARAM_HOTBAR_ITEMCOUNT, os.str());
4823 void Server::notifyPlayers(const std::wstring msg)
4825 BroadcastChatMessage(msg);
4828 void Server::spawnParticle(const char *playername, v3f pos,
4829 v3f velocity, v3f acceleration,
4830 float expirationtime, float size, bool
4831 collisiondetection, std::string texture)
4833 Player *player = m_env->getPlayer(playername);
4836 SendSpawnParticle(player->peer_id, pos, velocity, acceleration,
4837 expirationtime, size, collisiondetection, texture);
4840 void Server::spawnParticleAll(v3f pos, v3f velocity, v3f acceleration,
4841 float expirationtime, float size,
4842 bool collisiondetection, std::string texture)
4844 SendSpawnParticleAll(pos, velocity, acceleration,
4845 expirationtime, size, collisiondetection, texture);
4848 u32 Server::addParticleSpawner(const char *playername,
4849 u16 amount, float spawntime,
4850 v3f minpos, v3f maxpos,
4851 v3f minvel, v3f maxvel,
4852 v3f minacc, v3f maxacc,
4853 float minexptime, float maxexptime,
4854 float minsize, float maxsize,
4855 bool collisiondetection, std::string texture)
4857 Player *player = m_env->getPlayer(playername);
4862 for(;;) // look for unused particlespawner id
4865 if (std::find(m_particlespawner_ids.begin(),
4866 m_particlespawner_ids.end(), id)
4867 == m_particlespawner_ids.end())
4869 m_particlespawner_ids.push_back(id);
4874 SendAddParticleSpawner(player->peer_id, amount, spawntime,
4875 minpos, maxpos, minvel, maxvel, minacc, maxacc,
4876 minexptime, maxexptime, minsize, maxsize,
4877 collisiondetection, texture, id);
4882 u32 Server::addParticleSpawnerAll(u16 amount, float spawntime,
4883 v3f minpos, v3f maxpos,
4884 v3f minvel, v3f maxvel,
4885 v3f minacc, v3f maxacc,
4886 float minexptime, float maxexptime,
4887 float minsize, float maxsize,
4888 bool collisiondetection, std::string texture)
4891 for(;;) // look for unused particlespawner id
4894 if (std::find(m_particlespawner_ids.begin(),
4895 m_particlespawner_ids.end(), id)
4896 == m_particlespawner_ids.end())
4898 m_particlespawner_ids.push_back(id);
4903 SendAddParticleSpawnerAll(amount, spawntime,
4904 minpos, maxpos, minvel, maxvel, minacc, maxacc,
4905 minexptime, maxexptime, minsize, maxsize,
4906 collisiondetection, texture, id);
4911 void Server::deleteParticleSpawner(const char *playername, u32 id)
4913 Player *player = m_env->getPlayer(playername);
4917 m_particlespawner_ids.erase(
4918 std::remove(m_particlespawner_ids.begin(),
4919 m_particlespawner_ids.end(), id),
4920 m_particlespawner_ids.end());
4921 SendDeleteParticleSpawner(player->peer_id, id);
4924 void Server::deleteParticleSpawnerAll(u32 id)
4926 m_particlespawner_ids.erase(
4927 std::remove(m_particlespawner_ids.begin(),
4928 m_particlespawner_ids.end(), id),
4929 m_particlespawner_ids.end());
4930 SendDeleteParticleSpawnerAll(id);
4933 void Server::queueBlockEmerge(v3s16 blockpos, bool allow_generate)
4935 m_emerge->enqueueBlockEmerge(PEER_ID_INEXISTENT, blockpos, allow_generate);
4938 Inventory* Server::createDetachedInventory(const std::string &name)
4940 if(m_detached_inventories.count(name) > 0){
4941 infostream<<"Server clearing detached inventory \""<<name<<"\""<<std::endl;
4942 delete m_detached_inventories[name];
4944 infostream<<"Server creating detached inventory \""<<name<<"\""<<std::endl;
4946 Inventory *inv = new Inventory(m_itemdef);
4948 m_detached_inventories[name] = inv;
4949 sendDetachedInventoryToAll(name);
4956 BoolScopeSet(bool *dst, bool val):
4959 m_orig_state = *m_dst;
4964 *m_dst = m_orig_state;
4971 // actions: time-reversed list
4972 // Return value: success/failure
4973 bool Server::rollbackRevertActions(const std::list<RollbackAction> &actions,
4974 std::list<std::string> *log)
4976 infostream<<"Server::rollbackRevertActions(len="<<actions.size()<<")"<<std::endl;
4977 ServerMap *map = (ServerMap*)(&m_env->getMap());
4978 // Disable rollback report sink while reverting
4979 BoolScopeSet rollback_scope_disable(&m_rollback_sink_enabled, false);
4981 // Fail if no actions to handle
4982 if(actions.empty()){
4983 log->push_back("Nothing to do.");
4990 for(std::list<RollbackAction>::const_iterator
4991 i = actions.begin();
4992 i != actions.end(); i++)
4994 const RollbackAction &action = *i;
4996 bool success = action.applyRevert(map, this, this);
4999 std::ostringstream os;
5000 os<<"Revert of step ("<<num_tried<<") "<<action.toString()<<" failed";
5001 infostream<<"Map::rollbackRevertActions(): "<<os.str()<<std::endl;
5003 log->push_back(os.str());
5005 std::ostringstream os;
5006 os<<"Successfully reverted step ("<<num_tried<<") "<<action.toString();
5007 infostream<<"Map::rollbackRevertActions(): "<<os.str()<<std::endl;
5009 log->push_back(os.str());
5013 infostream<<"Map::rollbackRevertActions(): "<<num_failed<<"/"<<num_tried
5014 <<" failed"<<std::endl;
5016 // Call it done if less than half failed
5017 return num_failed <= num_tried/2;
5020 // IGameDef interface
5022 IItemDefManager* Server::getItemDefManager()
5026 INodeDefManager* Server::getNodeDefManager()
5030 ICraftDefManager* Server::getCraftDefManager()
5034 ITextureSource* Server::getTextureSource()
5038 IShaderSource* Server::getShaderSource()
5042 u16 Server::allocateUnknownNodeId(const std::string &name)
5044 return m_nodedef->allocateDummy(name);
5046 ISoundManager* Server::getSoundManager()
5048 return &dummySoundManager;
5050 MtEventManager* Server::getEventManager()
5054 IRollbackReportSink* Server::getRollbackReportSink()
5056 if(!m_enable_rollback_recording)
5058 if(!m_rollback_sink_enabled)
5063 IWritableItemDefManager* Server::getWritableItemDefManager()
5067 IWritableNodeDefManager* Server::getWritableNodeDefManager()
5071 IWritableCraftDefManager* Server::getWritableCraftDefManager()
5076 const ModSpec* Server::getModSpec(const std::string &modname)
5078 for(std::vector<ModSpec>::iterator i = m_mods.begin();
5079 i != m_mods.end(); i++){
5080 const ModSpec &mod = *i;
5081 if(mod.name == modname)
5086 void Server::getModNames(std::list<std::string> &modlist)
5088 for(std::vector<ModSpec>::iterator i = m_mods.begin(); i != m_mods.end(); i++)
5090 modlist.push_back(i->name);
5093 std::string Server::getBuiltinLuaPath()
5095 return porting::path_share + DIR_DELIM + "builtin";
5098 v3f findSpawnPos(ServerMap &map)
5100 //return v3f(50,50,50)*BS;
5105 nodepos = v2s16(0,0);
5110 s16 water_level = map.m_mgparams->water_level;
5112 // Try to find a good place a few times
5113 for(s32 i=0; i<1000; i++)
5116 // We're going to try to throw the player to this position
5117 v2s16 nodepos2d = v2s16(
5118 -range + (myrand() % (range * 2)),
5119 -range + (myrand() % (range * 2)));
5121 // Get ground height at point
5122 s16 groundheight = map.findGroundLevel(nodepos2d);
5123 if (groundheight <= water_level) // Don't go underwater
5125 if (groundheight > water_level + 6) // Don't go to high places
5128 nodepos = v3s16(nodepos2d.X, groundheight, nodepos2d.Y);
5129 bool is_good = false;
5131 for (s32 i = 0; i < 10; i++) {
5132 v3s16 blockpos = getNodeBlockPos(nodepos);
5133 map.emergeBlock(blockpos, true);
5134 content_t c = map.getNodeNoEx(nodepos).getContent();
5135 if (c == CONTENT_AIR || c == CONTENT_IGNORE) {
5137 if (air_count >= 2){
5145 // Found a good place
5146 //infostream<<"Searched through "<<i<<" places."<<std::endl;
5152 return intToFloat(nodepos, BS);
5155 PlayerSAO* Server::emergePlayer(const char *name, u16 peer_id)
5157 RemotePlayer *player = NULL;
5158 bool newplayer = false;
5161 Try to get an existing player
5163 player = static_cast<RemotePlayer*>(m_env->getPlayer(name));
5165 // If player is already connected, cancel
5166 if(player != NULL && player->peer_id != 0)
5168 infostream<<"emergePlayer(): Player already connected"<<std::endl;
5173 If player with the wanted peer_id already exists, cancel.
5175 if(m_env->getPlayer(peer_id) != NULL)
5177 infostream<<"emergePlayer(): Player with wrong name but same"
5178 " peer_id already exists"<<std::endl;
5183 Create a new player if it doesn't exist yet
5188 player = new RemotePlayer(this);
5189 player->updateName(name);
5191 /* Set player position */
5192 infostream<<"Server: Finding spawn place for player \""
5193 <<name<<"\""<<std::endl;
5194 v3f pos = findSpawnPos(m_env->getServerMap());
5195 player->setPosition(pos);
5197 /* Add player to environment */
5198 m_env->addPlayer(player);
5202 Create a new player active object
5204 PlayerSAO *playersao = new PlayerSAO(m_env, player, peer_id,
5205 getPlayerEffectivePrivs(player->getName()),
5208 /* Clean up old HUD elements from previous sessions */
5209 player->hud.clear();
5211 /* Add object to environment */
5212 m_env->addActiveObject(playersao);
5216 m_script->on_newplayer(playersao);
5218 m_script->on_joinplayer(playersao);
5223 void Server::handlePeerChange(PeerChange &c)
5225 JMutexAutoLock envlock(m_env_mutex);
5226 JMutexAutoLock conlock(m_con_mutex);
5228 if(c.type == PEER_ADDED)
5235 std::map<u16, RemoteClient*>::iterator n;
5236 n = m_clients.find(c.peer_id);
5237 // The client shouldn't already exist
5238 assert(n == m_clients.end());
5241 RemoteClient *client = new RemoteClient();
5242 client->peer_id = c.peer_id;
5243 m_clients[client->peer_id] = client;
5246 else if(c.type == PEER_REMOVED)
5253 std::map<u16, RemoteClient*>::iterator n;
5254 n = m_clients.find(c.peer_id);
5255 // The client should exist
5256 assert(n != m_clients.end());
5259 Mark objects to be not known by the client
5261 RemoteClient *client = n->second;
5263 for(std::set<u16>::iterator
5264 i = client->m_known_objects.begin();
5265 i != client->m_known_objects.end(); ++i)
5269 ServerActiveObject* obj = m_env->getActiveObject(id);
5271 if(obj && obj->m_known_by_count > 0)
5272 obj->m_known_by_count--;
5276 Clear references to playing sounds
5278 for(std::map<s32, ServerPlayingSound>::iterator
5279 i = m_playing_sounds.begin();
5280 i != m_playing_sounds.end();)
5282 ServerPlayingSound &psound = i->second;
5283 psound.clients.erase(c.peer_id);
5284 if(psound.clients.size() == 0)
5285 m_playing_sounds.erase(i++);
5290 Player *player = m_env->getPlayer(c.peer_id);
5292 // Collect information about leaving in chat
5293 std::wstring message;
5297 std::wstring name = narrow_to_wide(player->getName());
5300 message += L" left the game.";
5302 message += L" (timed out)";
5306 /* Run scripts and remove from environment */
5310 PlayerSAO *playersao = player->getPlayerSAO();
5313 m_script->on_leaveplayer(playersao);
5315 playersao->disconnected();
5325 std::ostringstream os(std::ios_base::binary);
5326 for(std::map<u16, RemoteClient*>::iterator
5327 i = m_clients.begin();
5328 i != m_clients.end(); ++i)
5330 RemoteClient *client = i->second;
5331 assert(client->peer_id == i->first);
5332 if(client->serialization_version == SER_FMT_VER_INVALID)
5335 Player *player = m_env->getPlayer(client->peer_id);
5338 // Get name of player
5339 os<<player->getName()<<" ";
5342 actionstream<<player->getName()<<" "
5343 <<(c.timeout?"times out.":"leaves game.")
5344 <<" List of players: "
5345 <<os.str()<<std::endl;
5350 delete m_clients[c.peer_id];
5351 m_clients.erase(c.peer_id);
5353 // Send player info to all remaining clients
5354 //SendPlayerInfos();
5356 // Send leave chat message to all remaining clients
5357 if(message.length() != 0)
5358 BroadcastChatMessage(message);
5367 void Server::handlePeerChanges()
5369 while(m_peer_change_queue.size() > 0)
5371 PeerChange c = m_peer_change_queue.pop_front();
5373 verbosestream<<"Server: Handling peer change: "
5374 <<"id="<<c.peer_id<<", timeout="<<c.timeout
5377 handlePeerChange(c);
5381 void dedicated_server_loop(Server &server, bool &kill)
5383 DSTACK(__FUNCTION_NAME);
5385 verbosestream<<"dedicated_server_loop()"<<std::endl;
5387 IntervalLimiter m_profiler_interval;
5391 float steplen = g_settings->getFloat("dedicated_server_step");
5392 // This is kind of a hack but can be done like this
5393 // because server.step() is very light
5395 ScopeProfiler sp(g_profiler, "dedicated server sleep");
5396 sleep_ms((int)(steplen*1000.0));
5398 server.step(steplen);
5400 if(server.getShutdownRequested() || kill)
5402 infostream<<"Dedicated server quitting"<<std::endl;
5404 if(g_settings->getBool("server_announce") == true)
5405 ServerList::sendAnnounce("delete");
5413 float profiler_print_interval =
5414 g_settings->getFloat("profiler_print_interval");
5415 if(profiler_print_interval != 0)
5417 if(m_profiler_interval.step(steplen, profiler_print_interval))
5419 infostream<<"Profiler:"<<std::endl;
5420 g_profiler->print(infostream);
5421 g_profiler->clear();