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.
23 #include "clientserver.h"
25 #include "jmutexautolock.h"
27 #include "constants.h"
32 #include "serverobject.h"
37 #include "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, this),
643 m_banmanager(path_world+DIR_DELIM+"ipban.txt"),
645 m_rollback_sink_enabled(true),
646 m_enable_rollback_recording(false),
650 m_itemdef(createItemDefManager()),
651 m_nodedef(createNodeDefManager()),
652 m_craftdef(createCraftDefManager()),
653 m_event(new EventManager()),
655 //m_emergethread(this),
656 m_time_of_day_send_timer(0),
658 m_shutdown_requested(false),
659 m_ignore_map_edit_events(false),
660 m_ignore_map_edit_events_peer_id(0)
662 m_liquid_transform_timer = 0.0;
663 m_liquid_transform_every = 1.0;
664 m_print_info_timer = 0.0;
665 m_masterserver_timer = 0.0;
666 m_objectdata_timer = 0.0;
667 m_emergethread_trigger_timer = 0.0;
668 m_savemap_timer = 0.0;
669 m_clients_number = 0;
673 m_step_dtime_mutex.Init();
677 throw ServerError("Supplied empty world path");
679 if(!gamespec.isValid())
680 throw ServerError("Supplied invalid gamespec");
682 infostream<<"Server created for gameid \""<<m_gamespec.id<<"\"";
683 if(m_simple_singleplayer_mode)
684 infostream<<" in simple singleplayer mode"<<std::endl;
686 infostream<<std::endl;
687 infostream<<"- world: "<<m_path_world<<std::endl;
688 infostream<<"- config: "<<m_path_config<<std::endl;
689 infostream<<"- game: "<<m_gamespec.path<<std::endl;
691 // Initialize default settings and override defaults with those provided
693 set_default_settings(g_settings);
694 Settings gamedefaults;
695 getGameMinetestConfig(gamespec.path, gamedefaults);
696 override_default_settings(g_settings, &gamedefaults);
698 // Create biome definition manager
699 m_biomedef = new BiomeDefManager(this);
701 // Create rollback manager
702 std::string rollback_path = m_path_world+DIR_DELIM+"rollback.txt";
703 m_rollback = createRollbackManager(rollback_path, this);
705 // Create world if it doesn't exist
706 if(!initializeWorld(m_path_world, m_gamespec.id))
707 throw ServerError("Failed to initialize world");
709 ModConfiguration modconf(m_path_world);
710 m_mods = modconf.getMods();
711 std::list<ModSpec> unsatisfied_mods = modconf.getUnsatisfiedMods();
712 // complain about mods with unsatisfied dependencies
713 if(!modconf.isConsistent())
715 for(std::list<ModSpec>::iterator it = unsatisfied_mods.begin();
716 it != unsatisfied_mods.end(); ++it)
719 errorstream << "mod \"" << mod.name << "\" has unsatisfied dependencies: ";
720 for(std::set<std::string>::iterator dep_it = mod.unsatisfied_depends.begin();
721 dep_it != mod.unsatisfied_depends.end(); ++dep_it)
722 errorstream << " \"" << *dep_it << "\"";
723 errorstream << std::endl;
727 Settings worldmt_settings;
728 std::string worldmt = m_path_world + DIR_DELIM + "world.mt";
729 worldmt_settings.readConfigFile(worldmt.c_str());
730 std::vector<std::string> names = worldmt_settings.getNames();
731 std::set<std::string> exclude_mod_names;
732 std::set<std::string> load_mod_names;
733 for(std::vector<std::string>::iterator it = names.begin();
734 it != names.end(); ++it)
736 std::string name = *it;
737 if (name.compare(0,9,"load_mod_")==0)
739 if(worldmt_settings.getBool(name))
740 load_mod_names.insert(name.substr(9));
742 exclude_mod_names.insert(name.substr(9));
745 // complain about mods declared to be loaded, but not found
746 for(std::vector<ModSpec>::iterator it = m_mods.begin();
747 it != m_mods.end(); ++it)
748 load_mod_names.erase((*it).name);
749 for(std::list<ModSpec>::iterator it = unsatisfied_mods.begin();
750 it != unsatisfied_mods.end(); ++it)
751 load_mod_names.erase((*it).name);
752 if(!load_mod_names.empty())
754 errorstream << "The following mods could not be found:";
755 for(std::set<std::string>::iterator it = load_mod_names.begin();
756 it != load_mod_names.end(); ++it)
757 errorstream << " \"" << (*it) << "\"";
758 errorstream << std::endl;
761 // Path to builtin.lua
762 std::string builtinpath = getBuiltinLuaPath() + DIR_DELIM + "builtin.lua";
765 JMutexAutoLock envlock(m_env_mutex);
766 JMutexAutoLock conlock(m_con_mutex);
768 // Initialize scripting
770 infostream<<"Server: Initializing Lua"<<std::endl;
771 m_lua = script_init();
774 scriptapi_export(m_lua, this);
775 // Load and run builtin.lua
776 infostream<<"Server: Loading builtin.lua [\""
777 <<builtinpath<<"\"]"<<std::endl;
778 bool success = scriptapi_loadmod(m_lua, builtinpath, "__builtin");
780 errorstream<<"Server: Failed to load and run "
781 <<builtinpath<<std::endl;
782 throw ModError("Failed to load and run "+builtinpath);
785 infostream<<"Server: Loading mods: ";
786 for(std::vector<ModSpec>::iterator i = m_mods.begin();
787 i != m_mods.end(); i++){
788 const ModSpec &mod = *i;
789 infostream<<mod.name<<" ";
791 infostream<<std::endl;
792 // Load and run "mod" scripts
793 for(std::vector<ModSpec>::iterator i = m_mods.begin();
794 i != m_mods.end(); i++){
795 const ModSpec &mod = *i;
796 std::string scriptpath = mod.path + DIR_DELIM + "init.lua";
797 infostream<<" ["<<padStringRight(mod.name, 12)<<"] [\""
798 <<scriptpath<<"\"]"<<std::endl;
799 bool success = scriptapi_loadmod(m_lua, scriptpath, mod.name);
801 errorstream<<"Server: Failed to load and run "
802 <<scriptpath<<std::endl;
803 throw ModError("Failed to load and run "+scriptpath);
807 // Read Textures and calculate sha1 sums
810 // Apply item aliases in the node definition manager
811 m_nodedef->updateAliases(m_itemdef);
813 // Add default biomes after nodedef had its aliases added
814 m_biomedef->addDefaultBiomes();
816 // Create emerge manager
817 m_emerge = new EmergeManager(this, m_biomedef);
819 // Initialize Environment
820 ServerMap *servermap = new ServerMap(path_world, this, m_emerge);
821 m_env = new ServerEnvironment(servermap, m_lua, this, this);
823 m_emerge->initMapgens(servermap->getMapgenParams());
825 // Give environment reference to scripting api
826 scriptapi_add_environment(m_lua, m_env);
828 // Register us to receive map edit events
829 servermap->addEventReceiver(this);
831 // If file exists, load environment metadata
832 if(fs::PathExists(m_path_world+DIR_DELIM+"env_meta.txt"))
834 infostream<<"Server: Loading environment metadata"<<std::endl;
835 m_env->loadMeta(m_path_world);
839 infostream<<"Server: Loading players"<<std::endl;
840 m_env->deSerializePlayers(m_path_world);
843 Add some test ActiveBlockModifiers to environment
845 add_legacy_abms(m_env, m_nodedef);
847 m_liquid_transform_every = g_settings->getFloat("liquid_update");
852 infostream<<"Server destructing"<<std::endl;
855 Send shutdown message
858 JMutexAutoLock conlock(m_con_mutex);
860 std::wstring line = L"*** Server shutting down";
863 Send the message to clients
865 for(std::map<u16, RemoteClient*>::iterator
866 i = m_clients.begin();
867 i != m_clients.end(); ++i)
869 // Get client and check that it is valid
870 RemoteClient *client = i->second;
871 assert(client->peer_id == i->first);
872 if(client->serialization_version == SER_FMT_VER_INVALID)
876 SendChatMessage(client->peer_id, line);
878 catch(con::PeerNotFoundException &e)
884 JMutexAutoLock envlock(m_env_mutex);
885 JMutexAutoLock conlock(m_con_mutex);
888 Execute script shutdown hooks
890 scriptapi_on_shutdown(m_lua);
894 JMutexAutoLock envlock(m_env_mutex);
899 infostream<<"Server: Saving players"<<std::endl;
900 m_env->serializePlayers(m_path_world);
903 Save environment metadata
905 infostream<<"Server: Saving environment metadata"<<std::endl;
906 m_env->saveMeta(m_path_world);
918 JMutexAutoLock clientslock(m_con_mutex);
920 for(std::map<u16, RemoteClient*>::iterator
921 i = m_clients.begin();
922 i != m_clients.end(); ++i)
930 // Delete things in the reverse order of creation
939 // Deinitialize scripting
940 infostream<<"Server: Deinitializing scripting"<<std::endl;
941 script_deinit(m_lua);
943 // Delete detached inventories
945 for(std::map<std::string, Inventory*>::iterator
946 i = m_detached_inventories.begin();
947 i != m_detached_inventories.end(); i++){
953 void Server::start(unsigned short port)
955 DSTACK(__FUNCTION_NAME);
956 infostream<<"Starting server on port "<<port<<"..."<<std::endl;
958 // Stop thread if already running
961 // Initialize connection
962 m_con.SetTimeoutMs(30);
966 m_thread.setRun(true);
969 // ASCII art for the win!
971 <<" .__ __ __ "<<std::endl
972 <<" _____ |__| ____ _____/ |_ ____ _______/ |_ "<<std::endl
973 <<" / \\| |/ \\_/ __ \\ __\\/ __ \\ / ___/\\ __\\"<<std::endl
974 <<"| Y Y \\ | | \\ ___/| | \\ ___/ \\___ \\ | | "<<std::endl
975 <<"|__|_| /__|___| /\\___ >__| \\___ >____ > |__| "<<std::endl
976 <<" \\/ \\/ \\/ \\/ \\/ "<<std::endl;
977 actionstream<<"World at ["<<m_path_world<<"]"<<std::endl;
978 actionstream<<"Server for gameid=\""<<m_gamespec.id
979 <<"\" listening on port "<<port<<"."<<std::endl;
984 DSTACK(__FUNCTION_NAME);
986 infostream<<"Server: Stopping and waiting threads"<<std::endl;
988 // Stop threads (set run=false first so both start stopping)
989 m_thread.setRun(false);
990 //m_emergethread.setRun(false);
992 //m_emergethread.stop();
994 infostream<<"Server: Threads stopped"<<std::endl;
997 void Server::step(float dtime)
999 DSTACK(__FUNCTION_NAME);
1004 JMutexAutoLock lock(m_step_dtime_mutex);
1005 m_step_dtime += dtime;
1007 // Throw if fatal error occurred in thread
1008 std::string async_err = m_async_fatal_error.get();
1009 if(async_err != ""){
1010 throw ServerError(async_err);
1014 void Server::AsyncRunStep()
1016 DSTACK(__FUNCTION_NAME);
1018 g_profiler->add("Server::AsyncRunStep (num)", 1);
1022 JMutexAutoLock lock1(m_step_dtime_mutex);
1023 dtime = m_step_dtime;
1027 // Send blocks to clients
1034 g_profiler->add("Server::AsyncRunStep with dtime (num)", 1);
1036 //infostream<<"Server steps "<<dtime<<std::endl;
1037 //infostream<<"Server::AsyncRunStep(): dtime="<<dtime<<std::endl;
1040 JMutexAutoLock lock1(m_step_dtime_mutex);
1041 m_step_dtime -= dtime;
1048 m_uptime.set(m_uptime.get() + dtime);
1052 // Process connection's timeouts
1053 JMutexAutoLock lock2(m_con_mutex);
1054 ScopeProfiler sp(g_profiler, "Server: connection timeout processing");
1055 m_con.RunTimeouts(dtime);
1059 // This has to be called so that the client list gets synced
1060 // with the peer list of the connection
1061 handlePeerChanges();
1065 Update time of day and overall game time
1068 JMutexAutoLock envlock(m_env_mutex);
1070 m_env->setTimeOfDaySpeed(g_settings->getFloat("time_speed"));
1073 Send to clients at constant intervals
1076 m_time_of_day_send_timer -= dtime;
1077 if(m_time_of_day_send_timer < 0.0)
1079 m_time_of_day_send_timer = g_settings->getFloat("time_send_interval");
1081 //JMutexAutoLock envlock(m_env_mutex);
1082 JMutexAutoLock conlock(m_con_mutex);
1084 for(std::map<u16, RemoteClient*>::iterator
1085 i = m_clients.begin();
1086 i != m_clients.end(); ++i)
1088 RemoteClient *client = i->second;
1089 SharedBuffer<u8> data = makePacket_TOCLIENT_TIME_OF_DAY(
1090 m_env->getTimeOfDay(), g_settings->getFloat("time_speed"));
1092 m_con.Send(client->peer_id, 0, data, true);
1098 JMutexAutoLock lock(m_env_mutex);
1100 ScopeProfiler sp(g_profiler, "SEnv step");
1101 ScopeProfiler sp2(g_profiler, "SEnv step avg", SPT_AVG);
1105 const float map_timer_and_unload_dtime = 2.92;
1106 if(m_map_timer_and_unload_interval.step(dtime, map_timer_and_unload_dtime))
1108 JMutexAutoLock lock(m_env_mutex);
1109 // Run Map's timers and unload unused data
1110 ScopeProfiler sp(g_profiler, "Server: map timer and unload");
1111 m_env->getMap().timerUpdate(map_timer_and_unload_dtime,
1112 g_settings->getFloat("server_unload_unused_data_timeout"));
1123 JMutexAutoLock lock(m_env_mutex);
1124 JMutexAutoLock lock2(m_con_mutex);
1126 ScopeProfiler sp(g_profiler, "Server: handle players");
1128 for(std::map<u16, RemoteClient*>::iterator
1129 i = m_clients.begin();
1130 i != m_clients.end(); ++i)
1132 RemoteClient *client = i->second;
1133 PlayerSAO *playersao = getPlayerSAO(client->peer_id);
1134 if(playersao == NULL)
1138 Handle player HPs (die if hp=0)
1140 if(playersao->m_hp_not_sent && g_settings->getBool("enable_damage"))
1142 if(playersao->getHP() == 0)
1143 DiePlayer(client->peer_id);
1145 SendPlayerHP(client->peer_id);
1149 Send player inventories if necessary
1151 if(playersao->m_moved){
1152 SendMovePlayer(client->peer_id);
1153 playersao->m_moved = false;
1155 if(playersao->m_inventory_not_sent){
1156 UpdateCrafting(client->peer_id);
1157 SendInventory(client->peer_id);
1162 /* Transform liquids */
1163 m_liquid_transform_timer += dtime;
1164 if(m_liquid_transform_timer >= m_liquid_transform_every)
1166 m_liquid_transform_timer -= m_liquid_transform_every;
1168 JMutexAutoLock lock(m_env_mutex);
1170 ScopeProfiler sp(g_profiler, "Server: liquid transform");
1172 std::map<v3s16, MapBlock*> modified_blocks;
1173 m_env->getMap().transformLiquids(modified_blocks);
1178 core::map<v3s16, MapBlock*> lighting_modified_blocks;
1179 ServerMap &map = ((ServerMap&)m_env->getMap());
1180 map.updateLighting(modified_blocks, lighting_modified_blocks);
1182 // Add blocks modified by lighting to modified_blocks
1183 for(core::map<v3s16, MapBlock*>::Iterator
1184 i = lighting_modified_blocks.getIterator();
1185 i.atEnd() == false; i++)
1187 MapBlock *block = i.getNode()->getValue();
1188 modified_blocks.insert(block->getPos(), block);
1192 Set the modified blocks unsent for all the clients
1195 JMutexAutoLock lock2(m_con_mutex);
1197 for(std::map<u16, RemoteClient*>::iterator
1198 i = m_clients.begin();
1199 i != m_clients.end(); ++i)
1201 RemoteClient *client = i->second;
1203 if(modified_blocks.size() > 0)
1205 // Remove block from sent history
1206 client->SetBlocksNotSent(modified_blocks);
1211 // Periodically print some info
1213 float &counter = m_print_info_timer;
1219 JMutexAutoLock lock2(m_con_mutex);
1220 m_clients_number = 0;
1221 if(m_clients.size() != 0)
1222 infostream<<"Players:"<<std::endl;
1223 for(std::map<u16, RemoteClient*>::iterator
1224 i = m_clients.begin();
1225 i != m_clients.end(); ++i)
1227 //u16 peer_id = i.getNode()->getKey();
1228 RemoteClient *client = i->second;
1229 Player *player = m_env->getPlayer(client->peer_id);
1232 infostream<<"* "<<player->getName()<<"\t";
1233 client->PrintInfo(infostream);
1241 // send masterserver announce
1243 float &counter = m_masterserver_timer;
1244 if((!counter || counter >= 300.0) && g_settings->getBool("server_announce") == true)
1246 ServerList::sendAnnounce(!counter ? "start" : "update", m_clients_number);
1253 //if(g_settings->getBool("enable_experimental"))
1257 Check added and deleted active objects
1260 //infostream<<"Server: Checking added and deleted active objects"<<std::endl;
1261 JMutexAutoLock envlock(m_env_mutex);
1262 JMutexAutoLock conlock(m_con_mutex);
1264 ScopeProfiler sp(g_profiler, "Server: checking added and deleted objs");
1266 // Radius inside which objects are active
1267 s16 radius = g_settings->getS16("active_object_send_range_blocks");
1268 radius *= MAP_BLOCKSIZE;
1270 for(std::map<u16, RemoteClient*>::iterator
1271 i = m_clients.begin();
1272 i != m_clients.end(); ++i)
1274 RemoteClient *client = i->second;
1276 // If definitions and textures have not been sent, don't
1277 // send objects either
1278 if(!client->definitions_sent)
1281 Player *player = m_env->getPlayer(client->peer_id);
1284 // This can happen if the client timeouts somehow
1285 /*infostream<<"WARNING: "<<__FUNCTION_NAME<<": Client "
1287 <<" has no associated player"<<std::endl;*/
1290 v3s16 pos = floatToInt(player->getPosition(), BS);
1292 std::set<u16> removed_objects;
1293 std::set<u16> added_objects;
1294 m_env->getRemovedActiveObjects(pos, radius,
1295 client->m_known_objects, removed_objects);
1296 m_env->getAddedActiveObjects(pos, radius,
1297 client->m_known_objects, added_objects);
1299 // Ignore if nothing happened
1300 if(removed_objects.size() == 0 && added_objects.size() == 0)
1302 //infostream<<"active objects: none changed"<<std::endl;
1306 std::string data_buffer;
1310 // Handle removed objects
1311 writeU16((u8*)buf, removed_objects.size());
1312 data_buffer.append(buf, 2);
1313 for(std::set<u16>::iterator
1314 i = removed_objects.begin();
1315 i != removed_objects.end(); ++i)
1319 ServerActiveObject* obj = m_env->getActiveObject(id);
1321 // Add to data buffer for sending
1322 writeU16((u8*)buf, id);
1323 data_buffer.append(buf, 2);
1325 // Remove from known objects
1326 client->m_known_objects.erase(id);
1328 if(obj && obj->m_known_by_count > 0)
1329 obj->m_known_by_count--;
1332 // Handle added objects
1333 writeU16((u8*)buf, added_objects.size());
1334 data_buffer.append(buf, 2);
1335 for(std::set<u16>::iterator
1336 i = added_objects.begin();
1337 i != added_objects.end(); ++i)
1341 ServerActiveObject* obj = m_env->getActiveObject(id);
1344 u8 type = ACTIVEOBJECT_TYPE_INVALID;
1346 infostream<<"WARNING: "<<__FUNCTION_NAME
1347 <<": NULL object"<<std::endl;
1349 type = obj->getSendType();
1351 // Add to data buffer for sending
1352 writeU16((u8*)buf, id);
1353 data_buffer.append(buf, 2);
1354 writeU8((u8*)buf, type);
1355 data_buffer.append(buf, 1);
1358 data_buffer.append(serializeLongString(
1359 obj->getClientInitializationData(client->net_proto_version)));
1361 data_buffer.append(serializeLongString(""));
1363 // Add to known objects
1364 client->m_known_objects.insert(id);
1367 obj->m_known_by_count++;
1371 SharedBuffer<u8> reply(2 + data_buffer.size());
1372 writeU16(&reply[0], TOCLIENT_ACTIVE_OBJECT_REMOVE_ADD);
1373 memcpy((char*)&reply[2], data_buffer.c_str(),
1374 data_buffer.size());
1376 m_con.Send(client->peer_id, 0, reply, true);
1378 verbosestream<<"Server: Sent object remove/add: "
1379 <<removed_objects.size()<<" removed, "
1380 <<added_objects.size()<<" added, "
1381 <<"packet size is "<<reply.getSize()<<std::endl;
1386 Collect a list of all the objects known by the clients
1387 and report it back to the environment.
1390 core::map<u16, bool> all_known_objects;
1392 for(core::map<u16, RemoteClient*>::Iterator
1393 i = m_clients.getIterator();
1394 i.atEnd() == false; i++)
1396 RemoteClient *client = i.getNode()->getValue();
1397 // Go through all known objects of client
1398 for(core::map<u16, bool>::Iterator
1399 i = client->m_known_objects.getIterator();
1400 i.atEnd()==false; i++)
1402 u16 id = i.getNode()->getKey();
1403 all_known_objects[id] = true;
1407 m_env->setKnownActiveObjects(whatever);
1413 Send object messages
1416 JMutexAutoLock envlock(m_env_mutex);
1417 JMutexAutoLock conlock(m_con_mutex);
1419 ScopeProfiler sp(g_profiler, "Server: sending object messages");
1422 // Value = data sent by object
1423 std::map<u16, std::list<ActiveObjectMessage>* > buffered_messages;
1425 // Get active object messages from environment
1428 ActiveObjectMessage aom = m_env->getActiveObjectMessage();
1432 std::list<ActiveObjectMessage>* message_list = NULL;
1433 std::map<u16, std::list<ActiveObjectMessage>* >::iterator n;
1434 n = buffered_messages.find(aom.id);
1435 if(n == buffered_messages.end())
1437 message_list = new std::list<ActiveObjectMessage>;
1438 buffered_messages[aom.id] = message_list;
1442 message_list = n->second;
1444 message_list->push_back(aom);
1447 // Route data to every client
1448 for(std::map<u16, RemoteClient*>::iterator
1449 i = m_clients.begin();
1450 i != m_clients.end(); ++i)
1452 RemoteClient *client = i->second;
1453 std::string reliable_data;
1454 std::string unreliable_data;
1455 // Go through all objects in message buffer
1456 for(std::map<u16, std::list<ActiveObjectMessage>* >::iterator
1457 j = buffered_messages.begin();
1458 j != buffered_messages.end(); ++j)
1460 // If object is not known by client, skip it
1462 if(client->m_known_objects.find(id) == client->m_known_objects.end())
1464 // Get message list of object
1465 std::list<ActiveObjectMessage>* list = j->second;
1466 // Go through every message
1467 for(std::list<ActiveObjectMessage>::iterator
1468 k = list->begin(); k != list->end(); ++k)
1470 // Compose the full new data with header
1471 ActiveObjectMessage aom = *k;
1472 std::string new_data;
1475 writeU16((u8*)&buf[0], aom.id);
1476 new_data.append(buf, 2);
1478 new_data += serializeString(aom.datastring);
1479 // Add data to buffer
1481 reliable_data += new_data;
1483 unreliable_data += new_data;
1487 reliable_data and unreliable_data are now ready.
1490 if(reliable_data.size() > 0)
1492 SharedBuffer<u8> reply(2 + reliable_data.size());
1493 writeU16(&reply[0], TOCLIENT_ACTIVE_OBJECT_MESSAGES);
1494 memcpy((char*)&reply[2], reliable_data.c_str(),
1495 reliable_data.size());
1497 m_con.Send(client->peer_id, 0, reply, true);
1499 if(unreliable_data.size() > 0)
1501 SharedBuffer<u8> reply(2 + unreliable_data.size());
1502 writeU16(&reply[0], TOCLIENT_ACTIVE_OBJECT_MESSAGES);
1503 memcpy((char*)&reply[2], unreliable_data.c_str(),
1504 unreliable_data.size());
1505 // Send as unreliable
1506 m_con.Send(client->peer_id, 0, reply, false);
1509 /*if(reliable_data.size() > 0 || unreliable_data.size() > 0)
1511 infostream<<"Server: Size of object message data: "
1512 <<"reliable: "<<reliable_data.size()
1513 <<", unreliable: "<<unreliable_data.size()
1518 // Clear buffered_messages
1519 for(std::map<u16, std::list<ActiveObjectMessage>* >::iterator
1520 i = buffered_messages.begin();
1521 i != buffered_messages.end(); ++i)
1527 } // enable_experimental
1530 Send queued-for-sending map edit events.
1533 // We will be accessing the environment and the connection
1534 JMutexAutoLock lock(m_env_mutex);
1535 JMutexAutoLock conlock(m_con_mutex);
1537 // Don't send too many at a time
1540 // Single change sending is disabled if queue size is not small
1541 bool disable_single_change_sending = false;
1542 if(m_unsent_map_edit_queue.size() >= 4)
1543 disable_single_change_sending = true;
1545 int event_count = m_unsent_map_edit_queue.size();
1547 // We'll log the amount of each
1550 while(m_unsent_map_edit_queue.size() != 0)
1552 MapEditEvent* event = m_unsent_map_edit_queue.pop_front();
1554 // Players far away from the change are stored here.
1555 // Instead of sending the changes, MapBlocks are set not sent
1557 std::list<u16> far_players;
1559 if(event->type == MEET_ADDNODE)
1561 //infostream<<"Server: MEET_ADDNODE"<<std::endl;
1562 prof.add("MEET_ADDNODE", 1);
1563 if(disable_single_change_sending)
1564 sendAddNode(event->p, event->n, event->already_known_by_peer,
1567 sendAddNode(event->p, event->n, event->already_known_by_peer,
1570 else if(event->type == MEET_REMOVENODE)
1572 //infostream<<"Server: MEET_REMOVENODE"<<std::endl;
1573 prof.add("MEET_REMOVENODE", 1);
1574 if(disable_single_change_sending)
1575 sendRemoveNode(event->p, event->already_known_by_peer,
1578 sendRemoveNode(event->p, event->already_known_by_peer,
1581 else if(event->type == MEET_BLOCK_NODE_METADATA_CHANGED)
1583 infostream<<"Server: MEET_BLOCK_NODE_METADATA_CHANGED"<<std::endl;
1584 prof.add("MEET_BLOCK_NODE_METADATA_CHANGED", 1);
1585 setBlockNotSent(event->p);
1587 else if(event->type == MEET_OTHER)
1589 infostream<<"Server: MEET_OTHER"<<std::endl;
1590 prof.add("MEET_OTHER", 1);
1591 for(std::set<v3s16>::iterator
1592 i = event->modified_blocks.begin();
1593 i != event->modified_blocks.end(); ++i)
1595 setBlockNotSent(*i);
1600 prof.add("unknown", 1);
1601 infostream<<"WARNING: Server: Unknown MapEditEvent "
1602 <<((u32)event->type)<<std::endl;
1606 Set blocks not sent to far players
1608 if(far_players.size() > 0)
1610 // Convert list format to that wanted by SetBlocksNotSent
1611 std::map<v3s16, MapBlock*> modified_blocks2;
1612 for(std::set<v3s16>::iterator
1613 i = event->modified_blocks.begin();
1614 i != event->modified_blocks.end(); ++i)
1616 modified_blocks2[*i] =
1617 m_env->getMap().getBlockNoCreateNoEx(*i);
1619 // Set blocks not sent
1620 for(std::list<u16>::iterator
1621 i = far_players.begin();
1622 i != far_players.end(); ++i)
1625 RemoteClient *client = getClient(peer_id);
1628 client->SetBlocksNotSent(modified_blocks2);
1634 /*// Don't send too many at a time
1636 if(count >= 1 && m_unsent_map_edit_queue.size() < 100)
1640 if(event_count >= 5){
1641 infostream<<"Server: MapEditEvents:"<<std::endl;
1642 prof.print(infostream);
1643 } else if(event_count != 0){
1644 verbosestream<<"Server: MapEditEvents:"<<std::endl;
1645 prof.print(verbosestream);
1651 Trigger emergethread (it somehow gets to a non-triggered but
1652 bysy state sometimes)
1655 float &counter = m_emergethread_trigger_timer;
1661 for (unsigned int i = 0; i != m_emerge->emergethread.size(); i++)
1662 m_emerge->emergethread[i]->trigger();
1664 // Update m_enable_rollback_recording here too
1665 m_enable_rollback_recording =
1666 g_settings->getBool("enable_rollback_recording");
1670 // Save map, players and auth stuff
1672 float &counter = m_savemap_timer;
1674 if(counter >= g_settings->getFloat("server_map_save_interval"))
1677 JMutexAutoLock lock(m_env_mutex);
1679 ScopeProfiler sp(g_profiler, "Server: saving stuff");
1682 if(m_banmanager.isModified())
1683 m_banmanager.save();
1685 // Save changed parts of map
1686 m_env->getMap().save(MOD_STATE_WRITE_NEEDED);
1689 m_env->serializePlayers(m_path_world);
1691 // Save environment metadata
1692 m_env->saveMeta(m_path_world);
1697 void Server::Receive()
1699 DSTACK(__FUNCTION_NAME);
1700 SharedBuffer<u8> data;
1705 JMutexAutoLock conlock(m_con_mutex);
1706 datasize = m_con.Receive(peer_id, data);
1709 // This has to be called so that the client list gets synced
1710 // with the peer list of the connection
1711 handlePeerChanges();
1713 ProcessData(*data, datasize, peer_id);
1715 catch(con::InvalidIncomingDataException &e)
1717 infostream<<"Server::Receive(): "
1718 "InvalidIncomingDataException: what()="
1719 <<e.what()<<std::endl;
1721 catch(con::PeerNotFoundException &e)
1723 //NOTE: This is not needed anymore
1725 // The peer has been disconnected.
1726 // Find the associated player and remove it.
1728 /*JMutexAutoLock envlock(m_env_mutex);
1730 infostream<<"ServerThread: peer_id="<<peer_id
1731 <<" has apparently closed connection. "
1732 <<"Removing player."<<std::endl;
1734 m_env->removePlayer(peer_id);*/
1738 void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
1740 DSTACK(__FUNCTION_NAME);
1741 // Environment is locked first.
1742 JMutexAutoLock envlock(m_env_mutex);
1743 JMutexAutoLock conlock(m_con_mutex);
1745 ScopeProfiler sp(g_profiler, "Server::ProcessData");
1748 Address address = m_con.GetPeerAddress(peer_id);
1749 std::string addr_s = address.serializeString();
1751 // drop player if is ip is banned
1752 if(m_banmanager.isIpBanned(addr_s)){
1753 infostream<<"Server: A banned client tried to connect from "
1754 <<addr_s<<"; banned name was "
1755 <<m_banmanager.getBanName(addr_s)<<std::endl;
1756 // This actually doesn't seem to transfer to the client
1757 SendAccessDenied(m_con, peer_id,
1758 L"Your ip is banned. Banned name was "
1759 +narrow_to_wide(m_banmanager.getBanName(addr_s)));
1760 m_con.DeletePeer(peer_id);
1764 catch(con::PeerNotFoundException &e)
1766 infostream<<"Server::ProcessData(): Cancelling: peer "
1767 <<peer_id<<" not found"<<std::endl;
1771 std::string addr_s = m_con.GetPeerAddress(peer_id).serializeString();
1773 u8 peer_ser_ver = getClient(peer_id)->serialization_version;
1781 ToServerCommand command = (ToServerCommand)readU16(&data[0]);
1783 if(command == TOSERVER_INIT)
1785 // [0] u16 TOSERVER_INIT
1786 // [2] u8 SER_FMT_VER_HIGHEST
1787 // [3] u8[20] player_name
1788 // [23] u8[28] password <--- can be sent without this, from old versions
1790 if(datasize < 2+1+PLAYERNAME_SIZE)
1793 verbosestream<<"Server: Got TOSERVER_INIT from "
1794 <<peer_id<<std::endl;
1796 // First byte after command is maximum supported
1797 // serialization version
1798 u8 client_max = data[2];
1799 u8 our_max = SER_FMT_VER_HIGHEST;
1800 // Use the highest version supported by both
1801 u8 deployed = std::min(client_max, our_max);
1802 // If it's lower than the lowest supported, give up.
1803 if(deployed < SER_FMT_VER_LOWEST)
1804 deployed = SER_FMT_VER_INVALID;
1806 //peer->serialization_version = deployed;
1807 getClient(peer_id)->pending_serialization_version = deployed;
1809 if(deployed == SER_FMT_VER_INVALID)
1811 actionstream<<"Server: A mismatched client tried to connect from "
1812 <<addr_s<<std::endl;
1813 infostream<<"Server: Cannot negotiate "
1814 "serialization version with peer "
1815 <<peer_id<<std::endl;
1816 SendAccessDenied(m_con, peer_id, std::wstring(
1817 L"Your client's version is not supported.\n"
1818 L"Server version is ")
1819 + narrow_to_wide(VERSION_STRING) + L"."
1825 Read and check network protocol version
1828 u16 min_net_proto_version = 0;
1829 if(datasize >= 2+1+PLAYERNAME_SIZE+PASSWORD_SIZE+2)
1830 min_net_proto_version = readU16(&data[2+1+PLAYERNAME_SIZE+PASSWORD_SIZE]);
1832 // Use same version as minimum and maximum if maximum version field
1833 // doesn't exist (backwards compatibility)
1834 u16 max_net_proto_version = min_net_proto_version;
1835 if(datasize >= 2+1+PLAYERNAME_SIZE+PASSWORD_SIZE+2+2)
1836 max_net_proto_version = readU16(&data[2+1+PLAYERNAME_SIZE+PASSWORD_SIZE+2]);
1838 // Start with client's maximum version
1839 u16 net_proto_version = max_net_proto_version;
1841 // Figure out a working version if it is possible at all
1842 if(max_net_proto_version >= SERVER_PROTOCOL_VERSION_MIN ||
1843 min_net_proto_version <= SERVER_PROTOCOL_VERSION_MAX)
1845 // If maximum is larger than our maximum, go with our maximum
1846 if(max_net_proto_version > SERVER_PROTOCOL_VERSION_MAX)
1847 net_proto_version = SERVER_PROTOCOL_VERSION_MAX;
1848 // Else go with client's maximum
1850 net_proto_version = max_net_proto_version;
1853 verbosestream<<"Server: "<<peer_id<<" Protocol version: min: "
1854 <<min_net_proto_version<<", max: "<<max_net_proto_version
1855 <<", chosen: "<<net_proto_version<<std::endl;
1857 getClient(peer_id)->net_proto_version = net_proto_version;
1859 if(net_proto_version < SERVER_PROTOCOL_VERSION_MIN ||
1860 net_proto_version > SERVER_PROTOCOL_VERSION_MAX)
1862 actionstream<<"Server: A mismatched client tried to connect from "<<addr_s
1864 SendAccessDenied(m_con, peer_id, std::wstring(
1865 L"Your client's version is not supported.\n"
1866 L"Server version is ")
1867 + narrow_to_wide(VERSION_STRING) + L",\n"
1868 + L"server's PROTOCOL_VERSION is "
1869 + narrow_to_wide(itos(SERVER_PROTOCOL_VERSION_MIN))
1871 + narrow_to_wide(itos(SERVER_PROTOCOL_VERSION_MAX))
1872 + L", client's PROTOCOL_VERSION is "
1873 + narrow_to_wide(itos(min_net_proto_version))
1875 + narrow_to_wide(itos(max_net_proto_version))
1880 if(g_settings->getBool("strict_protocol_version_checking"))
1882 if(net_proto_version != LATEST_PROTOCOL_VERSION)
1884 actionstream<<"Server: A mismatched (strict) client tried to "
1885 <<"connect from "<<addr_s<<std::endl;
1886 SendAccessDenied(m_con, peer_id, std::wstring(
1887 L"Your client's version is not supported.\n"
1888 L"Server version is ")
1889 + narrow_to_wide(VERSION_STRING) + L",\n"
1890 + L"server's PROTOCOL_VERSION (strict) is "
1891 + narrow_to_wide(itos(LATEST_PROTOCOL_VERSION))
1892 + L", client's PROTOCOL_VERSION is "
1893 + narrow_to_wide(itos(min_net_proto_version))
1895 + narrow_to_wide(itos(max_net_proto_version))
1906 char playername[PLAYERNAME_SIZE];
1907 for(u32 i=0; i<PLAYERNAME_SIZE-1; i++)
1909 playername[i] = data[3+i];
1911 playername[PLAYERNAME_SIZE-1] = 0;
1913 if(playername[0]=='\0')
1915 actionstream<<"Server: Player with an empty name "
1916 <<"tried to connect from "<<addr_s<<std::endl;
1917 SendAccessDenied(m_con, peer_id,
1922 if(string_allowed(playername, PLAYERNAME_ALLOWED_CHARS)==false)
1924 actionstream<<"Server: Player with an invalid name "
1925 <<"tried to connect from "<<addr_s<<std::endl;
1926 SendAccessDenied(m_con, peer_id,
1927 L"Name contains unallowed characters");
1931 infostream<<"Server: New connection: \""<<playername<<"\" from "
1932 <<m_con.GetPeerAddress(peer_id).serializeString()<<std::endl;
1935 char given_password[PASSWORD_SIZE];
1936 if(datasize < 2+1+PLAYERNAME_SIZE+PASSWORD_SIZE)
1938 // old version - assume blank password
1939 given_password[0] = 0;
1943 for(u32 i=0; i<PASSWORD_SIZE-1; i++)
1945 given_password[i] = data[23+i];
1947 given_password[PASSWORD_SIZE-1] = 0;
1950 if(!base64_is_valid(given_password)){
1951 infostream<<"Server: "<<playername
1952 <<" supplied invalid password hash"<<std::endl;
1953 SendAccessDenied(m_con, peer_id, L"Invalid password hash");
1957 std::string checkpwd; // Password hash to check against
1958 bool has_auth = scriptapi_get_auth(m_lua, playername, &checkpwd, NULL);
1960 // If no authentication info exists for user, create it
1962 if(!isSingleplayer() &&
1963 g_settings->getBool("disallow_empty_password") &&
1964 std::string(given_password) == ""){
1965 SendAccessDenied(m_con, peer_id, L"Empty passwords are "
1966 L"disallowed. Set a password and try again.");
1969 std::wstring raw_default_password =
1970 narrow_to_wide(g_settings->get("default_password"));
1971 std::string initial_password =
1972 translatePassword(playername, raw_default_password);
1974 // If default_password is empty, allow any initial password
1975 if (raw_default_password.length() == 0)
1976 initial_password = given_password;
1978 scriptapi_create_auth(m_lua, playername, initial_password);
1981 has_auth = scriptapi_get_auth(m_lua, playername, &checkpwd, NULL);
1984 SendAccessDenied(m_con, peer_id, L"Not allowed to login");
1988 if(given_password != checkpwd){
1989 infostream<<"Server: peer_id="<<peer_id
1990 <<": supplied invalid password for "
1991 <<playername<<std::endl;
1992 SendAccessDenied(m_con, peer_id, L"Invalid password");
1996 // Do not allow multiple players in simple singleplayer mode.
1997 // This isn't a perfect way to do it, but will suffice for now.
1998 if(m_simple_singleplayer_mode && m_clients.size() > 1){
1999 infostream<<"Server: Not allowing another client to connect in"
2000 <<" simple singleplayer mode"<<std::endl;
2001 SendAccessDenied(m_con, peer_id,
2002 L"Running in simple singleplayer mode.");
2006 // Enforce user limit.
2007 // Don't enforce for users that have some admin right
2008 if(m_clients.size() >= g_settings->getU16("max_users") &&
2009 !checkPriv(playername, "server") &&
2010 !checkPriv(playername, "ban") &&
2011 !checkPriv(playername, "privs") &&
2012 !checkPriv(playername, "password") &&
2013 playername != g_settings->get("name"))
2015 actionstream<<"Server: "<<playername<<" tried to join, but there"
2016 <<" are already max_users="
2017 <<g_settings->getU16("max_users")<<" players."<<std::endl;
2018 SendAccessDenied(m_con, peer_id, L"Too many users.");
2023 PlayerSAO *playersao = emergePlayer(playername, peer_id);
2025 // If failed, cancel
2026 if(playersao == NULL)
2028 errorstream<<"Server: peer_id="<<peer_id
2029 <<": failed to emerge player"<<std::endl;
2034 Answer with a TOCLIENT_INIT
2037 SharedBuffer<u8> reply(2+1+6+8+4);
2038 writeU16(&reply[0], TOCLIENT_INIT);
2039 writeU8(&reply[2], deployed);
2040 writeV3S16(&reply[2+1], floatToInt(playersao->getPlayer()->getPosition()+v3f(0,BS/2,0), BS));
2041 writeU64(&reply[2+1+6], m_env->getServerMap().getSeed());
2042 writeF1000(&reply[2+1+6+8], g_settings->getFloat("dedicated_server_step"));
2045 m_con.Send(peer_id, 0, reply, true);
2049 Send complete position information
2051 SendMovePlayer(peer_id);
2056 if(command == TOSERVER_INIT2)
2058 verbosestream<<"Server: Got TOSERVER_INIT2 from "
2059 <<peer_id<<std::endl;
2061 Player *player = m_env->getPlayer(peer_id);
2063 verbosestream<<"Server: TOSERVER_INIT2: "
2064 <<"Player not found; ignoring."<<std::endl;
2068 RemoteClient *client = getClient(peer_id);
2069 client->serialization_version =
2070 getClient(peer_id)->pending_serialization_version;
2073 Send some initialization data
2076 infostream<<"Server: Sending content to "
2077 <<getPlayerName(peer_id)<<std::endl;
2079 // Send player movement settings
2080 SendMovement(m_con, peer_id);
2082 // Send item definitions
2083 SendItemDef(m_con, peer_id, m_itemdef);
2085 // Send node definitions
2086 SendNodeDef(m_con, peer_id, m_nodedef, client->net_proto_version);
2088 // Send media announcement
2089 sendMediaAnnouncement(peer_id);
2092 SendPlayerPrivileges(peer_id);
2094 // Send inventory formspec
2095 SendPlayerInventoryFormspec(peer_id);
2098 UpdateCrafting(peer_id);
2099 SendInventory(peer_id);
2102 if(g_settings->getBool("enable_damage"))
2103 SendPlayerHP(peer_id);
2105 // Send detached inventories
2106 sendDetachedInventories(peer_id);
2108 // Show death screen if necessary
2110 SendDeathscreen(m_con, peer_id, false, v3f(0,0,0));
2114 SharedBuffer<u8> data = makePacket_TOCLIENT_TIME_OF_DAY(
2115 m_env->getTimeOfDay(), g_settings->getFloat("time_speed"));
2116 m_con.Send(peer_id, 0, data, true);
2119 // Note things in chat if not in simple singleplayer mode
2120 if(!m_simple_singleplayer_mode)
2122 // Send information about server to player in chat
2123 SendChatMessage(peer_id, getStatusString());
2125 // Send information about joining in chat
2127 std::wstring name = L"unknown";
2128 Player *player = m_env->getPlayer(peer_id);
2130 name = narrow_to_wide(player->getName());
2132 std::wstring message;
2135 message += L" joined the game.";
2136 BroadcastChatMessage(message);
2140 // Warnings about protocol version can be issued here
2141 if(getClient(peer_id)->net_proto_version < LATEST_PROTOCOL_VERSION)
2143 SendChatMessage(peer_id, L"# Server: WARNING: YOUR CLIENT'S "
2144 L"VERSION MAY NOT BE FULLY COMPATIBLE WITH THIS SERVER!");
2151 std::ostringstream os(std::ios_base::binary);
2152 for(std::map<u16, RemoteClient*>::iterator
2153 i = m_clients.begin();
2154 i != m_clients.end(); ++i)
2156 RemoteClient *client = i->second;
2157 assert(client->peer_id == i->first);
2158 if(client->serialization_version == SER_FMT_VER_INVALID)
2161 Player *player = m_env->getPlayer(client->peer_id);
2164 // Get name of player
2165 os<<player->getName()<<" ";
2168 actionstream<<player->getName()<<" joins game. List of players: "
2169 <<os.str()<<std::endl;
2175 if(peer_ser_ver == SER_FMT_VER_INVALID)
2177 infostream<<"Server::ProcessData(): Cancelling: Peer"
2178 " serialization format invalid or not initialized."
2179 " Skipping incoming command="<<command<<std::endl;
2183 Player *player = m_env->getPlayer(peer_id);
2185 infostream<<"Server::ProcessData(): Cancelling: "
2186 "No player for peer_id="<<peer_id
2191 PlayerSAO *playersao = player->getPlayerSAO();
2192 if(playersao == NULL){
2193 infostream<<"Server::ProcessData(): Cancelling: "
2194 "No player object for peer_id="<<peer_id
2199 if(command == TOSERVER_PLAYERPOS)
2201 if(datasize < 2+12+12+4+4)
2205 v3s32 ps = readV3S32(&data[start+2]);
2206 v3s32 ss = readV3S32(&data[start+2+12]);
2207 f32 pitch = (f32)readS32(&data[2+12+12]) / 100.0;
2208 f32 yaw = (f32)readS32(&data[2+12+12+4]) / 100.0;
2210 if(datasize >= 2+12+12+4+4+4)
2211 keyPressed = (u32)readU32(&data[2+12+12+4+4]);
2212 v3f position((f32)ps.X/100., (f32)ps.Y/100., (f32)ps.Z/100.);
2213 v3f speed((f32)ss.X/100., (f32)ss.Y/100., (f32)ss.Z/100.);
2214 pitch = wrapDegrees(pitch);
2215 yaw = wrapDegrees(yaw);
2217 player->setPosition(position);
2218 player->setSpeed(speed);
2219 player->setPitch(pitch);
2220 player->setYaw(yaw);
2221 player->keyPressed=keyPressed;
2222 player->control.up = (bool)(keyPressed&1);
2223 player->control.down = (bool)(keyPressed&2);
2224 player->control.left = (bool)(keyPressed&4);
2225 player->control.right = (bool)(keyPressed&8);
2226 player->control.jump = (bool)(keyPressed&16);
2227 player->control.aux1 = (bool)(keyPressed&32);
2228 player->control.sneak = (bool)(keyPressed&64);
2229 player->control.LMB = (bool)(keyPressed&128);
2230 player->control.RMB = (bool)(keyPressed&256);
2232 /*infostream<<"Server::ProcessData(): Moved player "<<peer_id<<" to "
2233 <<"("<<position.X<<","<<position.Y<<","<<position.Z<<")"
2234 <<" pitch="<<pitch<<" yaw="<<yaw<<std::endl;*/
2236 else if(command == TOSERVER_GOTBLOCKS)
2249 u16 count = data[2];
2250 for(u16 i=0; i<count; i++)
2252 if((s16)datasize < 2+1+(i+1)*6)
2253 throw con::InvalidIncomingDataException
2254 ("GOTBLOCKS length is too short");
2255 v3s16 p = readV3S16(&data[2+1+i*6]);
2256 /*infostream<<"Server: GOTBLOCKS ("
2257 <<p.X<<","<<p.Y<<","<<p.Z<<")"<<std::endl;*/
2258 RemoteClient *client = getClient(peer_id);
2259 client->GotBlock(p);
2262 else if(command == TOSERVER_DELETEDBLOCKS)
2275 u16 count = data[2];
2276 for(u16 i=0; i<count; i++)
2278 if((s16)datasize < 2+1+(i+1)*6)
2279 throw con::InvalidIncomingDataException
2280 ("DELETEDBLOCKS length is too short");
2281 v3s16 p = readV3S16(&data[2+1+i*6]);
2282 /*infostream<<"Server: DELETEDBLOCKS ("
2283 <<p.X<<","<<p.Y<<","<<p.Z<<")"<<std::endl;*/
2284 RemoteClient *client = getClient(peer_id);
2285 client->SetBlockNotSent(p);
2288 else if(command == TOSERVER_CLICK_OBJECT)
2290 infostream<<"Server: CLICK_OBJECT not supported anymore"<<std::endl;
2293 else if(command == TOSERVER_CLICK_ACTIVEOBJECT)
2295 infostream<<"Server: CLICK_ACTIVEOBJECT not supported anymore"<<std::endl;
2298 else if(command == TOSERVER_GROUND_ACTION)
2300 infostream<<"Server: GROUND_ACTION not supported anymore"<<std::endl;
2304 else if(command == TOSERVER_RELEASE)
2306 infostream<<"Server: RELEASE not supported anymore"<<std::endl;
2309 else if(command == TOSERVER_SIGNTEXT)
2311 infostream<<"Server: SIGNTEXT not supported anymore"
2315 else if(command == TOSERVER_SIGNNODETEXT)
2317 infostream<<"Server: SIGNNODETEXT not supported anymore"
2321 else if(command == TOSERVER_INVENTORY_ACTION)
2323 // Strip command and create a stream
2324 std::string datastring((char*)&data[2], datasize-2);
2325 verbosestream<<"TOSERVER_INVENTORY_ACTION: data="<<datastring<<std::endl;
2326 std::istringstream is(datastring, std::ios_base::binary);
2328 InventoryAction *a = InventoryAction::deSerialize(is);
2331 infostream<<"TOSERVER_INVENTORY_ACTION: "
2332 <<"InventoryAction::deSerialize() returned NULL"
2337 // If something goes wrong, this player is to blame
2338 RollbackScopeActor rollback_scope(m_rollback,
2339 std::string("player:")+player->getName());
2342 Note: Always set inventory not sent, to repair cases
2343 where the client made a bad prediction.
2347 Handle restrictions and special cases of the move action
2349 if(a->getType() == IACTION_MOVE)
2351 IMoveAction *ma = (IMoveAction*)a;
2353 ma->from_inv.applyCurrentPlayer(player->getName());
2354 ma->to_inv.applyCurrentPlayer(player->getName());
2356 setInventoryModified(ma->from_inv);
2357 setInventoryModified(ma->to_inv);
2359 bool from_inv_is_current_player =
2360 (ma->from_inv.type == InventoryLocation::PLAYER) &&
2361 (ma->from_inv.name == player->getName());
2363 bool to_inv_is_current_player =
2364 (ma->to_inv.type == InventoryLocation::PLAYER) &&
2365 (ma->to_inv.name == player->getName());
2368 Disable moving items out of craftpreview
2370 if(ma->from_list == "craftpreview")
2372 infostream<<"Ignoring IMoveAction from "
2373 <<(ma->from_inv.dump())<<":"<<ma->from_list
2374 <<" to "<<(ma->to_inv.dump())<<":"<<ma->to_list
2375 <<" because src is "<<ma->from_list<<std::endl;
2381 Disable moving items into craftresult and craftpreview
2383 if(ma->to_list == "craftpreview" || ma->to_list == "craftresult")
2385 infostream<<"Ignoring IMoveAction from "
2386 <<(ma->from_inv.dump())<<":"<<ma->from_list
2387 <<" to "<<(ma->to_inv.dump())<<":"<<ma->to_list
2388 <<" because dst is "<<ma->to_list<<std::endl;
2393 // Disallow moving items in elsewhere than player's inventory
2394 // if not allowed to interact
2395 if(!checkPriv(player->getName(), "interact") &&
2396 (!from_inv_is_current_player ||
2397 !to_inv_is_current_player))
2399 infostream<<"Cannot move outside of player's inventory: "
2400 <<"No interact privilege"<<std::endl;
2406 Handle restrictions and special cases of the drop action
2408 else if(a->getType() == IACTION_DROP)
2410 IDropAction *da = (IDropAction*)a;
2412 da->from_inv.applyCurrentPlayer(player->getName());
2414 setInventoryModified(da->from_inv);
2416 // Disallow dropping items if not allowed to interact
2417 if(!checkPriv(player->getName(), "interact"))
2424 Handle restrictions and special cases of the craft action
2426 else if(a->getType() == IACTION_CRAFT)
2428 ICraftAction *ca = (ICraftAction*)a;
2430 ca->craft_inv.applyCurrentPlayer(player->getName());
2432 setInventoryModified(ca->craft_inv);
2434 //bool craft_inv_is_current_player =
2435 // (ca->craft_inv.type == InventoryLocation::PLAYER) &&
2436 // (ca->craft_inv.name == player->getName());
2438 // Disallow crafting if not allowed to interact
2439 if(!checkPriv(player->getName(), "interact"))
2441 infostream<<"Cannot craft: "
2442 <<"No interact privilege"<<std::endl;
2449 a->apply(this, playersao, this);
2453 else if(command == TOSERVER_CHAT_MESSAGE)
2461 std::string datastring((char*)&data[2], datasize-2);
2462 std::istringstream is(datastring, std::ios_base::binary);
2465 is.read((char*)buf, 2);
2466 u16 len = readU16(buf);
2468 std::wstring message;
2469 for(u16 i=0; i<len; i++)
2471 is.read((char*)buf, 2);
2472 message += (wchar_t)readU16(buf);
2475 // If something goes wrong, this player is to blame
2476 RollbackScopeActor rollback_scope(m_rollback,
2477 std::string("player:")+player->getName());
2479 // Get player name of this client
2480 std::wstring name = narrow_to_wide(player->getName());
2483 bool ate = scriptapi_on_chat_message(m_lua, player->getName(),
2484 wide_to_narrow(message));
2485 // If script ate the message, don't proceed
2489 // Line to send to players
2491 // Whether to send to the player that sent the line
2492 bool send_to_sender = false;
2493 // Whether to send to other players
2494 bool send_to_others = false;
2496 // Commands are implemented in Lua, so only catch invalid
2497 // commands that were not "eaten" and send an error back
2498 if(message[0] == L'/')
2500 message = message.substr(1);
2501 send_to_sender = true;
2502 if(message.length() == 0)
2503 line += L"-!- Empty command";
2505 line += L"-!- Invalid command: " + str_split(message, L' ')[0];
2509 if(checkPriv(player->getName(), "shout")){
2514 send_to_others = true;
2516 line += L"-!- You don't have permission to shout.";
2517 send_to_sender = true;
2524 actionstream<<"CHAT: "<<wide_to_narrow(line)<<std::endl;
2527 Send the message to clients
2529 for(std::map<u16, RemoteClient*>::iterator
2530 i = m_clients.begin();
2531 i != m_clients.end(); ++i)
2533 // Get client and check that it is valid
2534 RemoteClient *client = i->second;
2535 assert(client->peer_id == i->first);
2536 if(client->serialization_version == SER_FMT_VER_INVALID)
2540 bool sender_selected = (peer_id == client->peer_id);
2541 if(sender_selected == true && send_to_sender == false)
2543 if(sender_selected == false && send_to_others == false)
2546 SendChatMessage(client->peer_id, line);
2550 else if(command == TOSERVER_DAMAGE)
2552 std::string datastring((char*)&data[2], datasize-2);
2553 std::istringstream is(datastring, std::ios_base::binary);
2554 u8 damage = readU8(is);
2556 if(g_settings->getBool("enable_damage"))
2558 actionstream<<player->getName()<<" damaged by "
2559 <<(int)damage<<" hp at "<<PP(player->getPosition()/BS)
2562 playersao->setHP(playersao->getHP() - damage);
2564 if(playersao->getHP() == 0 && playersao->m_hp_not_sent)
2567 if(playersao->m_hp_not_sent)
2568 SendPlayerHP(peer_id);
2571 else if(command == TOSERVER_PASSWORD)
2574 [0] u16 TOSERVER_PASSWORD
2575 [2] u8[28] old password
2576 [30] u8[28] new password
2579 if(datasize != 2+PASSWORD_SIZE*2)
2581 /*char password[PASSWORD_SIZE];
2582 for(u32 i=0; i<PASSWORD_SIZE-1; i++)
2583 password[i] = data[2+i];
2584 password[PASSWORD_SIZE-1] = 0;*/
2586 for(u32 i=0; i<PASSWORD_SIZE-1; i++)
2594 for(u32 i=0; i<PASSWORD_SIZE-1; i++)
2596 char c = data[2+PASSWORD_SIZE+i];
2602 if(!base64_is_valid(newpwd)){
2603 infostream<<"Server: "<<player->getName()<<" supplied invalid password hash"<<std::endl;
2604 // Wrong old password supplied!!
2605 SendChatMessage(peer_id, L"Invalid new password hash supplied. Password NOT changed.");
2609 infostream<<"Server: Client requests a password change from "
2610 <<"'"<<oldpwd<<"' to '"<<newpwd<<"'"<<std::endl;
2612 std::string playername = player->getName();
2614 std::string checkpwd;
2615 scriptapi_get_auth(m_lua, playername, &checkpwd, NULL);
2617 if(oldpwd != checkpwd)
2619 infostream<<"Server: invalid old password"<<std::endl;
2620 // Wrong old password supplied!!
2621 SendChatMessage(peer_id, L"Invalid old password supplied. Password NOT changed.");
2625 bool success = scriptapi_set_password(m_lua, playername, newpwd);
2627 actionstream<<player->getName()<<" changes password"<<std::endl;
2628 SendChatMessage(peer_id, L"Password change successful.");
2630 actionstream<<player->getName()<<" tries to change password but "
2631 <<"it fails"<<std::endl;
2632 SendChatMessage(peer_id, L"Password change failed or inavailable.");
2635 else if(command == TOSERVER_PLAYERITEM)
2640 u16 item = readU16(&data[2]);
2641 playersao->setWieldIndex(item);
2643 else if(command == TOSERVER_RESPAWN)
2645 if(player->hp != 0 || !g_settings->getBool("enable_damage"))
2648 RespawnPlayer(peer_id);
2650 actionstream<<player->getName()<<" respawns at "
2651 <<PP(player->getPosition()/BS)<<std::endl;
2653 // ActiveObject is added to environment in AsyncRunStep after
2654 // the previous addition has been succesfully removed
2656 else if(command == TOSERVER_REQUEST_MEDIA) {
2657 std::string datastring((char*)&data[2], datasize-2);
2658 std::istringstream is(datastring, std::ios_base::binary);
2660 std::list<MediaRequest> tosend;
2661 u16 numfiles = readU16(is);
2663 infostream<<"Sending "<<numfiles<<" files to "
2664 <<getPlayerName(peer_id)<<std::endl;
2665 verbosestream<<"TOSERVER_REQUEST_MEDIA: "<<std::endl;
2667 for(int i = 0; i < numfiles; i++) {
2668 std::string name = deSerializeString(is);
2669 tosend.push_back(MediaRequest(name));
2670 verbosestream<<"TOSERVER_REQUEST_MEDIA: requested file "
2674 sendRequestedMedia(peer_id, tosend);
2676 // Now the client should know about everything
2677 // (definitions and files)
2678 getClient(peer_id)->definitions_sent = true;
2680 else if(command == TOSERVER_RECEIVED_MEDIA) {
2681 getClient(peer_id)->definitions_sent = true;
2683 else if(command == TOSERVER_INTERACT)
2685 std::string datastring((char*)&data[2], datasize-2);
2686 std::istringstream is(datastring, std::ios_base::binary);
2692 [5] u32 length of the next item
2693 [9] serialized PointedThing
2695 0: start digging (from undersurface) or use
2696 1: stop digging (all parameters ignored)
2697 2: digging completed
2698 3: place block or item (to abovesurface)
2701 u8 action = readU8(is);
2702 u16 item_i = readU16(is);
2703 std::istringstream tmp_is(deSerializeLongString(is), std::ios::binary);
2704 PointedThing pointed;
2705 pointed.deSerialize(tmp_is);
2707 verbosestream<<"TOSERVER_INTERACT: action="<<(int)action<<", item="
2708 <<item_i<<", pointed="<<pointed.dump()<<std::endl;
2712 verbosestream<<"TOSERVER_INTERACT: "<<player->getName()
2713 <<" tried to interact, but is dead!"<<std::endl;
2717 v3f player_pos = playersao->getLastGoodPosition();
2719 // Update wielded item
2720 playersao->setWieldIndex(item_i);
2722 // Get pointed to node (undefined if not POINTEDTYPE_NODE)
2723 v3s16 p_under = pointed.node_undersurface;
2724 v3s16 p_above = pointed.node_abovesurface;
2726 // Get pointed to object (NULL if not POINTEDTYPE_OBJECT)
2727 ServerActiveObject *pointed_object = NULL;
2728 if(pointed.type == POINTEDTHING_OBJECT)
2730 pointed_object = m_env->getActiveObject(pointed.object_id);
2731 if(pointed_object == NULL)
2733 verbosestream<<"TOSERVER_INTERACT: "
2734 "pointed object is NULL"<<std::endl;
2740 v3f pointed_pos_under = player_pos;
2741 v3f pointed_pos_above = player_pos;
2742 if(pointed.type == POINTEDTHING_NODE)
2744 pointed_pos_under = intToFloat(p_under, BS);
2745 pointed_pos_above = intToFloat(p_above, BS);
2747 else if(pointed.type == POINTEDTHING_OBJECT)
2749 pointed_pos_under = pointed_object->getBasePosition();
2750 pointed_pos_above = pointed_pos_under;
2754 Check that target is reasonably close
2755 (only when digging or placing things)
2757 if(action == 0 || action == 2 || action == 3)
2759 float d = player_pos.getDistanceFrom(pointed_pos_under);
2760 float max_d = BS * 14; // Just some large enough value
2762 actionstream<<"Player "<<player->getName()
2763 <<" tried to access "<<pointed.dump()
2765 <<"d="<<d<<", max_d="<<max_d
2766 <<". ignoring."<<std::endl;
2767 // Re-send block to revert change on client-side
2768 RemoteClient *client = getClient(peer_id);
2769 v3s16 blockpos = getNodeBlockPos(floatToInt(pointed_pos_under, BS));
2770 client->SetBlockNotSent(blockpos);
2777 Make sure the player is allowed to do it
2779 if(!checkPriv(player->getName(), "interact"))
2781 actionstream<<player->getName()<<" attempted to interact with "
2782 <<pointed.dump()<<" without 'interact' privilege"
2784 // Re-send block to revert change on client-side
2785 RemoteClient *client = getClient(peer_id);
2786 // Digging completed -> under
2788 v3s16 blockpos = getNodeBlockPos(floatToInt(pointed_pos_under, BS));
2789 client->SetBlockNotSent(blockpos);
2791 // Placement -> above
2793 v3s16 blockpos = getNodeBlockPos(floatToInt(pointed_pos_above, BS));
2794 client->SetBlockNotSent(blockpos);
2800 If something goes wrong, this player is to blame
2802 RollbackScopeActor rollback_scope(m_rollback,
2803 std::string("player:")+player->getName());
2806 0: start digging or punch object
2810 if(pointed.type == POINTEDTHING_NODE)
2813 NOTE: This can be used in the future to check if
2814 somebody is cheating, by checking the timing.
2816 MapNode n(CONTENT_IGNORE);
2819 n = m_env->getMap().getNode(p_under);
2821 catch(InvalidPositionException &e)
2823 infostream<<"Server: Not punching: Node not found."
2824 <<" Adding block to emerge queue."
2826 m_emerge->enqueueBlockEmerge(peer_id, getNodeBlockPos(p_above), false);
2828 if(n.getContent() != CONTENT_IGNORE)
2829 scriptapi_node_on_punch(m_lua, p_under, n, playersao);
2831 playersao->noCheatDigStart(p_under);
2833 else if(pointed.type == POINTEDTHING_OBJECT)
2835 // Skip if object has been removed
2836 if(pointed_object->m_removed)
2839 actionstream<<player->getName()<<" punches object "
2840 <<pointed.object_id<<": "
2841 <<pointed_object->getDescription()<<std::endl;
2843 ItemStack punchitem = playersao->getWieldedItem();
2844 ToolCapabilities toolcap =
2845 punchitem.getToolCapabilities(m_itemdef);
2846 v3f dir = (pointed_object->getBasePosition() -
2847 (player->getPosition() + player->getEyeOffset())
2849 float time_from_last_punch =
2850 playersao->resetTimeFromLastPunch();
2851 pointed_object->punch(dir, &toolcap, playersao,
2852 time_from_last_punch);
2860 else if(action == 1)
2865 2: Digging completed
2867 else if(action == 2)
2869 // Only digging of nodes
2870 if(pointed.type == POINTEDTHING_NODE)
2872 MapNode n(CONTENT_IGNORE);
2875 n = m_env->getMap().getNode(p_under);
2877 catch(InvalidPositionException &e)
2879 infostream<<"Server: Not finishing digging: Node not found."
2880 <<" Adding block to emerge queue."
2882 m_emerge->enqueueBlockEmerge(peer_id, getNodeBlockPos(p_above), false);
2885 /* Cheat prevention */
2886 bool is_valid_dig = true;
2887 if(!isSingleplayer() && !g_settings->getBool("disable_anticheat"))
2889 v3s16 nocheat_p = playersao->getNoCheatDigPos();
2890 float nocheat_t = playersao->getNoCheatDigTime();
2891 playersao->noCheatDigEnd();
2892 // If player didn't start digging this, ignore dig
2893 if(nocheat_p != p_under){
2894 infostream<<"Server: NoCheat: "<<player->getName()
2895 <<" started digging "
2896 <<PP(nocheat_p)<<" and completed digging "
2897 <<PP(p_under)<<"; not digging."<<std::endl;
2898 is_valid_dig = false;
2900 // Get player's wielded item
2901 ItemStack playeritem;
2902 InventoryList *mlist = playersao->getInventory()->getList("main");
2904 playeritem = mlist->getItem(playersao->getWieldIndex());
2905 ToolCapabilities playeritem_toolcap =
2906 playeritem.getToolCapabilities(m_itemdef);
2907 // Get diggability and expected digging time
2908 DigParams params = getDigParams(m_nodedef->get(n).groups,
2909 &playeritem_toolcap);
2910 // If can't dig, try hand
2911 if(!params.diggable){
2912 const ItemDefinition &hand = m_itemdef->get("");
2913 const ToolCapabilities *tp = hand.tool_capabilities;
2915 params = getDigParams(m_nodedef->get(n).groups, tp);
2917 // If can't dig, ignore dig
2918 if(!params.diggable){
2919 infostream<<"Server: NoCheat: "<<player->getName()
2920 <<" completed digging "<<PP(p_under)
2921 <<", which is not diggable with tool. not digging."
2923 is_valid_dig = false;
2925 // If time is considerably too short, ignore dig
2926 // Check time only for medium and slow timed digs
2927 if(params.diggable && params.time > 0.3 && nocheat_t < 0.5 * params.time){
2928 infostream<<"Server: NoCheat: "<<player->getName()
2929 <<" completed digging "
2930 <<PP(p_under)<<" in "<<nocheat_t<<"s; expected "
2931 <<params.time<<"s; not digging."<<std::endl;
2932 is_valid_dig = false;
2936 /* Actually dig node */
2938 if(is_valid_dig && n.getContent() != CONTENT_IGNORE)
2939 scriptapi_node_on_dig(m_lua, p_under, n, playersao);
2941 // Send unusual result (that is, node not being removed)
2942 if(m_env->getMap().getNodeNoEx(p_under).getContent() != CONTENT_AIR)
2944 // Re-send block to revert change on client-side
2945 RemoteClient *client = getClient(peer_id);
2946 v3s16 blockpos = getNodeBlockPos(floatToInt(pointed_pos_under, BS));
2947 client->SetBlockNotSent(blockpos);
2953 3: place block or right-click object
2955 else if(action == 3)
2957 ItemStack item = playersao->getWieldedItem();
2959 // Reset build time counter
2960 if(pointed.type == POINTEDTHING_NODE &&
2961 item.getDefinition(m_itemdef).type == ITEM_NODE)
2962 getClient(peer_id)->m_time_from_building = 0.0;
2964 if(pointed.type == POINTEDTHING_OBJECT)
2966 // Right click object
2968 // Skip if object has been removed
2969 if(pointed_object->m_removed)
2972 actionstream<<player->getName()<<" right-clicks object "
2973 <<pointed.object_id<<": "
2974 <<pointed_object->getDescription()<<std::endl;
2977 pointed_object->rightClick(playersao);
2979 else if(scriptapi_item_on_place(m_lua,
2980 item, playersao, pointed))
2982 // Placement was handled in lua
2984 // Apply returned ItemStack
2985 playersao->setWieldedItem(item);
2988 // If item has node placement prediction, always send the above
2989 // node to make sure the client knows what exactly happened
2990 if(item.getDefinition(m_itemdef).node_placement_prediction != ""){
2991 RemoteClient *client = getClient(peer_id);
2992 v3s16 blockpos = getNodeBlockPos(floatToInt(pointed_pos_above, BS));
2993 client->SetBlockNotSent(blockpos);
3000 else if(action == 4)
3002 ItemStack item = playersao->getWieldedItem();
3004 actionstream<<player->getName()<<" uses "<<item.name
3005 <<", pointing at "<<pointed.dump()<<std::endl;
3007 if(scriptapi_item_on_use(m_lua,
3008 item, playersao, pointed))
3010 // Apply returned ItemStack
3011 playersao->setWieldedItem(item);
3018 Catch invalid actions
3022 infostream<<"WARNING: Server: Invalid action "
3023 <<action<<std::endl;
3026 else if(command == TOSERVER_REMOVED_SOUNDS)
3028 std::string datastring((char*)&data[2], datasize-2);
3029 std::istringstream is(datastring, std::ios_base::binary);
3031 int num = readU16(is);
3032 for(int k=0; k<num; k++){
3033 s32 id = readS32(is);
3034 std::map<s32, ServerPlayingSound>::iterator i =
3035 m_playing_sounds.find(id);
3036 if(i == m_playing_sounds.end())
3038 ServerPlayingSound &psound = i->second;
3039 psound.clients.erase(peer_id);
3040 if(psound.clients.size() == 0)
3041 m_playing_sounds.erase(i++);
3044 else if(command == TOSERVER_NODEMETA_FIELDS)
3046 std::string datastring((char*)&data[2], datasize-2);
3047 std::istringstream is(datastring, std::ios_base::binary);
3049 v3s16 p = readV3S16(is);
3050 std::string formname = deSerializeString(is);
3051 int num = readU16(is);
3052 std::map<std::string, std::string> fields;
3053 for(int k=0; k<num; k++){
3054 std::string fieldname = deSerializeString(is);
3055 std::string fieldvalue = deSerializeLongString(is);
3056 fields[fieldname] = fieldvalue;
3059 // If something goes wrong, this player is to blame
3060 RollbackScopeActor rollback_scope(m_rollback,
3061 std::string("player:")+player->getName());
3063 // Check the target node for rollback data; leave others unnoticed
3064 RollbackNode rn_old(&m_env->getMap(), p, this);
3066 scriptapi_node_on_receive_fields(m_lua, p, formname, fields,
3069 // Report rollback data
3070 RollbackNode rn_new(&m_env->getMap(), p, this);
3071 if(rollback() && rn_new != rn_old){
3072 RollbackAction action;
3073 action.setSetNode(p, rn_old, rn_new);
3074 rollback()->reportAction(action);
3077 else if(command == TOSERVER_INVENTORY_FIELDS)
3079 std::string datastring((char*)&data[2], datasize-2);
3080 std::istringstream is(datastring, std::ios_base::binary);
3082 std::string formname = deSerializeString(is);
3083 int num = readU16(is);
3084 std::map<std::string, std::string> fields;
3085 for(int k=0; k<num; k++){
3086 std::string fieldname = deSerializeString(is);
3087 std::string fieldvalue = deSerializeLongString(is);
3088 fields[fieldname] = fieldvalue;
3091 scriptapi_on_player_receive_fields(m_lua, playersao, formname, fields);
3095 infostream<<"Server::ProcessData(): Ignoring "
3096 "unknown command "<<command<<std::endl;
3100 catch(SendFailedException &e)
3102 errorstream<<"Server::ProcessData(): SendFailedException: "
3108 void Server::onMapEditEvent(MapEditEvent *event)
3110 //infostream<<"Server::onMapEditEvent()"<<std::endl;
3111 if(m_ignore_map_edit_events)
3113 if(m_ignore_map_edit_events_area.contains(event->getArea()))
3115 MapEditEvent *e = event->clone();
3116 m_unsent_map_edit_queue.push_back(e);
3119 Inventory* Server::getInventory(const InventoryLocation &loc)
3122 case InventoryLocation::UNDEFINED:
3125 case InventoryLocation::CURRENT_PLAYER:
3128 case InventoryLocation::PLAYER:
3130 Player *player = m_env->getPlayer(loc.name.c_str());
3133 PlayerSAO *playersao = player->getPlayerSAO();
3136 return playersao->getInventory();
3139 case InventoryLocation::NODEMETA:
3141 NodeMetadata *meta = m_env->getMap().getNodeMetadata(loc.p);
3144 return meta->getInventory();
3147 case InventoryLocation::DETACHED:
3149 if(m_detached_inventories.count(loc.name) == 0)
3151 return m_detached_inventories[loc.name];
3159 void Server::setInventoryModified(const InventoryLocation &loc)
3162 case InventoryLocation::UNDEFINED:
3165 case InventoryLocation::PLAYER:
3167 Player *player = m_env->getPlayer(loc.name.c_str());
3170 PlayerSAO *playersao = player->getPlayerSAO();
3173 playersao->m_inventory_not_sent = true;
3174 playersao->m_wielded_item_not_sent = true;
3177 case InventoryLocation::NODEMETA:
3179 v3s16 blockpos = getNodeBlockPos(loc.p);
3181 MapBlock *block = m_env->getMap().getBlockNoCreateNoEx(blockpos);
3183 block->raiseModified(MOD_STATE_WRITE_NEEDED);
3185 setBlockNotSent(blockpos);
3188 case InventoryLocation::DETACHED:
3190 sendDetachedInventoryToAll(loc.name);
3198 std::list<PlayerInfo> Server::getPlayerInfo()
3200 DSTACK(__FUNCTION_NAME);
3201 JMutexAutoLock envlock(m_env_mutex);
3202 JMutexAutoLock conlock(m_con_mutex);
3204 std::list<PlayerInfo> list;
3206 std::list<Player*> players = m_env->getPlayers();
3208 std::list<Player*>::iterator i;
3209 for(i = players.begin();
3210 i != players.end(); ++i)
3214 Player *player = *i;
3217 // Copy info from connection to info struct
3218 info.id = player->peer_id;
3219 info.address = m_con.GetPeerAddress(player->peer_id);
3220 info.avg_rtt = m_con.GetPeerAvgRTT(player->peer_id);
3222 catch(con::PeerNotFoundException &e)
3224 // Set dummy peer info
3226 info.address = Address(0,0,0,0,0);
3230 snprintf(info.name, PLAYERNAME_SIZE, "%s", player->getName());
3231 info.position = player->getPosition();
3233 list.push_back(info);
3240 void Server::peerAdded(con::Peer *peer)
3242 DSTACK(__FUNCTION_NAME);
3243 verbosestream<<"Server::peerAdded(): peer->id="
3244 <<peer->id<<std::endl;
3247 c.type = PEER_ADDED;
3248 c.peer_id = peer->id;
3250 m_peer_change_queue.push_back(c);
3253 void Server::deletingPeer(con::Peer *peer, bool timeout)
3255 DSTACK(__FUNCTION_NAME);
3256 verbosestream<<"Server::deletingPeer(): peer->id="
3257 <<peer->id<<", timeout="<<timeout<<std::endl;
3260 c.type = PEER_REMOVED;
3261 c.peer_id = peer->id;
3262 c.timeout = timeout;
3263 m_peer_change_queue.push_back(c);
3270 void Server::SendMovement(con::Connection &con, u16 peer_id)
3272 DSTACK(__FUNCTION_NAME);
3273 std::ostringstream os(std::ios_base::binary);
3275 writeU16(os, TOCLIENT_MOVEMENT);
3276 writeF1000(os, g_settings->getFloat("movement_acceleration_default"));
3277 writeF1000(os, g_settings->getFloat("movement_acceleration_air"));
3278 writeF1000(os, g_settings->getFloat("movement_acceleration_fast"));
3279 writeF1000(os, g_settings->getFloat("movement_speed_walk"));
3280 writeF1000(os, g_settings->getFloat("movement_speed_crouch"));
3281 writeF1000(os, g_settings->getFloat("movement_speed_fast"));
3282 writeF1000(os, g_settings->getFloat("movement_speed_climb"));
3283 writeF1000(os, g_settings->getFloat("movement_speed_jump"));
3284 writeF1000(os, g_settings->getFloat("movement_liquid_fluidity"));
3285 writeF1000(os, g_settings->getFloat("movement_liquid_fluidity_smooth"));
3286 writeF1000(os, g_settings->getFloat("movement_liquid_sink"));
3287 writeF1000(os, g_settings->getFloat("movement_gravity"));
3290 std::string s = os.str();
3291 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3293 con.Send(peer_id, 0, data, true);
3296 void Server::SendHP(con::Connection &con, u16 peer_id, u8 hp)
3298 DSTACK(__FUNCTION_NAME);
3299 std::ostringstream os(std::ios_base::binary);
3301 writeU16(os, TOCLIENT_HP);
3305 std::string s = os.str();
3306 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3308 con.Send(peer_id, 0, data, true);
3311 void Server::SendAccessDenied(con::Connection &con, u16 peer_id,
3312 const std::wstring &reason)
3314 DSTACK(__FUNCTION_NAME);
3315 std::ostringstream os(std::ios_base::binary);
3317 writeU16(os, TOCLIENT_ACCESS_DENIED);
3318 os<<serializeWideString(reason);
3321 std::string s = os.str();
3322 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3324 con.Send(peer_id, 0, data, true);
3327 void Server::SendDeathscreen(con::Connection &con, u16 peer_id,
3328 bool set_camera_point_target, v3f camera_point_target)
3330 DSTACK(__FUNCTION_NAME);
3331 std::ostringstream os(std::ios_base::binary);
3333 writeU16(os, TOCLIENT_DEATHSCREEN);
3334 writeU8(os, set_camera_point_target);
3335 writeV3F1000(os, camera_point_target);
3338 std::string s = os.str();
3339 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3341 con.Send(peer_id, 0, data, true);
3344 void Server::SendItemDef(con::Connection &con, u16 peer_id,
3345 IItemDefManager *itemdef)
3347 DSTACK(__FUNCTION_NAME);
3348 std::ostringstream os(std::ios_base::binary);
3352 u32 length of the next item
3353 zlib-compressed serialized ItemDefManager
3355 writeU16(os, TOCLIENT_ITEMDEF);
3356 std::ostringstream tmp_os(std::ios::binary);
3357 itemdef->serialize(tmp_os);
3358 std::ostringstream tmp_os2(std::ios::binary);
3359 compressZlib(tmp_os.str(), tmp_os2);
3360 os<<serializeLongString(tmp_os2.str());
3363 std::string s = os.str();
3364 verbosestream<<"Server: Sending item definitions to id("<<peer_id
3365 <<"): size="<<s.size()<<std::endl;
3366 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3368 con.Send(peer_id, 0, data, true);
3371 void Server::SendNodeDef(con::Connection &con, u16 peer_id,
3372 INodeDefManager *nodedef, u16 protocol_version)
3374 DSTACK(__FUNCTION_NAME);
3375 std::ostringstream os(std::ios_base::binary);
3379 u32 length of the next item
3380 zlib-compressed serialized NodeDefManager
3382 writeU16(os, TOCLIENT_NODEDEF);
3383 std::ostringstream tmp_os(std::ios::binary);
3384 nodedef->serialize(tmp_os, protocol_version);
3385 std::ostringstream tmp_os2(std::ios::binary);
3386 compressZlib(tmp_os.str(), tmp_os2);
3387 os<<serializeLongString(tmp_os2.str());
3390 std::string s = os.str();
3391 verbosestream<<"Server: Sending node definitions to id("<<peer_id
3392 <<"): size="<<s.size()<<std::endl;
3393 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3395 con.Send(peer_id, 0, data, true);
3399 Non-static send methods
3402 void Server::SendInventory(u16 peer_id)
3404 DSTACK(__FUNCTION_NAME);
3406 PlayerSAO *playersao = getPlayerSAO(peer_id);
3409 playersao->m_inventory_not_sent = false;
3415 std::ostringstream os;
3416 playersao->getInventory()->serialize(os);
3418 std::string s = os.str();
3420 SharedBuffer<u8> data(s.size()+2);
3421 writeU16(&data[0], TOCLIENT_INVENTORY);
3422 memcpy(&data[2], s.c_str(), s.size());
3425 m_con.Send(peer_id, 0, data, true);
3428 void Server::SendChatMessage(u16 peer_id, const std::wstring &message)
3430 DSTACK(__FUNCTION_NAME);
3432 std::ostringstream os(std::ios_base::binary);
3436 writeU16(buf, TOCLIENT_CHAT_MESSAGE);
3437 os.write((char*)buf, 2);
3440 writeU16(buf, message.size());
3441 os.write((char*)buf, 2);
3444 for(u32 i=0; i<message.size(); i++)
3448 os.write((char*)buf, 2);
3452 std::string s = os.str();
3453 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3455 m_con.Send(peer_id, 0, data, true);
3457 void Server::SendShowFormspecMessage(u16 peer_id, const std::string formspec, const std::string formname)
3459 DSTACK(__FUNCTION_NAME);
3461 std::ostringstream os(std::ios_base::binary);
3465 writeU16(buf, TOCLIENT_SHOW_FORMSPEC);
3466 os.write((char*)buf, 2);
3467 os<<serializeLongString(formspec);
3468 os<<serializeString(formname);
3471 std::string s = os.str();
3472 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3474 m_con.Send(peer_id, 0, data, true);
3477 void Server::BroadcastChatMessage(const std::wstring &message)
3479 for(std::map<u16, RemoteClient*>::iterator
3480 i = m_clients.begin();
3481 i != m_clients.end(); ++i)
3483 // Get client and check that it is valid
3484 RemoteClient *client = i->second;
3485 assert(client->peer_id == i->first);
3486 if(client->serialization_version == SER_FMT_VER_INVALID)
3489 SendChatMessage(client->peer_id, message);
3493 void Server::SendPlayerHP(u16 peer_id)
3495 DSTACK(__FUNCTION_NAME);
3496 PlayerSAO *playersao = getPlayerSAO(peer_id);
3498 playersao->m_hp_not_sent = false;
3499 SendHP(m_con, peer_id, playersao->getHP());
3502 void Server::SendMovePlayer(u16 peer_id)
3504 DSTACK(__FUNCTION_NAME);
3505 Player *player = m_env->getPlayer(peer_id);
3508 std::ostringstream os(std::ios_base::binary);
3509 writeU16(os, TOCLIENT_MOVE_PLAYER);
3510 writeV3F1000(os, player->getPosition());
3511 writeF1000(os, player->getPitch());
3512 writeF1000(os, player->getYaw());
3515 v3f pos = player->getPosition();
3516 f32 pitch = player->getPitch();
3517 f32 yaw = player->getYaw();
3518 verbosestream<<"Server: Sending TOCLIENT_MOVE_PLAYER"
3519 <<" pos=("<<pos.X<<","<<pos.Y<<","<<pos.Z<<")"
3526 std::string s = os.str();
3527 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3529 m_con.Send(peer_id, 0, data, true);
3532 void Server::SendPlayerPrivileges(u16 peer_id)
3534 Player *player = m_env->getPlayer(peer_id);
3536 if(player->peer_id == PEER_ID_INEXISTENT)
3539 std::set<std::string> privs;
3540 scriptapi_get_auth(m_lua, player->getName(), NULL, &privs);
3542 std::ostringstream os(std::ios_base::binary);
3543 writeU16(os, TOCLIENT_PRIVILEGES);
3544 writeU16(os, privs.size());
3545 for(std::set<std::string>::const_iterator i = privs.begin();
3546 i != privs.end(); i++){
3547 os<<serializeString(*i);
3551 std::string s = os.str();
3552 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3554 m_con.Send(peer_id, 0, data, true);
3557 void Server::SendPlayerInventoryFormspec(u16 peer_id)
3559 Player *player = m_env->getPlayer(peer_id);
3561 if(player->peer_id == PEER_ID_INEXISTENT)
3564 std::ostringstream os(std::ios_base::binary);
3565 writeU16(os, TOCLIENT_INVENTORY_FORMSPEC);
3566 os<<serializeLongString(player->inventory_formspec);
3569 std::string s = os.str();
3570 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3572 m_con.Send(peer_id, 0, data, true);
3575 s32 Server::playSound(const SimpleSoundSpec &spec,
3576 const ServerSoundParams ¶ms)
3578 // Find out initial position of sound
3579 bool pos_exists = false;
3580 v3f pos = params.getPos(m_env, &pos_exists);
3581 // If position is not found while it should be, cancel sound
3582 if(pos_exists != (params.type != ServerSoundParams::SSP_LOCAL))
3584 // Filter destination clients
3585 std::set<RemoteClient*> dst_clients;
3586 if(params.to_player != "")
3588 Player *player = m_env->getPlayer(params.to_player.c_str());
3590 infostream<<"Server::playSound: Player \""<<params.to_player
3591 <<"\" not found"<<std::endl;
3594 if(player->peer_id == PEER_ID_INEXISTENT){
3595 infostream<<"Server::playSound: Player \""<<params.to_player
3596 <<"\" not connected"<<std::endl;
3599 RemoteClient *client = getClient(player->peer_id);
3600 dst_clients.insert(client);
3604 for(std::map<u16, RemoteClient*>::iterator
3605 i = m_clients.begin(); i != m_clients.end(); ++i)
3607 RemoteClient *client = i->second;
3608 Player *player = m_env->getPlayer(client->peer_id);
3612 if(player->getPosition().getDistanceFrom(pos) >
3613 params.max_hear_distance)
3616 dst_clients.insert(client);
3619 if(dst_clients.size() == 0)
3622 s32 id = m_next_sound_id++;
3623 // The sound will exist as a reference in m_playing_sounds
3624 m_playing_sounds[id] = ServerPlayingSound();
3625 ServerPlayingSound &psound = m_playing_sounds[id];
3626 psound.params = params;
3627 for(std::set<RemoteClient*>::iterator i = dst_clients.begin();
3628 i != dst_clients.end(); i++)
3629 psound.clients.insert((*i)->peer_id);
3631 std::ostringstream os(std::ios_base::binary);
3632 writeU16(os, TOCLIENT_PLAY_SOUND);
3634 os<<serializeString(spec.name);
3635 writeF1000(os, spec.gain * params.gain);
3636 writeU8(os, params.type);
3637 writeV3F1000(os, pos);
3638 writeU16(os, params.object);
3639 writeU8(os, params.loop);
3641 std::string s = os.str();
3642 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3644 for(std::set<RemoteClient*>::iterator i = dst_clients.begin();
3645 i != dst_clients.end(); i++){
3647 m_con.Send((*i)->peer_id, 0, data, true);
3651 void Server::stopSound(s32 handle)
3653 // Get sound reference
3654 std::map<s32, ServerPlayingSound>::iterator i =
3655 m_playing_sounds.find(handle);
3656 if(i == m_playing_sounds.end())
3658 ServerPlayingSound &psound = i->second;
3660 std::ostringstream os(std::ios_base::binary);
3661 writeU16(os, TOCLIENT_STOP_SOUND);
3662 writeS32(os, handle);
3664 std::string s = os.str();
3665 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3667 for(std::set<u16>::iterator i = psound.clients.begin();
3668 i != psound.clients.end(); i++){
3670 m_con.Send(*i, 0, data, true);
3672 // Remove sound reference
3673 m_playing_sounds.erase(i);
3676 void Server::sendRemoveNode(v3s16 p, u16 ignore_id,
3677 std::list<u16> *far_players, float far_d_nodes)
3679 float maxd = far_d_nodes*BS;
3680 v3f p_f = intToFloat(p, BS);
3684 SharedBuffer<u8> reply(replysize);
3685 writeU16(&reply[0], TOCLIENT_REMOVENODE);
3686 writeS16(&reply[2], p.X);
3687 writeS16(&reply[4], p.Y);
3688 writeS16(&reply[6], p.Z);
3690 for(std::map<u16, RemoteClient*>::iterator
3691 i = m_clients.begin();
3692 i != m_clients.end(); ++i)
3694 // Get client and check that it is valid
3695 RemoteClient *client = i->second;
3696 assert(client->peer_id == i->first);
3697 if(client->serialization_version == SER_FMT_VER_INVALID)
3700 // Don't send if it's the same one
3701 if(client->peer_id == ignore_id)
3707 Player *player = m_env->getPlayer(client->peer_id);
3710 // If player is far away, only set modified blocks not sent
3711 v3f player_pos = player->getPosition();
3712 if(player_pos.getDistanceFrom(p_f) > maxd)
3714 far_players->push_back(client->peer_id);
3721 m_con.Send(client->peer_id, 0, reply, true);
3725 void Server::sendAddNode(v3s16 p, MapNode n, u16 ignore_id,
3726 std::list<u16> *far_players, float far_d_nodes)
3728 float maxd = far_d_nodes*BS;
3729 v3f p_f = intToFloat(p, BS);
3731 for(std::map<u16, RemoteClient*>::iterator
3732 i = m_clients.begin();
3733 i != m_clients.end(); ++i)
3735 // Get client and check that it is valid
3736 RemoteClient *client = i->second;
3737 assert(client->peer_id == i->first);
3738 if(client->serialization_version == SER_FMT_VER_INVALID)
3741 // Don't send if it's the same one
3742 if(client->peer_id == ignore_id)
3748 Player *player = m_env->getPlayer(client->peer_id);
3751 // If player is far away, only set modified blocks not sent
3752 v3f player_pos = player->getPosition();
3753 if(player_pos.getDistanceFrom(p_f) > maxd)
3755 far_players->push_back(client->peer_id);
3762 u32 replysize = 8 + MapNode::serializedLength(client->serialization_version);
3763 SharedBuffer<u8> reply(replysize);
3764 writeU16(&reply[0], TOCLIENT_ADDNODE);
3765 writeS16(&reply[2], p.X);
3766 writeS16(&reply[4], p.Y);
3767 writeS16(&reply[6], p.Z);
3768 n.serialize(&reply[8], client->serialization_version);
3771 m_con.Send(client->peer_id, 0, reply, true);
3775 void Server::setBlockNotSent(v3s16 p)
3777 for(std::map<u16, RemoteClient*>::iterator
3778 i = m_clients.begin();
3779 i != m_clients.end(); ++i)
3781 RemoteClient *client = i->second;
3782 client->SetBlockNotSent(p);
3786 void Server::SendBlockNoLock(u16 peer_id, MapBlock *block, u8 ver)
3788 DSTACK(__FUNCTION_NAME);
3790 v3s16 p = block->getPos();
3794 bool completely_air = true;
3795 for(s16 z0=0; z0<MAP_BLOCKSIZE; z0++)
3796 for(s16 x0=0; x0<MAP_BLOCKSIZE; x0++)
3797 for(s16 y0=0; y0<MAP_BLOCKSIZE; y0++)
3799 if(block->getNodeNoEx(v3s16(x0,y0,z0)).d != CONTENT_AIR)
3801 completely_air = false;
3802 x0 = y0 = z0 = MAP_BLOCKSIZE; // Break out
3807 infostream<<"Server: Sending block ("<<p.X<<","<<p.Y<<","<<p.Z<<"): ";
3809 infostream<<"[completely air] ";
3810 infostream<<std::endl;
3814 Create a packet with the block in the right format
3817 std::ostringstream os(std::ios_base::binary);
3818 block->serialize(os, ver, false);
3819 std::string s = os.str();
3820 SharedBuffer<u8> blockdata((u8*)s.c_str(), s.size());
3822 u32 replysize = 8 + blockdata.getSize();
3823 SharedBuffer<u8> reply(replysize);
3824 writeU16(&reply[0], TOCLIENT_BLOCKDATA);
3825 writeS16(&reply[2], p.X);
3826 writeS16(&reply[4], p.Y);
3827 writeS16(&reply[6], p.Z);
3828 memcpy(&reply[8], *blockdata, blockdata.getSize());
3830 /*infostream<<"Server: Sending block ("<<p.X<<","<<p.Y<<","<<p.Z<<")"
3831 <<": \tpacket size: "<<replysize<<std::endl;*/
3836 m_con.Send(peer_id, 1, reply, true);
3839 void Server::SendBlocks(float dtime)
3841 DSTACK(__FUNCTION_NAME);
3843 JMutexAutoLock envlock(m_env_mutex);
3844 JMutexAutoLock conlock(m_con_mutex);
3846 ScopeProfiler sp(g_profiler, "Server: sel and send blocks to clients");
3848 std::vector<PrioritySortedBlockTransfer> queue;
3850 s32 total_sending = 0;
3853 ScopeProfiler sp(g_profiler, "Server: selecting blocks for sending");
3855 for(std::map<u16, RemoteClient*>::iterator
3856 i = m_clients.begin();
3857 i != m_clients.end(); ++i)
3859 RemoteClient *client = i->second;
3860 assert(client->peer_id == i->first);
3862 // If definitions and textures have not been sent, don't
3863 // send MapBlocks either
3864 if(!client->definitions_sent)
3867 total_sending += client->SendingCount();
3869 if(client->serialization_version == SER_FMT_VER_INVALID)
3872 client->GetNextBlocks(this, dtime, queue);
3877 // Lowest priority number comes first.
3878 // Lowest is most important.
3879 std::sort(queue.begin(), queue.end());
3881 for(u32 i=0; i<queue.size(); i++)
3883 //TODO: Calculate limit dynamically
3884 if(total_sending >= g_settings->getS32
3885 ("max_simultaneous_block_sends_server_total"))
3888 PrioritySortedBlockTransfer q = queue[i];
3890 MapBlock *block = NULL;
3893 block = m_env->getMap().getBlockNoCreate(q.pos);
3895 catch(InvalidPositionException &e)
3900 RemoteClient *client = getClient(q.peer_id);
3902 SendBlockNoLock(q.peer_id, block, client->serialization_version);
3904 client->SentBlock(q.pos);
3910 void Server::fillMediaCache()
3912 DSTACK(__FUNCTION_NAME);
3914 infostream<<"Server: Calculating media file checksums"<<std::endl;
3916 // Collect all media file paths
3917 std::list<std::string> paths;
3918 for(std::vector<ModSpec>::iterator i = m_mods.begin();
3919 i != m_mods.end(); i++){
3920 const ModSpec &mod = *i;
3921 paths.push_back(mod.path + DIR_DELIM + "textures");
3922 paths.push_back(mod.path + DIR_DELIM + "sounds");
3923 paths.push_back(mod.path + DIR_DELIM + "media");
3924 paths.push_back(mod.path + DIR_DELIM + "models");
3926 std::string path_all = "textures";
3927 paths.push_back(path_all + DIR_DELIM + "all");
3929 // Collect media file information from paths into cache
3930 for(std::list<std::string>::iterator i = paths.begin();
3931 i != paths.end(); i++)
3933 std::string mediapath = *i;
3934 std::vector<fs::DirListNode> dirlist = fs::GetDirListing(mediapath);
3935 for(u32 j=0; j<dirlist.size(); j++){
3936 if(dirlist[j].dir) // Ignode dirs
3938 std::string filename = dirlist[j].name;
3939 // If name contains illegal characters, ignore the file
3940 if(!string_allowed(filename, TEXTURENAME_ALLOWED_CHARS)){
3941 infostream<<"Server: ignoring illegal file name: \""
3942 <<filename<<"\""<<std::endl;
3945 // If name is not in a supported format, ignore it
3946 const char *supported_ext[] = {
3947 ".png", ".jpg", ".bmp", ".tga",
3948 ".pcx", ".ppm", ".psd", ".wal", ".rgb",
3950 ".x", ".b3d", ".md2", ".obj",
3953 if(removeStringEnd(filename, supported_ext) == ""){
3954 infostream<<"Server: ignoring unsupported file extension: \""
3955 <<filename<<"\""<<std::endl;
3958 // Ok, attempt to load the file and add to cache
3959 std::string filepath = mediapath + DIR_DELIM + filename;
3961 std::ifstream fis(filepath.c_str(), std::ios_base::binary);
3962 if(fis.good() == false){
3963 errorstream<<"Server::fillMediaCache(): Could not open \""
3964 <<filename<<"\" for reading"<<std::endl;
3967 std::ostringstream tmp_os(std::ios_base::binary);
3971 fis.read(buf, 1024);
3972 std::streamsize len = fis.gcount();
3973 tmp_os.write(buf, len);
3982 errorstream<<"Server::fillMediaCache(): Failed to read \""
3983 <<filename<<"\""<<std::endl;
3986 if(tmp_os.str().length() == 0){
3987 errorstream<<"Server::fillMediaCache(): Empty file \""
3988 <<filepath<<"\""<<std::endl;
3993 sha1.addBytes(tmp_os.str().c_str(), tmp_os.str().length());
3995 unsigned char *digest = sha1.getDigest();
3996 std::string sha1_base64 = base64_encode(digest, 20);
3997 std::string sha1_hex = hex_encode((char*)digest, 20);
4001 this->m_media[filename] = MediaInfo(filepath, sha1_base64);
4002 verbosestream<<"Server: "<<sha1_hex<<" is "<<filename<<std::endl;
4007 struct SendableMediaAnnouncement
4010 std::string sha1_digest;
4012 SendableMediaAnnouncement(const std::string name_="",
4013 const std::string sha1_digest_=""):
4015 sha1_digest(sha1_digest_)
4019 void Server::sendMediaAnnouncement(u16 peer_id)
4021 DSTACK(__FUNCTION_NAME);
4023 verbosestream<<"Server: Announcing files to id("<<peer_id<<")"
4026 std::list<SendableMediaAnnouncement> file_announcements;
4028 for(std::map<std::string, MediaInfo>::iterator i = m_media.begin();
4029 i != m_media.end(); i++){
4031 file_announcements.push_back(
4032 SendableMediaAnnouncement(i->first, i->second.sha1_digest));
4036 std::ostringstream os(std::ios_base::binary);
4044 u16 length of sha1_digest
4049 writeU16(os, TOCLIENT_ANNOUNCE_MEDIA);
4050 writeU16(os, file_announcements.size());
4052 for(std::list<SendableMediaAnnouncement>::iterator
4053 j = file_announcements.begin();
4054 j != file_announcements.end(); ++j){
4055 os<<serializeString(j->name);
4056 os<<serializeString(j->sha1_digest);
4058 os<<serializeString(g_settings->get("remote_media"));
4061 std::string s = os.str();
4062 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
4065 m_con.Send(peer_id, 0, data, true);
4068 struct SendableMedia
4074 SendableMedia(const std::string &name_="", const std::string path_="",
4075 const std::string &data_=""):
4082 void Server::sendRequestedMedia(u16 peer_id,
4083 const std::list<MediaRequest> &tosend)
4085 DSTACK(__FUNCTION_NAME);
4087 verbosestream<<"Server::sendRequestedMedia(): "
4088 <<"Sending files to client"<<std::endl;
4092 // Put 5kB in one bunch (this is not accurate)
4093 u32 bytes_per_bunch = 5000;
4095 std::vector< std::list<SendableMedia> > file_bunches;
4096 file_bunches.push_back(std::list<SendableMedia>());
4098 u32 file_size_bunch_total = 0;
4100 for(std::list<MediaRequest>::const_iterator i = tosend.begin();
4101 i != tosend.end(); ++i)
4103 if(m_media.find(i->name) == m_media.end()){
4104 errorstream<<"Server::sendRequestedMedia(): Client asked for "
4105 <<"unknown file \""<<(i->name)<<"\""<<std::endl;
4109 //TODO get path + name
4110 std::string tpath = m_media[(*i).name].path;
4113 std::ifstream fis(tpath.c_str(), std::ios_base::binary);
4114 if(fis.good() == false){
4115 errorstream<<"Server::sendRequestedMedia(): Could not open \""
4116 <<tpath<<"\" for reading"<<std::endl;
4119 std::ostringstream tmp_os(std::ios_base::binary);
4123 fis.read(buf, 1024);
4124 std::streamsize len = fis.gcount();
4125 tmp_os.write(buf, len);
4126 file_size_bunch_total += len;
4135 errorstream<<"Server::sendRequestedMedia(): Failed to read \""
4136 <<(*i).name<<"\""<<std::endl;
4139 /*infostream<<"Server::sendRequestedMedia(): Loaded \""
4140 <<tname<<"\""<<std::endl;*/
4142 file_bunches[file_bunches.size()-1].push_back(
4143 SendableMedia((*i).name, tpath, tmp_os.str()));
4145 // Start next bunch if got enough data
4146 if(file_size_bunch_total >= bytes_per_bunch){
4147 file_bunches.push_back(std::list<SendableMedia>());
4148 file_size_bunch_total = 0;
4153 /* Create and send packets */
4155 u32 num_bunches = file_bunches.size();
4156 for(u32 i=0; i<num_bunches; i++)
4158 std::ostringstream os(std::ios_base::binary);
4162 u16 total number of texture bunches
4163 u16 index of this bunch
4164 u32 number of files in this bunch
4173 writeU16(os, TOCLIENT_MEDIA);
4174 writeU16(os, num_bunches);
4176 writeU32(os, file_bunches[i].size());
4178 for(std::list<SendableMedia>::iterator
4179 j = file_bunches[i].begin();
4180 j != file_bunches[i].end(); ++j){
4181 os<<serializeString(j->name);
4182 os<<serializeLongString(j->data);
4186 std::string s = os.str();
4187 verbosestream<<"Server::sendRequestedMedia(): bunch "
4188 <<i<<"/"<<num_bunches
4189 <<" files="<<file_bunches[i].size()
4190 <<" size=" <<s.size()<<std::endl;
4191 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
4193 m_con.Send(peer_id, 0, data, true);
4197 void Server::sendDetachedInventory(const std::string &name, u16 peer_id)
4199 if(m_detached_inventories.count(name) == 0){
4200 errorstream<<__FUNCTION_NAME<<": \""<<name<<"\" not found"<<std::endl;
4203 Inventory *inv = m_detached_inventories[name];
4205 std::ostringstream os(std::ios_base::binary);
4206 writeU16(os, TOCLIENT_DETACHED_INVENTORY);
4207 os<<serializeString(name);
4211 std::string s = os.str();
4212 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
4214 m_con.Send(peer_id, 0, data, true);
4217 void Server::sendDetachedInventoryToAll(const std::string &name)
4219 DSTACK(__FUNCTION_NAME);
4221 for(std::map<u16, RemoteClient*>::iterator
4222 i = m_clients.begin();
4223 i != m_clients.end(); ++i){
4224 RemoteClient *client = i->second;
4225 sendDetachedInventory(name, client->peer_id);
4229 void Server::sendDetachedInventories(u16 peer_id)
4231 DSTACK(__FUNCTION_NAME);
4233 for(std::map<std::string, Inventory*>::iterator
4234 i = m_detached_inventories.begin();
4235 i != m_detached_inventories.end(); i++){
4236 const std::string &name = i->first;
4237 //Inventory *inv = i->second;
4238 sendDetachedInventory(name, peer_id);
4246 void Server::DiePlayer(u16 peer_id)
4248 DSTACK(__FUNCTION_NAME);
4250 PlayerSAO *playersao = getPlayerSAO(peer_id);
4253 infostream<<"Server::DiePlayer(): Player "
4254 <<playersao->getPlayer()->getName()
4255 <<" dies"<<std::endl;
4257 playersao->setHP(0);
4259 // Trigger scripted stuff
4260 scriptapi_on_dieplayer(m_lua, playersao);
4262 SendPlayerHP(peer_id);
4263 SendDeathscreen(m_con, peer_id, false, v3f(0,0,0));
4266 void Server::RespawnPlayer(u16 peer_id)
4268 DSTACK(__FUNCTION_NAME);
4270 PlayerSAO *playersao = getPlayerSAO(peer_id);
4273 infostream<<"Server::RespawnPlayer(): Player "
4274 <<playersao->getPlayer()->getName()
4275 <<" respawns"<<std::endl;
4277 playersao->setHP(PLAYER_MAX_HP);
4279 bool repositioned = scriptapi_on_respawnplayer(m_lua, playersao);
4281 v3f pos = findSpawnPos(m_env->getServerMap());
4282 playersao->setPos(pos);
4286 void Server::UpdateCrafting(u16 peer_id)
4288 DSTACK(__FUNCTION_NAME);
4290 Player* player = m_env->getPlayer(peer_id);
4293 // Get a preview for crafting
4295 getCraftingResult(&player->inventory, preview, false, this);
4297 // Put the new preview in
4298 InventoryList *plist = player->inventory.getList("craftpreview");
4300 assert(plist->getSize() >= 1);
4301 plist->changeItem(0, preview);
4304 RemoteClient* Server::getClient(u16 peer_id)
4306 DSTACK(__FUNCTION_NAME);
4307 //JMutexAutoLock lock(m_con_mutex);
4308 std::map<u16, RemoteClient*>::iterator n;
4309 n = m_clients.find(peer_id);
4310 // A client should exist for all peers
4311 assert(n != m_clients.end());
4315 std::wstring Server::getStatusString()
4317 std::wostringstream os(std::ios_base::binary);
4320 os<<L"version="<<narrow_to_wide(VERSION_STRING);
4322 os<<L", uptime="<<m_uptime.get();
4323 // Information about clients
4324 std::map<u16, RemoteClient*>::iterator i;
4327 for(i = m_clients.begin(), first = true;
4328 i != m_clients.end(); ++i)
4330 // Get client and check that it is valid
4331 RemoteClient *client = i->second;
4332 assert(client->peer_id == i->first);
4333 if(client->serialization_version == SER_FMT_VER_INVALID)
4336 Player *player = m_env->getPlayer(client->peer_id);
4337 // Get name of player
4338 std::wstring name = L"unknown";
4340 name = narrow_to_wide(player->getName());
4341 // Add name to information string
4349 if(((ServerMap*)(&m_env->getMap()))->isSavingEnabled() == false)
4350 os<<std::endl<<L"# Server: "<<" WARNING: Map saving is disabled.";
4351 if(g_settings->get("motd") != "")
4352 os<<std::endl<<L"# Server: "<<narrow_to_wide(g_settings->get("motd"));
4356 std::set<std::string> Server::getPlayerEffectivePrivs(const std::string &name)
4358 std::set<std::string> privs;
4359 scriptapi_get_auth(m_lua, name, NULL, &privs);
4363 bool Server::checkPriv(const std::string &name, const std::string &priv)
4365 std::set<std::string> privs = getPlayerEffectivePrivs(name);
4366 return (privs.count(priv) != 0);
4369 void Server::reportPrivsModified(const std::string &name)
4372 for(std::map<u16, RemoteClient*>::iterator
4373 i = m_clients.begin();
4374 i != m_clients.end(); ++i){
4375 RemoteClient *client = i->second;
4376 Player *player = m_env->getPlayer(client->peer_id);
4377 reportPrivsModified(player->getName());
4380 Player *player = m_env->getPlayer(name.c_str());
4383 SendPlayerPrivileges(player->peer_id);
4384 PlayerSAO *sao = player->getPlayerSAO();
4387 sao->updatePrivileges(
4388 getPlayerEffectivePrivs(name),
4393 void Server::reportInventoryFormspecModified(const std::string &name)
4395 Player *player = m_env->getPlayer(name.c_str());
4398 SendPlayerInventoryFormspec(player->peer_id);
4401 // Saves g_settings to configpath given at initialization
4402 void Server::saveConfig()
4404 if(m_path_config != "")
4405 g_settings->updateConfigFile(m_path_config.c_str());
4408 void Server::notifyPlayer(const char *name, const std::wstring msg)
4410 Player *player = m_env->getPlayer(name);
4413 SendChatMessage(player->peer_id, std::wstring(L"Server: -!- ")+msg);
4416 bool Server::showFormspec(const char *playername, const std::string &formspec, const std::string &formname)
4418 Player *player = m_env->getPlayer(playername);
4422 infostream<<"showFormspec: couldn't find player:"<<playername<<std::endl;
4426 SendShowFormspecMessage(player->peer_id, formspec, formname);
4430 void Server::notifyPlayers(const std::wstring msg)
4432 BroadcastChatMessage(msg);
4435 void Server::queueBlockEmerge(v3s16 blockpos, bool allow_generate)
4437 m_emerge->enqueueBlockEmerge(PEER_ID_INEXISTENT, blockpos, allow_generate);
4440 Inventory* Server::createDetachedInventory(const std::string &name)
4442 if(m_detached_inventories.count(name) > 0){
4443 infostream<<"Server clearing detached inventory \""<<name<<"\""<<std::endl;
4444 delete m_detached_inventories[name];
4446 infostream<<"Server creating detached inventory \""<<name<<"\""<<std::endl;
4448 Inventory *inv = new Inventory(m_itemdef);
4450 m_detached_inventories[name] = inv;
4451 sendDetachedInventoryToAll(name);
4458 BoolScopeSet(bool *dst, bool val):
4461 m_orig_state = *m_dst;
4466 *m_dst = m_orig_state;
4473 // actions: time-reversed list
4474 // Return value: success/failure
4475 bool Server::rollbackRevertActions(const std::list<RollbackAction> &actions,
4476 std::list<std::string> *log)
4478 infostream<<"Server::rollbackRevertActions(len="<<actions.size()<<")"<<std::endl;
4479 ServerMap *map = (ServerMap*)(&m_env->getMap());
4480 // Disable rollback report sink while reverting
4481 BoolScopeSet rollback_scope_disable(&m_rollback_sink_enabled, false);
4483 // Fail if no actions to handle
4484 if(actions.empty()){
4485 log->push_back("Nothing to do.");
4492 for(std::list<RollbackAction>::const_iterator
4493 i = actions.begin();
4494 i != actions.end(); i++)
4496 const RollbackAction &action = *i;
4498 bool success = action.applyRevert(map, this, this);
4501 std::ostringstream os;
4502 os<<"Revert of step ("<<num_tried<<") "<<action.toString()<<" failed";
4503 infostream<<"Map::rollbackRevertActions(): "<<os.str()<<std::endl;
4505 log->push_back(os.str());
4507 std::ostringstream os;
4508 os<<"Successfully reverted step ("<<num_tried<<") "<<action.toString();
4509 infostream<<"Map::rollbackRevertActions(): "<<os.str()<<std::endl;
4511 log->push_back(os.str());
4515 infostream<<"Map::rollbackRevertActions(): "<<num_failed<<"/"<<num_tried
4516 <<" failed"<<std::endl;
4518 // Call it done if less than half failed
4519 return num_failed <= num_tried/2;
4522 // IGameDef interface
4524 IItemDefManager* Server::getItemDefManager()
4528 INodeDefManager* Server::getNodeDefManager()
4532 ICraftDefManager* Server::getCraftDefManager()
4536 ITextureSource* Server::getTextureSource()
4540 IShaderSource* Server::getShaderSource()
4544 u16 Server::allocateUnknownNodeId(const std::string &name)
4546 return m_nodedef->allocateDummy(name);
4548 ISoundManager* Server::getSoundManager()
4550 return &dummySoundManager;
4552 MtEventManager* Server::getEventManager()
4556 IRollbackReportSink* Server::getRollbackReportSink()
4558 if(!m_enable_rollback_recording)
4560 if(!m_rollback_sink_enabled)
4565 IWritableItemDefManager* Server::getWritableItemDefManager()
4569 IWritableNodeDefManager* Server::getWritableNodeDefManager()
4573 IWritableCraftDefManager* Server::getWritableCraftDefManager()
4578 const ModSpec* Server::getModSpec(const std::string &modname)
4580 for(std::vector<ModSpec>::iterator i = m_mods.begin();
4581 i != m_mods.end(); i++){
4582 const ModSpec &mod = *i;
4583 if(mod.name == modname)
4588 void Server::getModNames(std::list<std::string> &modlist)
4590 for(std::vector<ModSpec>::iterator i = m_mods.begin(); i != m_mods.end(); i++)
4592 modlist.push_back(i->name);
4595 std::string Server::getBuiltinLuaPath()
4597 return porting::path_share + DIR_DELIM + "builtin";
4600 v3f findSpawnPos(ServerMap &map)
4602 //return v3f(50,50,50)*BS;
4607 nodepos = v2s16(0,0);
4612 s16 water_level = map.m_mgparams->water_level;
4614 // Try to find a good place a few times
4615 for(s32 i=0; i<1000; i++)
4618 // We're going to try to throw the player to this position
4619 v2s16 nodepos2d = v2s16(-range + (myrand()%(range*2)),
4620 -range + (myrand()%(range*2)));
4621 //v2s16 sectorpos = getNodeSectorPos(nodepos2d);
4622 // Get ground height at point (fallbacks to heightmap function)
4623 s16 groundheight = map.findGroundLevel(nodepos2d);
4624 // Don't go underwater
4625 if(groundheight <= water_level)
4627 //infostream<<"-> Underwater"<<std::endl;
4630 // Don't go to high places
4631 if(groundheight > water_level + 6)
4633 //infostream<<"-> Underwater"<<std::endl;
4637 nodepos = v3s16(nodepos2d.X, groundheight-2, nodepos2d.Y);
4638 bool is_good = false;
4640 for(s32 i=0; i<10; i++){
4641 v3s16 blockpos = getNodeBlockPos(nodepos);
4642 map.emergeBlock(blockpos, true);
4643 MapNode n = map.getNodeNoEx(nodepos);
4644 if(n.getContent() == CONTENT_AIR){
4655 // Found a good place
4656 //infostream<<"Searched through "<<i<<" places."<<std::endl;
4662 return intToFloat(nodepos, BS);
4665 PlayerSAO* Server::emergePlayer(const char *name, u16 peer_id)
4667 RemotePlayer *player = NULL;
4668 bool newplayer = false;
4671 Try to get an existing player
4673 player = static_cast<RemotePlayer*>(m_env->getPlayer(name));
4675 // If player is already connected, cancel
4676 if(player != NULL && player->peer_id != 0)
4678 infostream<<"emergePlayer(): Player already connected"<<std::endl;
4683 If player with the wanted peer_id already exists, cancel.
4685 if(m_env->getPlayer(peer_id) != NULL)
4687 infostream<<"emergePlayer(): Player with wrong name but same"
4688 " peer_id already exists"<<std::endl;
4693 Create a new player if it doesn't exist yet
4698 player = new RemotePlayer(this);
4699 player->updateName(name);
4701 /* Set player position */
4702 infostream<<"Server: Finding spawn place for player \""
4703 <<name<<"\""<<std::endl;
4704 v3f pos = findSpawnPos(m_env->getServerMap());
4705 player->setPosition(pos);
4707 /* Add player to environment */
4708 m_env->addPlayer(player);
4712 Create a new player active object
4714 PlayerSAO *playersao = new PlayerSAO(m_env, player, peer_id,
4715 getPlayerEffectivePrivs(player->getName()),
4718 /* Add object to environment */
4719 m_env->addActiveObject(playersao);
4723 scriptapi_on_newplayer(m_lua, playersao);
4725 scriptapi_on_joinplayer(m_lua, playersao);
4730 void Server::handlePeerChange(PeerChange &c)
4732 JMutexAutoLock envlock(m_env_mutex);
4733 JMutexAutoLock conlock(m_con_mutex);
4735 if(c.type == PEER_ADDED)
4742 std::map<u16, RemoteClient*>::iterator n;
4743 n = m_clients.find(c.peer_id);
4744 // The client shouldn't already exist
4745 assert(n == m_clients.end());
4748 RemoteClient *client = new RemoteClient();
4749 client->peer_id = c.peer_id;
4750 m_clients[client->peer_id] = client;
4753 else if(c.type == PEER_REMOVED)
4760 std::map<u16, RemoteClient*>::iterator n;
4761 n = m_clients.find(c.peer_id);
4762 // The client should exist
4763 assert(n != m_clients.end());
4766 Mark objects to be not known by the client
4768 RemoteClient *client = n->second;
4770 for(std::set<u16>::iterator
4771 i = client->m_known_objects.begin();
4772 i != client->m_known_objects.end(); ++i)
4776 ServerActiveObject* obj = m_env->getActiveObject(id);
4778 if(obj && obj->m_known_by_count > 0)
4779 obj->m_known_by_count--;
4783 Clear references to playing sounds
4785 for(std::map<s32, ServerPlayingSound>::iterator
4786 i = m_playing_sounds.begin();
4787 i != m_playing_sounds.end();)
4789 ServerPlayingSound &psound = i->second;
4790 psound.clients.erase(c.peer_id);
4791 if(psound.clients.size() == 0)
4792 m_playing_sounds.erase(i++);
4797 Player *player = m_env->getPlayer(c.peer_id);
4799 // Collect information about leaving in chat
4800 std::wstring message;
4804 std::wstring name = narrow_to_wide(player->getName());
4807 message += L" left the game.";
4809 message += L" (timed out)";
4813 /* Run scripts and remove from environment */
4817 PlayerSAO *playersao = player->getPlayerSAO();
4820 scriptapi_on_leaveplayer(m_lua, playersao);
4822 playersao->disconnected();
4832 std::ostringstream os(std::ios_base::binary);
4833 for(std::map<u16, RemoteClient*>::iterator
4834 i = m_clients.begin();
4835 i != m_clients.end(); ++i)
4837 RemoteClient *client = i->second;
4838 assert(client->peer_id == i->first);
4839 if(client->serialization_version == SER_FMT_VER_INVALID)
4842 Player *player = m_env->getPlayer(client->peer_id);
4845 // Get name of player
4846 os<<player->getName()<<" ";
4849 actionstream<<player->getName()<<" "
4850 <<(c.timeout?"times out.":"leaves game.")
4851 <<" List of players: "
4852 <<os.str()<<std::endl;
4857 delete m_clients[c.peer_id];
4858 m_clients.erase(c.peer_id);
4860 // Send player info to all remaining clients
4861 //SendPlayerInfos();
4863 // Send leave chat message to all remaining clients
4864 if(message.length() != 0)
4865 BroadcastChatMessage(message);
4874 void Server::handlePeerChanges()
4876 while(m_peer_change_queue.size() > 0)
4878 PeerChange c = m_peer_change_queue.pop_front();
4880 verbosestream<<"Server: Handling peer change: "
4881 <<"id="<<c.peer_id<<", timeout="<<c.timeout
4884 handlePeerChange(c);
4888 void dedicated_server_loop(Server &server, bool &kill)
4890 DSTACK(__FUNCTION_NAME);
4892 verbosestream<<"dedicated_server_loop()"<<std::endl;
4894 IntervalLimiter m_profiler_interval;
4898 float steplen = g_settings->getFloat("dedicated_server_step");
4899 // This is kind of a hack but can be done like this
4900 // because server.step() is very light
4902 ScopeProfiler sp(g_profiler, "dedicated server sleep");
4903 sleep_ms((int)(steplen*1000.0));
4905 server.step(steplen);
4907 if(server.getShutdownRequested() || kill)
4909 infostream<<"Dedicated server quitting"<<std::endl;
4911 if(g_settings->getBool("server_announce") == true)
4912 ServerList::sendAnnounce("delete");
4920 float profiler_print_interval =
4921 g_settings->getFloat("profiler_print_interval");
4922 if(profiler_print_interval != 0)
4924 if(m_profiler_interval.step(steplen, profiler_print_interval))
4926 infostream<<"Profiler:"<<std::endl;
4927 g_profiler->print(infostream);
4928 g_profiler->clear();