3 Copyright (C) 2010-2013 celeron55, Perttu Ahola <celeron55@gmail.com>
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU Lesser General Public License as published by
7 the Free Software Foundation; either version 2.1 of the License, or
8 (at your option) any later version.
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU Lesser General Public License for more details.
15 You should have received a copy of the GNU Lesser General Public License along
16 with this program; if not, write to the Free Software Foundation, Inc.,
17 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
24 #include "clientserver.h"
26 #include "environment.h"
28 #include "jthread/jmutexautolock.h"
30 #include "constants.h"
36 #include "serverobject.h"
37 #include "genericobject.h"
41 #include "scripting_game.h"
48 #include "content_mapnode.h"
49 #include "content_nodemeta.h"
50 #include "content_abm.h"
51 #include "content_sao.h"
56 #include "sound.h" // dummySoundManager
57 #include "event_manager.h"
59 #include "serverlist.h"
60 #include "util/string.h"
61 #include "util/pointedthing.h"
62 #include "util/mathconstants.h"
64 #include "util/serialize.h"
65 #include "util/thread.h"
66 #include "defaultsettings.h"
68 class ClientNotFoundException : public BaseException
71 ClientNotFoundException(const char *s):
76 class ServerThread : public JThread
82 ServerThread(Server *server):
91 void * ServerThread::Thread()
95 log_register_thread("ServerThread");
97 DSTACK(__FUNCTION_NAME);
99 BEGIN_DEBUG_EXCEPTION_HANDLER
101 while(!StopRequested())
104 //TimeTaker timer("AsyncRunStep() + Receive()");
107 //TimeTaker timer("AsyncRunStep()");
108 m_server->AsyncRunStep();
111 //infostream<<"Running m_server->Receive()"<<std::endl;
114 catch(con::NoIncomingDataException &e)
117 catch(con::PeerNotFoundException &e)
119 infostream<<"Server: PeerNotFoundException"<<std::endl;
121 catch(ClientNotFoundException &e)
124 catch(con::ConnectionBindFailed &e)
126 m_server->setAsyncFatalError(e.what());
130 m_server->setAsyncFatalError(e.what());
134 END_DEBUG_EXCEPTION_HANDLER(errorstream)
139 v3f ServerSoundParams::getPos(ServerEnvironment *env, bool *pos_exists) const
141 if(pos_exists) *pos_exists = false;
146 if(pos_exists) *pos_exists = true;
151 ServerActiveObject *sao = env->getActiveObject(object);
154 if(pos_exists) *pos_exists = true;
155 return sao->getBasePosition(); }
160 void RemoteClient::GetNextBlocks(Server *server, float dtime,
161 std::vector<PrioritySortedBlockTransfer> &dest)
163 DSTACK(__FUNCTION_NAME);
166 TimeTaker timer("RemoteClient::GetNextBlocks", &timer_result);*/
169 m_nothing_to_send_pause_timer -= dtime;
170 m_nearest_unsent_reset_timer += dtime;
172 if(m_nothing_to_send_pause_timer >= 0)
175 Player *player = server->m_env->getPlayer(peer_id);
176 // This can happen sometimes; clients and players are not in perfect sync.
180 // Won't send anything if already sending
181 if(m_blocks_sending.size() >= g_settings->getU16
182 ("max_simultaneous_block_sends_per_client"))
184 //infostream<<"Not sending any blocks, Queue full."<<std::endl;
188 //TimeTaker timer("RemoteClient::GetNextBlocks");
190 v3f playerpos = player->getPosition();
191 v3f playerspeed = player->getSpeed();
192 v3f playerspeeddir(0,0,0);
193 if(playerspeed.getLength() > 1.0*BS)
194 playerspeeddir = playerspeed / playerspeed.getLength();
195 // Predict to next block
196 v3f playerpos_predicted = playerpos + playerspeeddir*MAP_BLOCKSIZE*BS;
198 v3s16 center_nodepos = floatToInt(playerpos_predicted, BS);
200 v3s16 center = getNodeBlockPos(center_nodepos);
202 // Camera position and direction
203 v3f camera_pos = player->getEyePosition();
204 v3f camera_dir = v3f(0,0,1);
205 camera_dir.rotateYZBy(player->getPitch());
206 camera_dir.rotateXZBy(player->getYaw());
208 /*infostream<<"camera_dir=("<<camera_dir.X<<","<<camera_dir.Y<<","
209 <<camera_dir.Z<<")"<<std::endl;*/
212 Get the starting value of the block finder radius.
215 if(m_last_center != center)
217 m_nearest_unsent_d = 0;
218 m_last_center = center;
221 /*infostream<<"m_nearest_unsent_reset_timer="
222 <<m_nearest_unsent_reset_timer<<std::endl;*/
224 // Reset periodically to workaround for some bugs or stuff
225 if(m_nearest_unsent_reset_timer > 20.0)
227 m_nearest_unsent_reset_timer = 0;
228 m_nearest_unsent_d = 0;
229 //infostream<<"Resetting m_nearest_unsent_d for "
230 // <<server->getPlayerName(peer_id)<<std::endl;
233 //s16 last_nearest_unsent_d = m_nearest_unsent_d;
234 s16 d_start = m_nearest_unsent_d;
236 //infostream<<"d_start="<<d_start<<std::endl;
238 u16 max_simul_sends_setting = g_settings->getU16
239 ("max_simultaneous_block_sends_per_client");
240 u16 max_simul_sends_usually = max_simul_sends_setting;
243 Check the time from last addNode/removeNode.
245 Decrease send rate if player is building stuff.
247 m_time_from_building += dtime;
248 if(m_time_from_building < g_settings->getFloat(
249 "full_block_send_enable_min_time_from_building"))
251 max_simul_sends_usually
252 = LIMITED_MAX_SIMULTANEOUS_BLOCK_SENDS;
256 Number of blocks sending + number of blocks selected for sending
258 u32 num_blocks_selected = m_blocks_sending.size();
261 next time d will be continued from the d from which the nearest
262 unsent block was found this time.
264 This is because not necessarily any of the blocks found this
265 time are actually sent.
267 s32 new_nearest_unsent_d = -1;
269 s16 d_max = g_settings->getS16("max_block_send_distance");
270 s16 d_max_gen = g_settings->getS16("max_block_generate_distance");
272 // Don't loop very much at a time
273 s16 max_d_increment_at_time = 2;
274 if(d_max > d_start + max_d_increment_at_time)
275 d_max = d_start + max_d_increment_at_time;
276 /*if(d_max_gen > d_start+2)
277 d_max_gen = d_start+2;*/
279 //infostream<<"Starting from "<<d_start<<std::endl;
281 s32 nearest_emerged_d = -1;
282 s32 nearest_emergefull_d = -1;
283 s32 nearest_sent_d = -1;
284 bool queue_is_full = false;
287 for(d = d_start; d <= d_max; d++)
289 /*errorstream<<"checking d="<<d<<" for "
290 <<server->getPlayerName(peer_id)<<std::endl;*/
291 //infostream<<"RemoteClient::SendBlocks(): d="<<d<<std::endl;
294 If m_nearest_unsent_d was changed by the EmergeThread
295 (it can change it to 0 through SetBlockNotSent),
297 Else update m_nearest_unsent_d
299 /*if(m_nearest_unsent_d != last_nearest_unsent_d)
301 d = m_nearest_unsent_d;
302 last_nearest_unsent_d = m_nearest_unsent_d;
306 Get the border/face dot coordinates of a "d-radiused"
309 std::list<v3s16> list;
310 getFacePositions(list, d);
312 std::list<v3s16>::iterator li;
313 for(li=list.begin(); li!=list.end(); ++li)
315 v3s16 p = *li + center;
319 - Don't allow too many simultaneous transfers
320 - EXCEPT when the blocks are very close
322 Also, don't send blocks that are already flying.
325 // Start with the usual maximum
326 u16 max_simul_dynamic = max_simul_sends_usually;
328 // If block is very close, allow full maximum
329 if(d <= BLOCK_SEND_DISABLE_LIMITS_MAX_D)
330 max_simul_dynamic = max_simul_sends_setting;
332 // Don't select too many blocks for sending
333 if(num_blocks_selected >= max_simul_dynamic)
335 queue_is_full = true;
336 goto queue_full_break;
339 // Don't send blocks that are currently being transferred
340 if(m_blocks_sending.find(p) != m_blocks_sending.end())
346 if(p.X < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
347 || p.X > MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
348 || p.Y < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
349 || p.Y > MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
350 || p.Z < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
351 || p.Z > MAP_GENERATION_LIMIT / MAP_BLOCKSIZE)
354 // If this is true, inexistent block will be made from scratch
355 bool generate = d <= d_max_gen;
358 /*// Limit the generating area vertically to 2/3
359 if(abs(p.Y - center.Y) > d_max_gen - d_max_gen / 3)
362 // Limit the send area vertically to 1/2
363 if(abs(p.Y - center.Y) > d_max / 2)
369 If block is far away, don't generate it unless it is
375 // Block center y in nodes
376 f32 y = (f32)(p.Y * MAP_BLOCKSIZE + MAP_BLOCKSIZE/2);
377 // Don't generate if it's very high or very low
378 if(y < -64 || y > 64)
382 v2s16 p2d_nodes_center(
386 // Get ground height in nodes
387 s16 gh = server->m_env->getServerMap().findGroundLevel(
390 // If differs a lot, don't generate
391 if(fabs(gh - y) > MAP_BLOCKSIZE*2)
393 // Actually, don't even send it
399 //infostream<<"d="<<d<<std::endl;
402 Don't generate or send if not in sight
403 FIXME This only works if the client uses a small enough
404 FOV setting. The default of 72 degrees is fine.
407 float camera_fov = (72.0*M_PI/180) * 4./3.;
408 if(isBlockInSight(p, camera_pos, camera_dir, camera_fov, 10000*BS) == false)
414 Don't send already sent blocks
417 if(m_blocks_sent.find(p) != m_blocks_sent.end())
424 Check if map has this block
426 MapBlock *block = server->m_env->getMap().getBlockNoCreateNoEx(p);
428 bool surely_not_found_on_disk = false;
429 bool block_is_invalid = false;
432 // Reset usage timer, this block will be of use in the future.
433 block->resetUsageTimer();
435 // Block is dummy if data doesn't exist.
436 // It means it has been not found from disk and not generated
439 surely_not_found_on_disk = true;
442 // Block is valid if lighting is up-to-date and data exists
443 if(block->isValid() == false)
445 block_is_invalid = true;
448 /*if(block->isFullyGenerated() == false)
450 block_is_invalid = true;
455 ServerMap *map = (ServerMap*)(&server->m_env->getMap());
456 v2s16 chunkpos = map->sector_to_chunk(p2d);
457 if(map->chunkNonVolatile(chunkpos) == false)
458 block_is_invalid = true;
460 if(block->isGenerated() == false)
461 block_is_invalid = true;
464 If block is not close, don't send it unless it is near
467 Block is near ground level if night-time mesh
468 differs from day-time mesh.
472 if(block->getDayNightDiff() == false)
479 If block has been marked to not exist on disk (dummy)
480 and generating new ones is not wanted, skip block.
482 if(generate == false && surely_not_found_on_disk == true)
489 Add inexistent block to emerge queue.
491 if(block == NULL || surely_not_found_on_disk || block_is_invalid)
493 /* //TODO: Get value from somewhere
494 // Allow only one block in emerge queue
495 //if(server->m_emerge_queue.peerItemCount(peer_id) < 1)
496 // Allow two blocks in queue per client
497 //if(server->m_emerge_queue.peerItemCount(peer_id) < 2)
499 // Make it more responsive when needing to generate stuff
500 if(surely_not_found_on_disk)
502 if(server->m_emerge_queue.peerItemCount(peer_id) < max_emerge)
504 //infostream<<"Adding block to emerge queue"<<std::endl;
506 // Add it to the emerge queue and trigger the thread
509 if(generate == false)
510 flags |= BLOCK_EMERGE_FLAG_FROMDISK;
512 server->m_emerge_queue.addBlock(peer_id, p, flags);
513 server->m_emergethread.trigger();
515 if(nearest_emerged_d == -1)
516 nearest_emerged_d = d;
518 if(nearest_emergefull_d == -1)
519 nearest_emergefull_d = d;
520 goto queue_full_break;
524 if (server->m_emerge->enqueueBlockEmerge(peer_id, p, generate)) {
525 if (nearest_emerged_d == -1)
526 nearest_emerged_d = d;
528 if (nearest_emergefull_d == -1)
529 nearest_emergefull_d = d;
530 goto queue_full_break;
537 if(nearest_sent_d == -1)
541 Add block to send queue
544 /*errorstream<<"sending from d="<<d<<" to "
545 <<server->getPlayerName(peer_id)<<std::endl;*/
547 PrioritySortedBlockTransfer q((float)d, p, peer_id);
551 num_blocks_selected += 1;
556 //infostream<<"Stopped at "<<d<<std::endl;
558 // If nothing was found for sending and nothing was queued for
559 // emerging, continue next time browsing from here
560 if(nearest_emerged_d != -1){
561 new_nearest_unsent_d = nearest_emerged_d;
562 } else if(nearest_emergefull_d != -1){
563 new_nearest_unsent_d = nearest_emergefull_d;
565 if(d > g_settings->getS16("max_block_send_distance")){
566 new_nearest_unsent_d = 0;
567 m_nothing_to_send_pause_timer = 2.0;
568 /*infostream<<"GetNextBlocks(): d wrapped around for "
569 <<server->getPlayerName(peer_id)
570 <<"; setting to 0 and pausing"<<std::endl;*/
572 if(nearest_sent_d != -1)
573 new_nearest_unsent_d = nearest_sent_d;
575 new_nearest_unsent_d = d;
579 if(new_nearest_unsent_d != -1)
580 m_nearest_unsent_d = new_nearest_unsent_d;
582 /*timer_result = timer.stop(true);
583 if(timer_result != 0)
584 infostream<<"GetNextBlocks timeout: "<<timer_result<<" (!=0)"<<std::endl;*/
587 void RemoteClient::GotBlock(v3s16 p)
589 if(m_blocks_sending.find(p) != m_blocks_sending.end())
590 m_blocks_sending.erase(p);
593 /*infostream<<"RemoteClient::GotBlock(): Didn't find in"
594 " m_blocks_sending"<<std::endl;*/
595 m_excess_gotblocks++;
597 m_blocks_sent.insert(p);
600 void RemoteClient::SentBlock(v3s16 p)
602 if(m_blocks_sending.find(p) == m_blocks_sending.end())
603 m_blocks_sending[p] = 0.0;
605 infostream<<"RemoteClient::SentBlock(): Sent block"
606 " already in m_blocks_sending"<<std::endl;
609 void RemoteClient::SetBlockNotSent(v3s16 p)
611 m_nearest_unsent_d = 0;
613 if(m_blocks_sending.find(p) != m_blocks_sending.end())
614 m_blocks_sending.erase(p);
615 if(m_blocks_sent.find(p) != m_blocks_sent.end())
616 m_blocks_sent.erase(p);
619 void RemoteClient::SetBlocksNotSent(std::map<v3s16, MapBlock*> &blocks)
621 m_nearest_unsent_d = 0;
623 for(std::map<v3s16, MapBlock*>::iterator
625 i != blocks.end(); ++i)
629 if(m_blocks_sending.find(p) != m_blocks_sending.end())
630 m_blocks_sending.erase(p);
631 if(m_blocks_sent.find(p) != m_blocks_sent.end())
632 m_blocks_sent.erase(p);
641 const std::string &path_world,
642 const SubgameSpec &gamespec,
643 bool simple_singleplayer_mode
645 m_path_world(path_world),
646 m_gamespec(gamespec),
647 m_simple_singleplayer_mode(simple_singleplayer_mode),
648 m_async_fatal_error(""),
650 m_con(PROTOCOL_ID, 512, CONNECTION_TIMEOUT,
651 g_settings->getBool("enable_ipv6") && g_settings->getBool("ipv6_server"), this),
654 m_rollback_sink_enabled(true),
655 m_enable_rollback_recording(false),
658 m_itemdef(createItemDefManager()),
659 m_nodedef(createNodeDefManager()),
660 m_craftdef(createCraftDefManager()),
661 m_event(new EventManager()),
663 m_time_of_day_send_timer(0),
665 m_shutdown_requested(false),
666 m_ignore_map_edit_events(false),
667 m_ignore_map_edit_events_peer_id(0)
669 m_liquid_transform_timer = 0.0;
670 m_liquid_transform_every = 1.0;
671 m_print_info_timer = 0.0;
672 m_masterserver_timer = 0.0;
673 m_objectdata_timer = 0.0;
674 m_emergethread_trigger_timer = 0.0;
675 m_savemap_timer = 0.0;
678 m_lag = g_settings->getFloat("dedicated_server_step");
681 throw ServerError("Supplied empty world path");
683 if(!gamespec.isValid())
684 throw ServerError("Supplied invalid gamespec");
686 infostream<<"Server created for gameid \""<<m_gamespec.id<<"\"";
687 if(m_simple_singleplayer_mode)
688 infostream<<" in simple singleplayer mode"<<std::endl;
690 infostream<<std::endl;
691 infostream<<"- world: "<<m_path_world<<std::endl;
692 infostream<<"- game: "<<m_gamespec.path<<std::endl;
694 // Initialize default settings and override defaults with those provided
696 set_default_settings(g_settings);
697 Settings gamedefaults;
698 getGameMinetestConfig(gamespec.path, gamedefaults);
699 override_default_settings(g_settings, &gamedefaults);
701 // Create server thread
702 m_thread = new ServerThread(this);
704 // Create emerge manager
705 m_emerge = new EmergeManager(this);
707 // Create world if it doesn't exist
708 if(!initializeWorld(m_path_world, m_gamespec.id))
709 throw ServerError("Failed to initialize world");
711 // Create ban manager
712 std::string ban_path = m_path_world+DIR_DELIM+"ipban.txt";
713 m_banmanager = new BanManager(ban_path);
715 // Create rollback manager
716 std::string rollback_path = m_path_world+DIR_DELIM+"rollback.txt";
717 m_rollback = createRollbackManager(rollback_path, this);
719 ModConfiguration modconf(m_path_world);
720 m_mods = modconf.getMods();
721 std::vector<ModSpec> unsatisfied_mods = modconf.getUnsatisfiedMods();
722 // complain about mods with unsatisfied dependencies
723 if(!modconf.isConsistent())
725 for(std::vector<ModSpec>::iterator it = unsatisfied_mods.begin();
726 it != unsatisfied_mods.end(); ++it)
729 errorstream << "mod \"" << mod.name << "\" has unsatisfied dependencies: ";
730 for(std::set<std::string>::iterator dep_it = mod.unsatisfied_depends.begin();
731 dep_it != mod.unsatisfied_depends.end(); ++dep_it)
732 errorstream << " \"" << *dep_it << "\"";
733 errorstream << std::endl;
737 Settings worldmt_settings;
738 std::string worldmt = m_path_world + DIR_DELIM + "world.mt";
739 worldmt_settings.readConfigFile(worldmt.c_str());
740 std::vector<std::string> names = worldmt_settings.getNames();
741 std::set<std::string> load_mod_names;
742 for(std::vector<std::string>::iterator it = names.begin();
743 it != names.end(); ++it)
745 std::string name = *it;
746 if(name.compare(0,9,"load_mod_")==0 && worldmt_settings.getBool(name))
747 load_mod_names.insert(name.substr(9));
749 // complain about mods declared to be loaded, but not found
750 for(std::vector<ModSpec>::iterator it = m_mods.begin();
751 it != m_mods.end(); ++it)
752 load_mod_names.erase((*it).name);
753 for(std::vector<ModSpec>::iterator it = unsatisfied_mods.begin();
754 it != unsatisfied_mods.end(); ++it)
755 load_mod_names.erase((*it).name);
756 if(!load_mod_names.empty())
758 errorstream << "The following mods could not be found:";
759 for(std::set<std::string>::iterator it = load_mod_names.begin();
760 it != load_mod_names.end(); ++it)
761 errorstream << " \"" << (*it) << "\"";
762 errorstream << std::endl;
765 // Path to builtin.lua
766 std::string builtinpath = getBuiltinLuaPath() + DIR_DELIM + "builtin.lua";
769 JMutexAutoLock envlock(m_env_mutex);
770 JMutexAutoLock conlock(m_con_mutex);
772 // Initialize scripting
774 infostream<<"Server: Initializing Lua"<<std::endl;
776 m_script = new GameScripting(this);
779 // Load and run builtin.lua
780 infostream<<"Server: Loading builtin.lua [\""
781 <<builtinpath<<"\"]"<<std::endl;
782 bool success = m_script->loadMod(builtinpath, "__builtin");
784 errorstream<<"Server: Failed to load and run "
785 <<builtinpath<<std::endl;
786 throw ModError("Failed to load and run "+builtinpath);
789 infostream<<"Server: Loading mods: ";
790 for(std::vector<ModSpec>::iterator i = m_mods.begin();
791 i != m_mods.end(); i++){
792 const ModSpec &mod = *i;
793 infostream<<mod.name<<" ";
795 infostream<<std::endl;
796 // Load and run "mod" scripts
797 for(std::vector<ModSpec>::iterator i = m_mods.begin();
798 i != m_mods.end(); i++){
799 const ModSpec &mod = *i;
800 std::string scriptpath = mod.path + DIR_DELIM + "init.lua";
801 infostream<<" ["<<padStringRight(mod.name, 12)<<"] [\""
802 <<scriptpath<<"\"]"<<std::endl;
803 bool success = m_script->loadMod(scriptpath, mod.name);
805 errorstream<<"Server: Failed to load and run "
806 <<scriptpath<<std::endl;
807 throw ModError("Failed to load and run "+scriptpath);
811 // Read Textures and calculate sha1 sums
814 // Apply item aliases in the node definition manager
815 m_nodedef->updateAliases(m_itemdef);
817 // Initialize Environment
818 ServerMap *servermap = new ServerMap(path_world, this, m_emerge);
819 m_env = new ServerEnvironment(servermap, m_script, this, m_emerge);
821 // Run some callbacks after the MG params have been set up but before activation
822 MapgenParams *mgparams = servermap->getMapgenParams();
823 m_script->environment_OnMapgenInit(mgparams);
825 // Initialize mapgens
826 m_emerge->initMapgens(mgparams);
827 servermap->setMapgenParams(m_emerge->params);
829 // Give environment reference to scripting api
830 m_script->initializeEnvironment(m_env);
832 // Register us to receive map edit events
833 servermap->addEventReceiver(this);
835 // If file exists, load environment metadata
836 if(fs::PathExists(m_path_world+DIR_DELIM+"env_meta.txt"))
838 infostream<<"Server: Loading environment metadata"<<std::endl;
839 m_env->loadMeta(m_path_world);
843 infostream<<"Server: Loading players"<<std::endl;
844 m_env->deSerializePlayers(m_path_world);
847 Add some test ActiveBlockModifiers to environment
849 add_legacy_abms(m_env, m_nodedef);
851 m_liquid_transform_every = g_settings->getFloat("liquid_update");
856 infostream<<"Server destructing"<<std::endl;
859 Send shutdown message
862 JMutexAutoLock conlock(m_con_mutex);
864 std::wstring line = L"*** Server shutting down";
867 Send the message to clients
869 for(std::map<u16, RemoteClient*>::iterator
870 i = m_clients.begin();
871 i != m_clients.end(); ++i)
873 // Get client and check that it is valid
874 RemoteClient *client = i->second;
875 assert(client->peer_id == i->first);
876 if(client->serialization_version == SER_FMT_VER_INVALID)
880 SendChatMessage(client->peer_id, line);
882 catch(con::PeerNotFoundException &e)
888 JMutexAutoLock envlock(m_env_mutex);
889 JMutexAutoLock conlock(m_con_mutex);
892 Execute script shutdown hooks
894 m_script->on_shutdown();
898 JMutexAutoLock envlock(m_env_mutex);
903 infostream<<"Server: Saving players"<<std::endl;
904 m_env->serializePlayers(m_path_world);
907 Save environment metadata
909 infostream<<"Server: Saving environment metadata"<<std::endl;
910 m_env->saveMeta(m_path_world);
919 //shutdown all emerge threads first!
926 JMutexAutoLock clientslock(m_con_mutex);
928 for(std::map<u16, RemoteClient*>::iterator
929 i = m_clients.begin();
930 i != m_clients.end(); ++i)
938 // Delete things in the reverse order of creation
947 // Deinitialize scripting
948 infostream<<"Server: Deinitializing scripting"<<std::endl;
951 // Delete detached inventories
953 for(std::map<std::string, Inventory*>::iterator
954 i = m_detached_inventories.begin();
955 i != m_detached_inventories.end(); i++){
961 void Server::start(unsigned short port)
963 DSTACK(__FUNCTION_NAME);
964 infostream<<"Starting server on port "<<port<<"..."<<std::endl;
966 // Stop thread if already running
969 // Initialize connection
970 m_con.SetTimeoutMs(30);
976 // ASCII art for the win!
978 <<" .__ __ __ "<<std::endl
979 <<" _____ |__| ____ _____/ |_ ____ _______/ |_ "<<std::endl
980 <<" / \\| |/ \\_/ __ \\ __\\/ __ \\ / ___/\\ __\\"<<std::endl
981 <<"| Y Y \\ | | \\ ___/| | \\ ___/ \\___ \\ | | "<<std::endl
982 <<"|__|_| /__|___| /\\___ >__| \\___ >____ > |__| "<<std::endl
983 <<" \\/ \\/ \\/ \\/ \\/ "<<std::endl;
984 actionstream<<"World at ["<<m_path_world<<"]"<<std::endl;
985 actionstream<<"Server for gameid=\""<<m_gamespec.id
986 <<"\" listening on port "<<port<<"."<<std::endl;
991 DSTACK(__FUNCTION_NAME);
993 infostream<<"Server: Stopping and waiting threads"<<std::endl;
995 // Stop threads (set run=false first so both start stopping)
997 //m_emergethread.setRun(false);
999 //m_emergethread.stop();
1001 infostream<<"Server: Threads stopped"<<std::endl;
1004 void Server::step(float dtime)
1006 DSTACK(__FUNCTION_NAME);
1011 JMutexAutoLock lock(m_step_dtime_mutex);
1012 m_step_dtime += dtime;
1014 // Throw if fatal error occurred in thread
1015 std::string async_err = m_async_fatal_error.get();
1016 if(async_err != ""){
1017 throw ServerError(async_err);
1021 void Server::AsyncRunStep()
1023 DSTACK(__FUNCTION_NAME);
1025 g_profiler->add("Server::AsyncRunStep (num)", 1);
1029 JMutexAutoLock lock1(m_step_dtime_mutex);
1030 dtime = m_step_dtime;
1034 // Send blocks to clients
1041 g_profiler->add("Server::AsyncRunStep with dtime (num)", 1);
1043 //infostream<<"Server steps "<<dtime<<std::endl;
1044 //infostream<<"Server::AsyncRunStep(): dtime="<<dtime<<std::endl;
1047 JMutexAutoLock lock1(m_step_dtime_mutex);
1048 m_step_dtime -= dtime;
1055 m_uptime.set(m_uptime.get() + dtime);
1059 // Process connection's timeouts
1060 JMutexAutoLock lock2(m_con_mutex);
1061 ScopeProfiler sp(g_profiler, "Server: connection timeout processing");
1062 m_con.RunTimeouts(dtime);
1066 // This has to be called so that the client list gets synced
1067 // with the peer list of the connection
1068 handlePeerChanges();
1072 Update time of day and overall game time
1075 JMutexAutoLock envlock(m_env_mutex);
1077 m_env->setTimeOfDaySpeed(g_settings->getFloat("time_speed"));
1080 Send to clients at constant intervals
1083 m_time_of_day_send_timer -= dtime;
1084 if(m_time_of_day_send_timer < 0.0)
1086 m_time_of_day_send_timer = g_settings->getFloat("time_send_interval");
1088 //JMutexAutoLock envlock(m_env_mutex);
1089 JMutexAutoLock conlock(m_con_mutex);
1091 u16 time = m_env->getTimeOfDay();
1092 float time_speed = g_settings->getFloat("time_speed");
1094 for(std::map<u16, RemoteClient*>::iterator
1095 i = m_clients.begin();
1096 i != m_clients.end(); ++i)
1098 RemoteClient *client = i->second;
1099 SendTimeOfDay(client->peer_id, time, time_speed);
1105 JMutexAutoLock lock(m_env_mutex);
1106 // Figure out and report maximum lag to environment
1107 float max_lag = m_env->getMaxLagEstimate();
1108 max_lag *= 0.9998; // Decrease slowly (about half per 5 minutes)
1109 if(dtime > max_lag){
1110 if(dtime > 0.1 && dtime > max_lag * 2.0)
1111 infostream<<"Server: Maximum lag peaked to "<<dtime
1115 m_env->reportMaxLagEstimate(max_lag);
1117 ScopeProfiler sp(g_profiler, "SEnv step");
1118 ScopeProfiler sp2(g_profiler, "SEnv step avg", SPT_AVG);
1122 const float map_timer_and_unload_dtime = 2.92;
1123 if(m_map_timer_and_unload_interval.step(dtime, map_timer_and_unload_dtime))
1125 JMutexAutoLock lock(m_env_mutex);
1126 // Run Map's timers and unload unused data
1127 ScopeProfiler sp(g_profiler, "Server: map timer and unload");
1128 m_env->getMap().timerUpdate(map_timer_and_unload_dtime,
1129 g_settings->getFloat("server_unload_unused_data_timeout"));
1140 JMutexAutoLock lock(m_env_mutex);
1141 JMutexAutoLock lock2(m_con_mutex);
1143 ScopeProfiler sp(g_profiler, "Server: handle players");
1145 for(std::map<u16, RemoteClient*>::iterator
1146 i = m_clients.begin();
1147 i != m_clients.end(); ++i)
1149 RemoteClient *client = i->second;
1150 PlayerSAO *playersao = getPlayerSAO(client->peer_id);
1151 if(playersao == NULL)
1155 Handle player HPs (die if hp=0)
1157 if(playersao->m_hp_not_sent && g_settings->getBool("enable_damage"))
1159 if(playersao->getHP() == 0)
1160 DiePlayer(client->peer_id);
1162 SendPlayerHP(client->peer_id);
1166 Send player breath if changed
1168 if(playersao->m_breath_not_sent){
1169 SendPlayerBreath(client->peer_id);
1173 Send player inventories if necessary
1175 if(playersao->m_moved){
1176 SendMovePlayer(client->peer_id);
1177 playersao->m_moved = false;
1179 if(playersao->m_inventory_not_sent){
1180 UpdateCrafting(client->peer_id);
1181 SendInventory(client->peer_id);
1186 /* Transform liquids */
1187 m_liquid_transform_timer += dtime;
1188 if(m_liquid_transform_timer >= m_liquid_transform_every)
1190 m_liquid_transform_timer -= m_liquid_transform_every;
1192 JMutexAutoLock lock(m_env_mutex);
1194 ScopeProfiler sp(g_profiler, "Server: liquid transform");
1196 std::map<v3s16, MapBlock*> modified_blocks;
1197 m_env->getMap().transformLiquids(modified_blocks);
1202 core::map<v3s16, MapBlock*> lighting_modified_blocks;
1203 ServerMap &map = ((ServerMap&)m_env->getMap());
1204 map.updateLighting(modified_blocks, lighting_modified_blocks);
1206 // Add blocks modified by lighting to modified_blocks
1207 for(core::map<v3s16, MapBlock*>::Iterator
1208 i = lighting_modified_blocks.getIterator();
1209 i.atEnd() == false; i++)
1211 MapBlock *block = i.getNode()->getValue();
1212 modified_blocks.insert(block->getPos(), block);
1216 Set the modified blocks unsent for all the clients
1219 JMutexAutoLock lock2(m_con_mutex);
1221 for(std::map<u16, RemoteClient*>::iterator
1222 i = m_clients.begin();
1223 i != m_clients.end(); ++i)
1225 RemoteClient *client = i->second;
1227 if(modified_blocks.size() > 0)
1229 // Remove block from sent history
1230 client->SetBlocksNotSent(modified_blocks);
1235 // Periodically print some info
1237 float &counter = m_print_info_timer;
1243 JMutexAutoLock lock2(m_con_mutex);
1244 m_clients_names.clear();
1245 if(m_clients.size() != 0)
1246 infostream<<"Players:"<<std::endl;
1247 for(std::map<u16, RemoteClient*>::iterator
1248 i = m_clients.begin();
1249 i != m_clients.end(); ++i)
1251 //u16 peer_id = i.getNode()->getKey();
1252 RemoteClient *client = i->second;
1253 Player *player = m_env->getPlayer(client->peer_id);
1256 infostream<<"* "<<player->getName()<<"\t";
1257 client->PrintInfo(infostream);
1258 m_clients_names.push_back(player->getName());
1264 m_lag += (m_lag > dtime ? -1 : 1) * dtime/100;
1266 // send masterserver announce
1268 float &counter = m_masterserver_timer;
1269 if(!isSingleplayer() && (!counter || counter >= 300.0) && g_settings->getBool("server_announce") == true)
1271 ServerList::sendAnnounce(!counter ? "start" : "update", m_clients_names, m_uptime.get(), m_env->getGameTime(), m_lag, m_gamespec.id, m_mods);
1278 //if(g_settings->getBool("enable_experimental"))
1282 Check added and deleted active objects
1285 //infostream<<"Server: Checking added and deleted active objects"<<std::endl;
1286 JMutexAutoLock envlock(m_env_mutex);
1287 JMutexAutoLock conlock(m_con_mutex);
1289 ScopeProfiler sp(g_profiler, "Server: checking added and deleted objs");
1291 // Radius inside which objects are active
1292 s16 radius = g_settings->getS16("active_object_send_range_blocks");
1293 radius *= MAP_BLOCKSIZE;
1295 for(std::map<u16, RemoteClient*>::iterator
1296 i = m_clients.begin();
1297 i != m_clients.end(); ++i)
1299 RemoteClient *client = i->second;
1301 // If definitions and textures have not been sent, don't
1302 // send objects either
1303 if(!client->definitions_sent)
1306 Player *player = m_env->getPlayer(client->peer_id);
1309 // This can happen if the client timeouts somehow
1310 /*infostream<<"WARNING: "<<__FUNCTION_NAME<<": Client "
1312 <<" has no associated player"<<std::endl;*/
1315 v3s16 pos = floatToInt(player->getPosition(), BS);
1317 std::set<u16> removed_objects;
1318 std::set<u16> added_objects;
1319 m_env->getRemovedActiveObjects(pos, radius,
1320 client->m_known_objects, removed_objects);
1321 m_env->getAddedActiveObjects(pos, radius,
1322 client->m_known_objects, added_objects);
1324 // Ignore if nothing happened
1325 if(removed_objects.size() == 0 && added_objects.size() == 0)
1327 //infostream<<"active objects: none changed"<<std::endl;
1331 std::string data_buffer;
1335 // Handle removed objects
1336 writeU16((u8*)buf, removed_objects.size());
1337 data_buffer.append(buf, 2);
1338 for(std::set<u16>::iterator
1339 i = removed_objects.begin();
1340 i != removed_objects.end(); ++i)
1344 ServerActiveObject* obj = m_env->getActiveObject(id);
1346 // Add to data buffer for sending
1347 writeU16((u8*)buf, id);
1348 data_buffer.append(buf, 2);
1350 // Remove from known objects
1351 client->m_known_objects.erase(id);
1353 if(obj && obj->m_known_by_count > 0)
1354 obj->m_known_by_count--;
1357 // Handle added objects
1358 writeU16((u8*)buf, added_objects.size());
1359 data_buffer.append(buf, 2);
1360 for(std::set<u16>::iterator
1361 i = added_objects.begin();
1362 i != added_objects.end(); ++i)
1366 ServerActiveObject* obj = m_env->getActiveObject(id);
1369 u8 type = ACTIVEOBJECT_TYPE_INVALID;
1371 infostream<<"WARNING: "<<__FUNCTION_NAME
1372 <<": NULL object"<<std::endl;
1374 type = obj->getSendType();
1376 // Add to data buffer for sending
1377 writeU16((u8*)buf, id);
1378 data_buffer.append(buf, 2);
1379 writeU8((u8*)buf, type);
1380 data_buffer.append(buf, 1);
1383 data_buffer.append(serializeLongString(
1384 obj->getClientInitializationData(client->net_proto_version)));
1386 data_buffer.append(serializeLongString(""));
1388 // Add to known objects
1389 client->m_known_objects.insert(id);
1392 obj->m_known_by_count++;
1396 SharedBuffer<u8> reply(2 + data_buffer.size());
1397 writeU16(&reply[0], TOCLIENT_ACTIVE_OBJECT_REMOVE_ADD);
1398 memcpy((char*)&reply[2], data_buffer.c_str(),
1399 data_buffer.size());
1401 m_con.Send(client->peer_id, 0, reply, true);
1403 verbosestream<<"Server: Sent object remove/add: "
1404 <<removed_objects.size()<<" removed, "
1405 <<added_objects.size()<<" added, "
1406 <<"packet size is "<<reply.getSize()<<std::endl;
1411 Collect a list of all the objects known by the clients
1412 and report it back to the environment.
1415 core::map<u16, bool> all_known_objects;
1417 for(core::map<u16, RemoteClient*>::Iterator
1418 i = m_clients.getIterator();
1419 i.atEnd() == false; i++)
1421 RemoteClient *client = i.getNode()->getValue();
1422 // Go through all known objects of client
1423 for(core::map<u16, bool>::Iterator
1424 i = client->m_known_objects.getIterator();
1425 i.atEnd()==false; i++)
1427 u16 id = i.getNode()->getKey();
1428 all_known_objects[id] = true;
1432 m_env->setKnownActiveObjects(whatever);
1438 Send object messages
1441 JMutexAutoLock envlock(m_env_mutex);
1442 JMutexAutoLock conlock(m_con_mutex);
1444 ScopeProfiler sp(g_profiler, "Server: sending object messages");
1447 // Value = data sent by object
1448 std::map<u16, std::list<ActiveObjectMessage>* > buffered_messages;
1450 // Get active object messages from environment
1453 ActiveObjectMessage aom = m_env->getActiveObjectMessage();
1457 std::list<ActiveObjectMessage>* message_list = NULL;
1458 std::map<u16, std::list<ActiveObjectMessage>* >::iterator n;
1459 n = buffered_messages.find(aom.id);
1460 if(n == buffered_messages.end())
1462 message_list = new std::list<ActiveObjectMessage>;
1463 buffered_messages[aom.id] = message_list;
1467 message_list = n->second;
1469 message_list->push_back(aom);
1472 // Route data to every client
1473 for(std::map<u16, RemoteClient*>::iterator
1474 i = m_clients.begin();
1475 i != m_clients.end(); ++i)
1477 RemoteClient *client = i->second;
1478 std::string reliable_data;
1479 std::string unreliable_data;
1480 // Go through all objects in message buffer
1481 for(std::map<u16, std::list<ActiveObjectMessage>* >::iterator
1482 j = buffered_messages.begin();
1483 j != buffered_messages.end(); ++j)
1485 // If object is not known by client, skip it
1487 if(client->m_known_objects.find(id) == client->m_known_objects.end())
1489 // Get message list of object
1490 std::list<ActiveObjectMessage>* list = j->second;
1491 // Go through every message
1492 for(std::list<ActiveObjectMessage>::iterator
1493 k = list->begin(); k != list->end(); ++k)
1495 // Compose the full new data with header
1496 ActiveObjectMessage aom = *k;
1497 std::string new_data;
1500 writeU16((u8*)&buf[0], aom.id);
1501 new_data.append(buf, 2);
1503 new_data += serializeString(aom.datastring);
1504 // Add data to buffer
1506 reliable_data += new_data;
1508 unreliable_data += new_data;
1512 reliable_data and unreliable_data are now ready.
1515 if(reliable_data.size() > 0)
1517 SharedBuffer<u8> reply(2 + reliable_data.size());
1518 writeU16(&reply[0], TOCLIENT_ACTIVE_OBJECT_MESSAGES);
1519 memcpy((char*)&reply[2], reliable_data.c_str(),
1520 reliable_data.size());
1522 m_con.Send(client->peer_id, 0, reply, true);
1524 if(unreliable_data.size() > 0)
1526 SharedBuffer<u8> reply(2 + unreliable_data.size());
1527 writeU16(&reply[0], TOCLIENT_ACTIVE_OBJECT_MESSAGES);
1528 memcpy((char*)&reply[2], unreliable_data.c_str(),
1529 unreliable_data.size());
1530 // Send as unreliable
1531 m_con.Send(client->peer_id, 0, reply, false);
1534 /*if(reliable_data.size() > 0 || unreliable_data.size() > 0)
1536 infostream<<"Server: Size of object message data: "
1537 <<"reliable: "<<reliable_data.size()
1538 <<", unreliable: "<<unreliable_data.size()
1543 // Clear buffered_messages
1544 for(std::map<u16, std::list<ActiveObjectMessage>* >::iterator
1545 i = buffered_messages.begin();
1546 i != buffered_messages.end(); ++i)
1552 } // enable_experimental
1555 Send queued-for-sending map edit events.
1558 // We will be accessing the environment and the connection
1559 JMutexAutoLock lock(m_env_mutex);
1560 JMutexAutoLock conlock(m_con_mutex);
1562 // Don't send too many at a time
1565 // Single change sending is disabled if queue size is not small
1566 bool disable_single_change_sending = false;
1567 if(m_unsent_map_edit_queue.size() >= 4)
1568 disable_single_change_sending = true;
1570 int event_count = m_unsent_map_edit_queue.size();
1572 // We'll log the amount of each
1575 while(m_unsent_map_edit_queue.size() != 0)
1577 MapEditEvent* event = m_unsent_map_edit_queue.pop_front();
1579 // Players far away from the change are stored here.
1580 // Instead of sending the changes, MapBlocks are set not sent
1582 std::list<u16> far_players;
1584 if(event->type == MEET_ADDNODE || event->type == MEET_SWAPNODE)
1586 //infostream<<"Server: MEET_ADDNODE"<<std::endl;
1587 prof.add("MEET_ADDNODE", 1);
1588 if(disable_single_change_sending)
1589 sendAddNode(event->p, event->n, event->already_known_by_peer,
1590 &far_players, 5, event->type == MEET_ADDNODE);
1592 sendAddNode(event->p, event->n, event->already_known_by_peer,
1593 &far_players, 30, event->type == MEET_ADDNODE);
1595 else if(event->type == MEET_REMOVENODE)
1597 //infostream<<"Server: MEET_REMOVENODE"<<std::endl;
1598 prof.add("MEET_REMOVENODE", 1);
1599 if(disable_single_change_sending)
1600 sendRemoveNode(event->p, event->already_known_by_peer,
1603 sendRemoveNode(event->p, event->already_known_by_peer,
1606 else if(event->type == MEET_BLOCK_NODE_METADATA_CHANGED)
1608 infostream<<"Server: MEET_BLOCK_NODE_METADATA_CHANGED"<<std::endl;
1609 prof.add("MEET_BLOCK_NODE_METADATA_CHANGED", 1);
1610 setBlockNotSent(event->p);
1612 else if(event->type == MEET_OTHER)
1614 infostream<<"Server: MEET_OTHER"<<std::endl;
1615 prof.add("MEET_OTHER", 1);
1616 for(std::set<v3s16>::iterator
1617 i = event->modified_blocks.begin();
1618 i != event->modified_blocks.end(); ++i)
1620 setBlockNotSent(*i);
1625 prof.add("unknown", 1);
1626 infostream<<"WARNING: Server: Unknown MapEditEvent "
1627 <<((u32)event->type)<<std::endl;
1631 Set blocks not sent to far players
1633 if(far_players.size() > 0)
1635 // Convert list format to that wanted by SetBlocksNotSent
1636 std::map<v3s16, MapBlock*> modified_blocks2;
1637 for(std::set<v3s16>::iterator
1638 i = event->modified_blocks.begin();
1639 i != event->modified_blocks.end(); ++i)
1641 modified_blocks2[*i] =
1642 m_env->getMap().getBlockNoCreateNoEx(*i);
1644 // Set blocks not sent
1645 for(std::list<u16>::iterator
1646 i = far_players.begin();
1647 i != far_players.end(); ++i)
1650 RemoteClient *client = getClient(peer_id);
1653 client->SetBlocksNotSent(modified_blocks2);
1659 /*// Don't send too many at a time
1661 if(count >= 1 && m_unsent_map_edit_queue.size() < 100)
1665 if(event_count >= 5){
1666 infostream<<"Server: MapEditEvents:"<<std::endl;
1667 prof.print(infostream);
1668 } else if(event_count != 0){
1669 verbosestream<<"Server: MapEditEvents:"<<std::endl;
1670 prof.print(verbosestream);
1676 Trigger emergethread (it somehow gets to a non-triggered but
1677 bysy state sometimes)
1680 float &counter = m_emergethread_trigger_timer;
1686 m_emerge->startAllThreads();
1688 // Update m_enable_rollback_recording here too
1689 m_enable_rollback_recording =
1690 g_settings->getBool("enable_rollback_recording");
1694 // Save map, players and auth stuff
1696 float &counter = m_savemap_timer;
1698 if(counter >= g_settings->getFloat("server_map_save_interval"))
1701 JMutexAutoLock lock(m_env_mutex);
1703 ScopeProfiler sp(g_profiler, "Server: saving stuff");
1706 if(m_banmanager->isModified())
1707 m_banmanager->save();
1709 // Save changed parts of map
1710 m_env->getMap().save(MOD_STATE_WRITE_NEEDED);
1713 m_env->serializePlayers(m_path_world);
1715 // Save environment metadata
1716 m_env->saveMeta(m_path_world);
1721 void Server::Receive()
1723 DSTACK(__FUNCTION_NAME);
1724 SharedBuffer<u8> data;
1729 JMutexAutoLock conlock(m_con_mutex);
1730 datasize = m_con.Receive(peer_id, data);
1733 // This has to be called so that the client list gets synced
1734 // with the peer list of the connection
1735 handlePeerChanges();
1737 ProcessData(*data, datasize, peer_id);
1739 catch(con::InvalidIncomingDataException &e)
1741 infostream<<"Server::Receive(): "
1742 "InvalidIncomingDataException: what()="
1743 <<e.what()<<std::endl;
1745 catch(con::PeerNotFoundException &e)
1747 //NOTE: This is not needed anymore
1749 // The peer has been disconnected.
1750 // Find the associated player and remove it.
1752 /*JMutexAutoLock envlock(m_env_mutex);
1754 infostream<<"ServerThread: peer_id="<<peer_id
1755 <<" has apparently closed connection. "
1756 <<"Removing player."<<std::endl;
1758 m_env->removePlayer(peer_id);*/
1762 void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
1764 DSTACK(__FUNCTION_NAME);
1765 // Environment is locked first.
1766 JMutexAutoLock envlock(m_env_mutex);
1767 JMutexAutoLock conlock(m_con_mutex);
1769 ScopeProfiler sp(g_profiler, "Server::ProcessData");
1773 Address address = m_con.GetPeerAddress(peer_id);
1774 addr_s = address.serializeString();
1776 // drop player if is ip is banned
1777 if(m_banmanager->isIpBanned(addr_s)){
1778 std::string ban_name = m_banmanager->getBanName(addr_s);
1779 infostream<<"Server: A banned client tried to connect from "
1780 <<addr_s<<"; banned name was "
1781 <<ban_name<<std::endl;
1782 // This actually doesn't seem to transfer to the client
1783 DenyAccess(peer_id, L"Your ip is banned. Banned name was "
1784 +narrow_to_wide(ban_name));
1785 m_con.DeletePeer(peer_id);
1789 catch(con::PeerNotFoundException &e)
1791 infostream<<"Server::ProcessData(): Cancelling: peer "
1792 <<peer_id<<" not found"<<std::endl;
1796 u8 peer_ser_ver = getClient(peer_id)->serialization_version;
1804 ToServerCommand command = (ToServerCommand)readU16(&data[0]);
1806 if(command == TOSERVER_INIT)
1808 // [0] u16 TOSERVER_INIT
1809 // [2] u8 SER_FMT_VER_HIGHEST_READ
1810 // [3] u8[20] player_name
1811 // [23] u8[28] password <--- can be sent without this, from old versions
1813 if(datasize < 2+1+PLAYERNAME_SIZE)
1816 // If net_proto_version is set, this client has already been handled
1817 if(getClient(peer_id)->net_proto_version != 0){
1818 verbosestream<<"Server: Ignoring multiple TOSERVER_INITs from "
1819 <<addr_s<<" (peer_id="<<peer_id<<")"<<std::endl;
1823 verbosestream<<"Server: Got TOSERVER_INIT from "<<addr_s<<" (peer_id="
1824 <<peer_id<<")"<<std::endl;
1826 // Do not allow multiple players in simple singleplayer mode.
1827 // This isn't a perfect way to do it, but will suffice for now.
1828 if(m_simple_singleplayer_mode && m_clients.size() > 1){
1829 infostream<<"Server: Not allowing another client ("<<addr_s
1830 <<") to connect in simple singleplayer mode"<<std::endl;
1831 DenyAccess(peer_id, L"Running in simple singleplayer mode.");
1835 // First byte after command is maximum supported
1836 // serialization version
1837 u8 client_max = data[2];
1838 u8 our_max = SER_FMT_VER_HIGHEST_READ;
1839 // Use the highest version supported by both
1840 u8 deployed = std::min(client_max, our_max);
1841 // If it's lower than the lowest supported, give up.
1842 if(deployed < SER_FMT_VER_LOWEST)
1843 deployed = SER_FMT_VER_INVALID;
1845 //peer->serialization_version = deployed;
1846 getClient(peer_id)->pending_serialization_version = deployed;
1848 if(deployed == SER_FMT_VER_INVALID)
1850 actionstream<<"Server: A mismatched client tried to connect from "
1851 <<addr_s<<std::endl;
1852 infostream<<"Server: Cannot negotiate serialization version with "
1853 <<addr_s<<std::endl;
1854 DenyAccess(peer_id, std::wstring(
1855 L"Your client's version is not supported.\n"
1856 L"Server version is ")
1857 + narrow_to_wide(minetest_version_simple) + L"."
1863 Read and check network protocol version
1866 u16 min_net_proto_version = 0;
1867 if(datasize >= 2+1+PLAYERNAME_SIZE+PASSWORD_SIZE+2)
1868 min_net_proto_version = readU16(&data[2+1+PLAYERNAME_SIZE+PASSWORD_SIZE]);
1870 // Use same version as minimum and maximum if maximum version field
1871 // doesn't exist (backwards compatibility)
1872 u16 max_net_proto_version = min_net_proto_version;
1873 if(datasize >= 2+1+PLAYERNAME_SIZE+PASSWORD_SIZE+2+2)
1874 max_net_proto_version = readU16(&data[2+1+PLAYERNAME_SIZE+PASSWORD_SIZE+2]);
1876 // Start with client's maximum version
1877 u16 net_proto_version = max_net_proto_version;
1879 // Figure out a working version if it is possible at all
1880 if(max_net_proto_version >= SERVER_PROTOCOL_VERSION_MIN ||
1881 min_net_proto_version <= SERVER_PROTOCOL_VERSION_MAX)
1883 // If maximum is larger than our maximum, go with our maximum
1884 if(max_net_proto_version > SERVER_PROTOCOL_VERSION_MAX)
1885 net_proto_version = SERVER_PROTOCOL_VERSION_MAX;
1886 // Else go with client's maximum
1888 net_proto_version = max_net_proto_version;
1891 verbosestream<<"Server: "<<addr_s<<": Protocol version: min: "
1892 <<min_net_proto_version<<", max: "<<max_net_proto_version
1893 <<", chosen: "<<net_proto_version<<std::endl;
1895 getClient(peer_id)->net_proto_version = net_proto_version;
1897 if(net_proto_version < SERVER_PROTOCOL_VERSION_MIN ||
1898 net_proto_version > SERVER_PROTOCOL_VERSION_MAX)
1900 actionstream<<"Server: A mismatched client tried to connect from "
1901 <<addr_s<<std::endl;
1902 DenyAccess(peer_id, std::wstring(
1903 L"Your client's version is not supported.\n"
1904 L"Server version is ")
1905 + narrow_to_wide(minetest_version_simple) + L",\n"
1906 + L"server's PROTOCOL_VERSION is "
1907 + narrow_to_wide(itos(SERVER_PROTOCOL_VERSION_MIN))
1909 + narrow_to_wide(itos(SERVER_PROTOCOL_VERSION_MAX))
1910 + L", client's PROTOCOL_VERSION is "
1911 + narrow_to_wide(itos(min_net_proto_version))
1913 + narrow_to_wide(itos(max_net_proto_version))
1918 if(g_settings->getBool("strict_protocol_version_checking"))
1920 if(net_proto_version != LATEST_PROTOCOL_VERSION)
1922 actionstream<<"Server: A mismatched (strict) client tried to "
1923 <<"connect from "<<addr_s<<std::endl;
1924 DenyAccess(peer_id, std::wstring(
1925 L"Your client's version is not supported.\n"
1926 L"Server version is ")
1927 + narrow_to_wide(minetest_version_simple) + L",\n"
1928 + L"server's PROTOCOL_VERSION (strict) is "
1929 + narrow_to_wide(itos(LATEST_PROTOCOL_VERSION))
1930 + L", client's PROTOCOL_VERSION is "
1931 + narrow_to_wide(itos(min_net_proto_version))
1933 + narrow_to_wide(itos(max_net_proto_version))
1944 char playername[PLAYERNAME_SIZE];
1945 for(u32 i=0; i<PLAYERNAME_SIZE-1; i++)
1947 playername[i] = data[3+i];
1949 playername[PLAYERNAME_SIZE-1] = 0;
1951 if(playername[0]=='\0')
1953 actionstream<<"Server: Player with an empty name "
1954 <<"tried to connect from "<<addr_s<<std::endl;
1955 DenyAccess(peer_id, L"Empty name");
1959 if(string_allowed(playername, PLAYERNAME_ALLOWED_CHARS)==false)
1961 actionstream<<"Server: Player with an invalid name "
1962 <<"tried to connect from "<<addr_s<<std::endl;
1963 DenyAccess(peer_id, L"Name contains unallowed characters");
1967 if(!isSingleplayer() && strcasecmp(playername, "singleplayer") == 0)
1969 actionstream<<"Server: Player with the name \"singleplayer\" "
1970 <<"tried to connect from "<<addr_s<<std::endl;
1971 DenyAccess(peer_id, L"Name is not allowed");
1977 if(m_script->on_prejoinplayer(playername, addr_s, reason))
1979 actionstream<<"Server: Player with the name \""<<playername<<"\" "
1980 <<"tried to connect from "<<addr_s<<" "
1981 <<"but it was disallowed for the following reason: "
1982 <<reason<<std::endl;
1983 DenyAccess(peer_id, narrow_to_wide(reason.c_str()));
1988 infostream<<"Server: New connection: \""<<playername<<"\" from "
1989 <<addr_s<<" (peer_id="<<peer_id<<")"<<std::endl;
1992 char given_password[PASSWORD_SIZE];
1993 if(datasize < 2+1+PLAYERNAME_SIZE+PASSWORD_SIZE)
1995 // old version - assume blank password
1996 given_password[0] = 0;
2000 for(u32 i=0; i<PASSWORD_SIZE-1; i++)
2002 given_password[i] = data[23+i];
2004 given_password[PASSWORD_SIZE-1] = 0;
2007 if(!base64_is_valid(given_password)){
2008 actionstream<<"Server: "<<playername
2009 <<" supplied invalid password hash"<<std::endl;
2010 DenyAccess(peer_id, L"Invalid password hash");
2014 // Enforce user limit.
2015 // Don't enforce for users that have some admin right
2016 if(m_clients.size() >= g_settings->getU16("max_users") &&
2017 !checkPriv(playername, "server") &&
2018 !checkPriv(playername, "ban") &&
2019 !checkPriv(playername, "privs") &&
2020 !checkPriv(playername, "password") &&
2021 playername != g_settings->get("name"))
2023 actionstream<<"Server: "<<playername<<" tried to join, but there"
2024 <<" are already max_users="
2025 <<g_settings->getU16("max_users")<<" players."<<std::endl;
2026 DenyAccess(peer_id, L"Too many users.");
2030 std::string checkpwd; // Password hash to check against
2031 bool has_auth = m_script->getAuth(playername, &checkpwd, NULL);
2033 // If no authentication info exists for user, create it
2035 if(!isSingleplayer() &&
2036 g_settings->getBool("disallow_empty_password") &&
2037 std::string(given_password) == ""){
2038 actionstream<<"Server: "<<playername
2039 <<" supplied empty password"<<std::endl;
2040 DenyAccess(peer_id, L"Empty passwords are "
2041 L"disallowed. Set a password and try again.");
2044 std::wstring raw_default_password =
2045 narrow_to_wide(g_settings->get("default_password"));
2046 std::string initial_password =
2047 translatePassword(playername, raw_default_password);
2049 // If default_password is empty, allow any initial password
2050 if (raw_default_password.length() == 0)
2051 initial_password = given_password;
2053 m_script->createAuth(playername, initial_password);
2056 has_auth = m_script->getAuth(playername, &checkpwd, NULL);
2059 actionstream<<"Server: "<<playername<<" cannot be authenticated"
2060 <<" (auth handler does not work?)"<<std::endl;
2061 DenyAccess(peer_id, L"Not allowed to login");
2065 if(given_password != checkpwd){
2066 actionstream<<"Server: "<<playername<<" supplied wrong password"
2068 DenyAccess(peer_id, L"Wrong password");
2073 PlayerSAO *playersao = emergePlayer(playername, peer_id);
2075 // If failed, cancel
2076 if(playersao == NULL)
2078 RemotePlayer *player =
2079 static_cast<RemotePlayer*>(m_env->getPlayer(playername));
2080 if(player && player->peer_id != 0){
2081 errorstream<<"Server: "<<playername<<": Failed to emerge player"
2082 <<" (player allocated to an another client)"<<std::endl;
2083 DenyAccess(peer_id, L"Another client is connected with this "
2084 L"name. If your client closed unexpectedly, try again in "
2087 errorstream<<"Server: "<<playername<<": Failed to emerge player"
2089 DenyAccess(peer_id, L"Could not allocate player.");
2095 Answer with a TOCLIENT_INIT
2098 SharedBuffer<u8> reply(2+1+6+8+4);
2099 writeU16(&reply[0], TOCLIENT_INIT);
2100 writeU8(&reply[2], deployed);
2101 writeV3S16(&reply[2+1], floatToInt(playersao->getPlayer()->getPosition()+v3f(0,BS/2,0), BS));
2102 writeU64(&reply[2+1+6], m_env->getServerMap().getSeed());
2103 writeF1000(&reply[2+1+6+8], g_settings->getFloat("dedicated_server_step"));
2106 m_con.Send(peer_id, 0, reply, true);
2110 Send complete position information
2112 SendMovePlayer(peer_id);
2117 if(command == TOSERVER_INIT2)
2119 verbosestream<<"Server: Got TOSERVER_INIT2 from "
2120 <<peer_id<<std::endl;
2122 Player *player = m_env->getPlayer(peer_id);
2124 verbosestream<<"Server: TOSERVER_INIT2: "
2125 <<"Player not found; ignoring."<<std::endl;
2129 RemoteClient *client = getClient(peer_id);
2130 client->serialization_version =
2131 getClient(peer_id)->pending_serialization_version;
2134 Send some initialization data
2137 infostream<<"Server: Sending content to "
2138 <<getPlayerName(peer_id)<<std::endl;
2140 // Send player movement settings
2141 SendMovement(m_con, peer_id);
2143 // Send item definitions
2144 SendItemDef(m_con, peer_id, m_itemdef, client->net_proto_version);
2146 // Send node definitions
2147 SendNodeDef(m_con, peer_id, m_nodedef, client->net_proto_version);
2149 // Send media announcement
2150 sendMediaAnnouncement(peer_id);
2153 SendPlayerPrivileges(peer_id);
2155 // Send inventory formspec
2156 SendPlayerInventoryFormspec(peer_id);
2159 UpdateCrafting(peer_id);
2160 SendInventory(peer_id);
2163 if(g_settings->getBool("enable_damage"))
2164 SendPlayerHP(peer_id);
2167 SendPlayerBreath(peer_id);
2169 // Send detached inventories
2170 sendDetachedInventories(peer_id);
2172 // Show death screen if necessary
2174 SendDeathscreen(m_con, peer_id, false, v3f(0,0,0));
2178 u16 time = m_env->getTimeOfDay();
2179 float time_speed = g_settings->getFloat("time_speed");
2180 SendTimeOfDay(peer_id, time, time_speed);
2183 // Note things in chat if not in simple singleplayer mode
2184 if(!m_simple_singleplayer_mode)
2186 // Send information about server to player in chat
2187 SendChatMessage(peer_id, getStatusString());
2189 // Send information about joining in chat
2191 std::wstring name = L"unknown";
2192 Player *player = m_env->getPlayer(peer_id);
2194 name = narrow_to_wide(player->getName());
2196 std::wstring message;
2199 message += L" joined the game.";
2200 BroadcastChatMessage(message);
2204 // Warnings about protocol version can be issued here
2205 if(getClient(peer_id)->net_proto_version < LATEST_PROTOCOL_VERSION)
2207 SendChatMessage(peer_id, L"# Server: WARNING: YOUR CLIENT'S "
2208 L"VERSION MAY NOT BE FULLY COMPATIBLE WITH THIS SERVER!");
2215 std::ostringstream os(std::ios_base::binary);
2216 for(std::map<u16, RemoteClient*>::iterator
2217 i = m_clients.begin();
2218 i != m_clients.end(); ++i)
2220 RemoteClient *client = i->second;
2221 assert(client->peer_id == i->first);
2222 if(client->serialization_version == SER_FMT_VER_INVALID)
2225 Player *player = m_env->getPlayer(client->peer_id);
2228 // Get name of player
2229 os<<player->getName()<<" ";
2232 actionstream<<player->getName()<<" ["<<addr_s<<"] "<<"joins game. List of players: "
2233 <<os.str()<<std::endl;
2239 if(peer_ser_ver == SER_FMT_VER_INVALID)
2241 infostream<<"Server::ProcessData(): Cancelling: Peer"
2242 " serialization format invalid or not initialized."
2243 " Skipping incoming command="<<command<<std::endl;
2247 Player *player = m_env->getPlayer(peer_id);
2249 infostream<<"Server::ProcessData(): Cancelling: "
2250 "No player for peer_id="<<peer_id
2255 PlayerSAO *playersao = player->getPlayerSAO();
2256 if(playersao == NULL){
2257 infostream<<"Server::ProcessData(): Cancelling: "
2258 "No player object for peer_id="<<peer_id
2263 if(command == TOSERVER_PLAYERPOS)
2265 if(datasize < 2+12+12+4+4)
2269 v3s32 ps = readV3S32(&data[start+2]);
2270 v3s32 ss = readV3S32(&data[start+2+12]);
2271 f32 pitch = (f32)readS32(&data[2+12+12]) / 100.0;
2272 f32 yaw = (f32)readS32(&data[2+12+12+4]) / 100.0;
2274 if(datasize >= 2+12+12+4+4+4)
2275 keyPressed = (u32)readU32(&data[2+12+12+4+4]);
2276 v3f position((f32)ps.X/100., (f32)ps.Y/100., (f32)ps.Z/100.);
2277 v3f speed((f32)ss.X/100., (f32)ss.Y/100., (f32)ss.Z/100.);
2278 pitch = wrapDegrees(pitch);
2279 yaw = wrapDegrees(yaw);
2281 player->setPosition(position);
2282 player->setSpeed(speed);
2283 player->setPitch(pitch);
2284 player->setYaw(yaw);
2285 player->keyPressed=keyPressed;
2286 player->control.up = (bool)(keyPressed&1);
2287 player->control.down = (bool)(keyPressed&2);
2288 player->control.left = (bool)(keyPressed&4);
2289 player->control.right = (bool)(keyPressed&8);
2290 player->control.jump = (bool)(keyPressed&16);
2291 player->control.aux1 = (bool)(keyPressed&32);
2292 player->control.sneak = (bool)(keyPressed&64);
2293 player->control.LMB = (bool)(keyPressed&128);
2294 player->control.RMB = (bool)(keyPressed&256);
2296 bool cheated = playersao->checkMovementCheat();
2299 m_script->on_cheat(playersao, "moved_too_fast");
2302 /*infostream<<"Server::ProcessData(): Moved player "<<peer_id<<" to "
2303 <<"("<<position.X<<","<<position.Y<<","<<position.Z<<")"
2304 <<" pitch="<<pitch<<" yaw="<<yaw<<std::endl;*/
2306 else if(command == TOSERVER_GOTBLOCKS)
2319 u16 count = data[2];
2320 for(u16 i=0; i<count; i++)
2322 if((s16)datasize < 2+1+(i+1)*6)
2323 throw con::InvalidIncomingDataException
2324 ("GOTBLOCKS length is too short");
2325 v3s16 p = readV3S16(&data[2+1+i*6]);
2326 /*infostream<<"Server: GOTBLOCKS ("
2327 <<p.X<<","<<p.Y<<","<<p.Z<<")"<<std::endl;*/
2328 RemoteClient *client = getClient(peer_id);
2329 client->GotBlock(p);
2332 else if(command == TOSERVER_DELETEDBLOCKS)
2345 u16 count = data[2];
2346 for(u16 i=0; i<count; i++)
2348 if((s16)datasize < 2+1+(i+1)*6)
2349 throw con::InvalidIncomingDataException
2350 ("DELETEDBLOCKS length is too short");
2351 v3s16 p = readV3S16(&data[2+1+i*6]);
2352 /*infostream<<"Server: DELETEDBLOCKS ("
2353 <<p.X<<","<<p.Y<<","<<p.Z<<")"<<std::endl;*/
2354 RemoteClient *client = getClient(peer_id);
2355 client->SetBlockNotSent(p);
2358 else if(command == TOSERVER_CLICK_OBJECT)
2360 infostream<<"Server: CLICK_OBJECT not supported anymore"<<std::endl;
2363 else if(command == TOSERVER_CLICK_ACTIVEOBJECT)
2365 infostream<<"Server: CLICK_ACTIVEOBJECT not supported anymore"<<std::endl;
2368 else if(command == TOSERVER_GROUND_ACTION)
2370 infostream<<"Server: GROUND_ACTION not supported anymore"<<std::endl;
2374 else if(command == TOSERVER_RELEASE)
2376 infostream<<"Server: RELEASE not supported anymore"<<std::endl;
2379 else if(command == TOSERVER_SIGNTEXT)
2381 infostream<<"Server: SIGNTEXT not supported anymore"
2385 else if(command == TOSERVER_SIGNNODETEXT)
2387 infostream<<"Server: SIGNNODETEXT not supported anymore"
2391 else if(command == TOSERVER_INVENTORY_ACTION)
2393 // Strip command and create a stream
2394 std::string datastring((char*)&data[2], datasize-2);
2395 verbosestream<<"TOSERVER_INVENTORY_ACTION: data="<<datastring<<std::endl;
2396 std::istringstream is(datastring, std::ios_base::binary);
2398 InventoryAction *a = InventoryAction::deSerialize(is);
2401 infostream<<"TOSERVER_INVENTORY_ACTION: "
2402 <<"InventoryAction::deSerialize() returned NULL"
2407 // If something goes wrong, this player is to blame
2408 RollbackScopeActor rollback_scope(m_rollback,
2409 std::string("player:")+player->getName());
2412 Note: Always set inventory not sent, to repair cases
2413 where the client made a bad prediction.
2417 Handle restrictions and special cases of the move action
2419 if(a->getType() == IACTION_MOVE)
2421 IMoveAction *ma = (IMoveAction*)a;
2423 ma->from_inv.applyCurrentPlayer(player->getName());
2424 ma->to_inv.applyCurrentPlayer(player->getName());
2426 setInventoryModified(ma->from_inv);
2427 setInventoryModified(ma->to_inv);
2429 bool from_inv_is_current_player =
2430 (ma->from_inv.type == InventoryLocation::PLAYER) &&
2431 (ma->from_inv.name == player->getName());
2433 bool to_inv_is_current_player =
2434 (ma->to_inv.type == InventoryLocation::PLAYER) &&
2435 (ma->to_inv.name == player->getName());
2438 Disable moving items out of craftpreview
2440 if(ma->from_list == "craftpreview")
2442 infostream<<"Ignoring IMoveAction from "
2443 <<(ma->from_inv.dump())<<":"<<ma->from_list
2444 <<" to "<<(ma->to_inv.dump())<<":"<<ma->to_list
2445 <<" because src is "<<ma->from_list<<std::endl;
2451 Disable moving items into craftresult and craftpreview
2453 if(ma->to_list == "craftpreview" || ma->to_list == "craftresult")
2455 infostream<<"Ignoring IMoveAction from "
2456 <<(ma->from_inv.dump())<<":"<<ma->from_list
2457 <<" to "<<(ma->to_inv.dump())<<":"<<ma->to_list
2458 <<" because dst is "<<ma->to_list<<std::endl;
2463 // Disallow moving items in elsewhere than player's inventory
2464 // if not allowed to interact
2465 if(!checkPriv(player->getName(), "interact") &&
2466 (!from_inv_is_current_player ||
2467 !to_inv_is_current_player))
2469 infostream<<"Cannot move outside of player's inventory: "
2470 <<"No interact privilege"<<std::endl;
2476 Handle restrictions and special cases of the drop action
2478 else if(a->getType() == IACTION_DROP)
2480 IDropAction *da = (IDropAction*)a;
2482 da->from_inv.applyCurrentPlayer(player->getName());
2484 setInventoryModified(da->from_inv);
2487 Disable dropping items out of craftpreview
2489 if(da->from_list == "craftpreview")
2491 infostream<<"Ignoring IDropAction from "
2492 <<(da->from_inv.dump())<<":"<<da->from_list
2493 <<" because src is "<<da->from_list<<std::endl;
2498 // Disallow dropping items if not allowed to interact
2499 if(!checkPriv(player->getName(), "interact"))
2506 Handle restrictions and special cases of the craft action
2508 else if(a->getType() == IACTION_CRAFT)
2510 ICraftAction *ca = (ICraftAction*)a;
2512 ca->craft_inv.applyCurrentPlayer(player->getName());
2514 setInventoryModified(ca->craft_inv);
2516 //bool craft_inv_is_current_player =
2517 // (ca->craft_inv.type == InventoryLocation::PLAYER) &&
2518 // (ca->craft_inv.name == player->getName());
2520 // Disallow crafting if not allowed to interact
2521 if(!checkPriv(player->getName(), "interact"))
2523 infostream<<"Cannot craft: "
2524 <<"No interact privilege"<<std::endl;
2531 a->apply(this, playersao, this);
2535 else if(command == TOSERVER_CHAT_MESSAGE)
2543 std::string datastring((char*)&data[2], datasize-2);
2544 std::istringstream is(datastring, std::ios_base::binary);
2547 is.read((char*)buf, 2);
2548 u16 len = readU16(buf);
2550 std::wstring message;
2551 for(u16 i=0; i<len; i++)
2553 is.read((char*)buf, 2);
2554 message += (wchar_t)readU16(buf);
2557 // If something goes wrong, this player is to blame
2558 RollbackScopeActor rollback_scope(m_rollback,
2559 std::string("player:")+player->getName());
2561 // Get player name of this client
2562 std::wstring name = narrow_to_wide(player->getName());
2565 bool ate = m_script->on_chat_message(player->getName(),
2566 wide_to_narrow(message));
2567 // If script ate the message, don't proceed
2571 // Line to send to players
2573 // Whether to send to the player that sent the line
2574 bool send_to_sender = false;
2575 // Whether to send to other players
2576 bool send_to_others = false;
2578 // Commands are implemented in Lua, so only catch invalid
2579 // commands that were not "eaten" and send an error back
2580 if(message[0] == L'/')
2582 message = message.substr(1);
2583 send_to_sender = true;
2584 if(message.length() == 0)
2585 line += L"-!- Empty command";
2587 line += L"-!- Invalid command: " + str_split(message, L' ')[0];
2591 if(checkPriv(player->getName(), "shout")){
2596 send_to_others = true;
2598 line += L"-!- You don't have permission to shout.";
2599 send_to_sender = true;
2606 actionstream<<"CHAT: "<<wide_to_narrow(line)<<std::endl;
2609 Send the message to clients
2611 for(std::map<u16, RemoteClient*>::iterator
2612 i = m_clients.begin();
2613 i != m_clients.end(); ++i)
2615 // Get client and check that it is valid
2616 RemoteClient *client = i->second;
2617 assert(client->peer_id == i->first);
2618 if(client->serialization_version == SER_FMT_VER_INVALID)
2622 bool sender_selected = (peer_id == client->peer_id);
2623 if(sender_selected == true && send_to_sender == false)
2625 if(sender_selected == false && send_to_others == false)
2628 SendChatMessage(client->peer_id, line);
2632 else if(command == TOSERVER_DAMAGE)
2634 std::string datastring((char*)&data[2], datasize-2);
2635 std::istringstream is(datastring, std::ios_base::binary);
2636 u8 damage = readU8(is);
2638 if(g_settings->getBool("enable_damage"))
2640 actionstream<<player->getName()<<" damaged by "
2641 <<(int)damage<<" hp at "<<PP(player->getPosition()/BS)
2644 playersao->setHP(playersao->getHP() - damage);
2646 if(playersao->getHP() == 0 && playersao->m_hp_not_sent)
2649 if(playersao->m_hp_not_sent)
2650 SendPlayerHP(peer_id);
2653 else if(command == TOSERVER_BREATH)
2655 std::string datastring((char*)&data[2], datasize-2);
2656 std::istringstream is(datastring, std::ios_base::binary);
2657 u16 breath = readU16(is);
2658 playersao->setBreath(breath);
2660 else if(command == TOSERVER_PASSWORD)
2663 [0] u16 TOSERVER_PASSWORD
2664 [2] u8[28] old password
2665 [30] u8[28] new password
2668 if(datasize != 2+PASSWORD_SIZE*2)
2670 /*char password[PASSWORD_SIZE];
2671 for(u32 i=0; i<PASSWORD_SIZE-1; i++)
2672 password[i] = data[2+i];
2673 password[PASSWORD_SIZE-1] = 0;*/
2675 for(u32 i=0; i<PASSWORD_SIZE-1; i++)
2683 for(u32 i=0; i<PASSWORD_SIZE-1; i++)
2685 char c = data[2+PASSWORD_SIZE+i];
2691 if(!base64_is_valid(newpwd)){
2692 infostream<<"Server: "<<player->getName()<<" supplied invalid password hash"<<std::endl;
2693 // Wrong old password supplied!!
2694 SendChatMessage(peer_id, L"Invalid new password hash supplied. Password NOT changed.");
2698 infostream<<"Server: Client requests a password change from "
2699 <<"'"<<oldpwd<<"' to '"<<newpwd<<"'"<<std::endl;
2701 std::string playername = player->getName();
2703 std::string checkpwd;
2704 m_script->getAuth(playername, &checkpwd, NULL);
2706 if(oldpwd != checkpwd)
2708 infostream<<"Server: invalid old password"<<std::endl;
2709 // Wrong old password supplied!!
2710 SendChatMessage(peer_id, L"Invalid old password supplied. Password NOT changed.");
2714 bool success = m_script->setPassword(playername, newpwd);
2716 actionstream<<player->getName()<<" changes password"<<std::endl;
2717 SendChatMessage(peer_id, L"Password change successful.");
2719 actionstream<<player->getName()<<" tries to change password but "
2720 <<"it fails"<<std::endl;
2721 SendChatMessage(peer_id, L"Password change failed or inavailable.");
2724 else if(command == TOSERVER_PLAYERITEM)
2729 u16 item = readU16(&data[2]);
2730 playersao->setWieldIndex(item);
2732 else if(command == TOSERVER_RESPAWN)
2734 if(player->hp != 0 || !g_settings->getBool("enable_damage"))
2737 RespawnPlayer(peer_id);
2739 actionstream<<player->getName()<<" respawns at "
2740 <<PP(player->getPosition()/BS)<<std::endl;
2742 // ActiveObject is added to environment in AsyncRunStep after
2743 // the previous addition has been succesfully removed
2745 else if(command == TOSERVER_REQUEST_MEDIA) {
2746 std::string datastring((char*)&data[2], datasize-2);
2747 std::istringstream is(datastring, std::ios_base::binary);
2749 std::list<std::string> tosend;
2750 u16 numfiles = readU16(is);
2752 infostream<<"Sending "<<numfiles<<" files to "
2753 <<getPlayerName(peer_id)<<std::endl;
2754 verbosestream<<"TOSERVER_REQUEST_MEDIA: "<<std::endl;
2756 for(int i = 0; i < numfiles; i++) {
2757 std::string name = deSerializeString(is);
2758 tosend.push_back(name);
2759 verbosestream<<"TOSERVER_REQUEST_MEDIA: requested file "
2763 sendRequestedMedia(peer_id, tosend);
2765 // Now the client should know about everything
2766 // (definitions and files)
2767 getClient(peer_id)->definitions_sent = true;
2769 else if(command == TOSERVER_RECEIVED_MEDIA) {
2770 getClient(peer_id)->definitions_sent = true;
2772 else if(command == TOSERVER_INTERACT)
2774 std::string datastring((char*)&data[2], datasize-2);
2775 std::istringstream is(datastring, std::ios_base::binary);
2781 [5] u32 length of the next item
2782 [9] serialized PointedThing
2784 0: start digging (from undersurface) or use
2785 1: stop digging (all parameters ignored)
2786 2: digging completed
2787 3: place block or item (to abovesurface)
2790 u8 action = readU8(is);
2791 u16 item_i = readU16(is);
2792 std::istringstream tmp_is(deSerializeLongString(is), std::ios::binary);
2793 PointedThing pointed;
2794 pointed.deSerialize(tmp_is);
2796 verbosestream<<"TOSERVER_INTERACT: action="<<(int)action<<", item="
2797 <<item_i<<", pointed="<<pointed.dump()<<std::endl;
2801 verbosestream<<"TOSERVER_INTERACT: "<<player->getName()
2802 <<" tried to interact, but is dead!"<<std::endl;
2806 v3f player_pos = playersao->getLastGoodPosition();
2808 // Update wielded item
2809 playersao->setWieldIndex(item_i);
2811 // Get pointed to node (undefined if not POINTEDTYPE_NODE)
2812 v3s16 p_under = pointed.node_undersurface;
2813 v3s16 p_above = pointed.node_abovesurface;
2815 // Get pointed to object (NULL if not POINTEDTYPE_OBJECT)
2816 ServerActiveObject *pointed_object = NULL;
2817 if(pointed.type == POINTEDTHING_OBJECT)
2819 pointed_object = m_env->getActiveObject(pointed.object_id);
2820 if(pointed_object == NULL)
2822 verbosestream<<"TOSERVER_INTERACT: "
2823 "pointed object is NULL"<<std::endl;
2829 v3f pointed_pos_under = player_pos;
2830 v3f pointed_pos_above = player_pos;
2831 if(pointed.type == POINTEDTHING_NODE)
2833 pointed_pos_under = intToFloat(p_under, BS);
2834 pointed_pos_above = intToFloat(p_above, BS);
2836 else if(pointed.type == POINTEDTHING_OBJECT)
2838 pointed_pos_under = pointed_object->getBasePosition();
2839 pointed_pos_above = pointed_pos_under;
2843 Check that target is reasonably close
2844 (only when digging or placing things)
2846 if(action == 0 || action == 2 || action == 3)
2848 float d = player_pos.getDistanceFrom(pointed_pos_under);
2849 float max_d = BS * 14; // Just some large enough value
2851 actionstream<<"Player "<<player->getName()
2852 <<" tried to access "<<pointed.dump()
2854 <<"d="<<d<<", max_d="<<max_d
2855 <<". ignoring."<<std::endl;
2856 // Re-send block to revert change on client-side
2857 RemoteClient *client = getClient(peer_id);
2858 v3s16 blockpos = getNodeBlockPos(floatToInt(pointed_pos_under, BS));
2859 client->SetBlockNotSent(blockpos);
2861 m_script->on_cheat(playersao, "interacted_too_far");
2868 Make sure the player is allowed to do it
2870 if(!checkPriv(player->getName(), "interact"))
2872 actionstream<<player->getName()<<" attempted to interact with "
2873 <<pointed.dump()<<" without 'interact' privilege"
2875 // Re-send block to revert change on client-side
2876 RemoteClient *client = getClient(peer_id);
2877 // Digging completed -> under
2879 v3s16 blockpos = getNodeBlockPos(floatToInt(pointed_pos_under, BS));
2880 client->SetBlockNotSent(blockpos);
2882 // Placement -> above
2884 v3s16 blockpos = getNodeBlockPos(floatToInt(pointed_pos_above, BS));
2885 client->SetBlockNotSent(blockpos);
2891 If something goes wrong, this player is to blame
2893 RollbackScopeActor rollback_scope(m_rollback,
2894 std::string("player:")+player->getName());
2897 0: start digging or punch object
2901 if(pointed.type == POINTEDTHING_NODE)
2904 NOTE: This can be used in the future to check if
2905 somebody is cheating, by checking the timing.
2907 MapNode n(CONTENT_IGNORE);
2910 n = m_env->getMap().getNode(p_under);
2912 catch(InvalidPositionException &e)
2914 infostream<<"Server: Not punching: Node not found."
2915 <<" Adding block to emerge queue."
2917 m_emerge->enqueueBlockEmerge(peer_id, getNodeBlockPos(p_above), false);
2919 if(n.getContent() != CONTENT_IGNORE)
2920 m_script->node_on_punch(p_under, n, playersao);
2922 playersao->noCheatDigStart(p_under);
2924 else if(pointed.type == POINTEDTHING_OBJECT)
2926 // Skip if object has been removed
2927 if(pointed_object->m_removed)
2930 actionstream<<player->getName()<<" punches object "
2931 <<pointed.object_id<<": "
2932 <<pointed_object->getDescription()<<std::endl;
2934 ItemStack punchitem = playersao->getWieldedItem();
2935 ToolCapabilities toolcap =
2936 punchitem.getToolCapabilities(m_itemdef);
2937 v3f dir = (pointed_object->getBasePosition() -
2938 (player->getPosition() + player->getEyeOffset())
2940 float time_from_last_punch =
2941 playersao->resetTimeFromLastPunch();
2942 pointed_object->punch(dir, &toolcap, playersao,
2943 time_from_last_punch);
2951 else if(action == 1)
2956 2: Digging completed
2958 else if(action == 2)
2960 // Only digging of nodes
2961 if(pointed.type == POINTEDTHING_NODE)
2963 MapNode n(CONTENT_IGNORE);
2966 n = m_env->getMap().getNode(p_under);
2968 catch(InvalidPositionException &e)
2970 infostream<<"Server: Not finishing digging: Node not found."
2971 <<" Adding block to emerge queue."
2973 m_emerge->enqueueBlockEmerge(peer_id, getNodeBlockPos(p_above), false);
2976 /* Cheat prevention */
2977 bool is_valid_dig = true;
2978 if(!isSingleplayer() && !g_settings->getBool("disable_anticheat"))
2980 v3s16 nocheat_p = playersao->getNoCheatDigPos();
2981 float nocheat_t = playersao->getNoCheatDigTime();
2982 playersao->noCheatDigEnd();
2983 // If player didn't start digging this, ignore dig
2984 if(nocheat_p != p_under){
2985 infostream<<"Server: NoCheat: "<<player->getName()
2986 <<" started digging "
2987 <<PP(nocheat_p)<<" and completed digging "
2988 <<PP(p_under)<<"; not digging."<<std::endl;
2989 is_valid_dig = false;
2991 m_script->on_cheat(playersao, "finished_unknown_dig");
2993 // Get player's wielded item
2994 ItemStack playeritem;
2995 InventoryList *mlist = playersao->getInventory()->getList("main");
2997 playeritem = mlist->getItem(playersao->getWieldIndex());
2998 ToolCapabilities playeritem_toolcap =
2999 playeritem.getToolCapabilities(m_itemdef);
3000 // Get diggability and expected digging time
3001 DigParams params = getDigParams(m_nodedef->get(n).groups,
3002 &playeritem_toolcap);
3003 // If can't dig, try hand
3004 if(!params.diggable){
3005 const ItemDefinition &hand = m_itemdef->get("");
3006 const ToolCapabilities *tp = hand.tool_capabilities;
3008 params = getDigParams(m_nodedef->get(n).groups, tp);
3010 // If can't dig, ignore dig
3011 if(!params.diggable){
3012 infostream<<"Server: NoCheat: "<<player->getName()
3013 <<" completed digging "<<PP(p_under)
3014 <<", which is not diggable with tool. not digging."
3016 is_valid_dig = false;
3018 m_script->on_cheat(playersao, "dug_unbreakable");
3020 // Check digging time
3021 // If already invalidated, we don't have to
3023 // Well not our problem then
3025 // Clean and long dig
3026 else if(params.time > 2.0 && nocheat_t * 1.2 > params.time){
3027 // All is good, but grab time from pool; don't care if
3028 // it's actually available
3029 playersao->getDigPool().grab(params.time);
3031 // Short or laggy dig
3032 // Try getting the time from pool
3033 else if(playersao->getDigPool().grab(params.time)){
3038 infostream<<"Server: NoCheat: "<<player->getName()
3039 <<" completed digging "<<PP(p_under)
3040 <<"too fast; not digging."<<std::endl;
3041 is_valid_dig = false;
3043 m_script->on_cheat(playersao, "dug_too_fast");
3047 /* Actually dig node */
3049 if(is_valid_dig && n.getContent() != CONTENT_IGNORE)
3050 m_script->node_on_dig(p_under, n, playersao);
3052 // Send unusual result (that is, node not being removed)
3053 if(m_env->getMap().getNodeNoEx(p_under).getContent() != CONTENT_AIR)
3055 // Re-send block to revert change on client-side
3056 RemoteClient *client = getClient(peer_id);
3057 v3s16 blockpos = getNodeBlockPos(floatToInt(pointed_pos_under, BS));
3058 client->SetBlockNotSent(blockpos);
3064 3: place block or right-click object
3066 else if(action == 3)
3068 ItemStack item = playersao->getWieldedItem();
3070 // Reset build time counter
3071 if(pointed.type == POINTEDTHING_NODE &&
3072 item.getDefinition(m_itemdef).type == ITEM_NODE)
3073 getClient(peer_id)->m_time_from_building = 0.0;
3075 if(pointed.type == POINTEDTHING_OBJECT)
3077 // Right click object
3079 // Skip if object has been removed
3080 if(pointed_object->m_removed)
3083 actionstream<<player->getName()<<" right-clicks object "
3084 <<pointed.object_id<<": "
3085 <<pointed_object->getDescription()<<std::endl;
3088 pointed_object->rightClick(playersao);
3090 else if(m_script->item_OnPlace(
3091 item, playersao, pointed))
3093 // Placement was handled in lua
3095 // Apply returned ItemStack
3096 playersao->setWieldedItem(item);
3099 // If item has node placement prediction, always send the
3100 // blocks to make sure the client knows what exactly happened
3101 if(item.getDefinition(m_itemdef).node_placement_prediction != ""){
3102 RemoteClient *client = getClient(peer_id);
3103 v3s16 blockpos = getNodeBlockPos(floatToInt(pointed_pos_above, BS));
3104 client->SetBlockNotSent(blockpos);
3105 v3s16 blockpos2 = getNodeBlockPos(floatToInt(pointed_pos_under, BS));
3106 if(blockpos2 != blockpos){
3107 client->SetBlockNotSent(blockpos2);
3115 else if(action == 4)
3117 ItemStack item = playersao->getWieldedItem();
3119 actionstream<<player->getName()<<" uses "<<item.name
3120 <<", pointing at "<<pointed.dump()<<std::endl;
3122 if(m_script->item_OnUse(
3123 item, playersao, pointed))
3125 // Apply returned ItemStack
3126 playersao->setWieldedItem(item);
3133 Catch invalid actions
3137 infostream<<"WARNING: Server: Invalid action "
3138 <<action<<std::endl;
3141 else if(command == TOSERVER_REMOVED_SOUNDS)
3143 std::string datastring((char*)&data[2], datasize-2);
3144 std::istringstream is(datastring, std::ios_base::binary);
3146 int num = readU16(is);
3147 for(int k=0; k<num; k++){
3148 s32 id = readS32(is);
3149 std::map<s32, ServerPlayingSound>::iterator i =
3150 m_playing_sounds.find(id);
3151 if(i == m_playing_sounds.end())
3153 ServerPlayingSound &psound = i->second;
3154 psound.clients.erase(peer_id);
3155 if(psound.clients.size() == 0)
3156 m_playing_sounds.erase(i++);
3159 else if(command == TOSERVER_NODEMETA_FIELDS)
3161 std::string datastring((char*)&data[2], datasize-2);
3162 std::istringstream is(datastring, std::ios_base::binary);
3164 v3s16 p = readV3S16(is);
3165 std::string formname = deSerializeString(is);
3166 int num = readU16(is);
3167 std::map<std::string, std::string> fields;
3168 for(int k=0; k<num; k++){
3169 std::string fieldname = deSerializeString(is);
3170 std::string fieldvalue = deSerializeLongString(is);
3171 fields[fieldname] = fieldvalue;
3174 // If something goes wrong, this player is to blame
3175 RollbackScopeActor rollback_scope(m_rollback,
3176 std::string("player:")+player->getName());
3178 // Check the target node for rollback data; leave others unnoticed
3179 RollbackNode rn_old(&m_env->getMap(), p, this);
3181 m_script->node_on_receive_fields(p, formname, fields,playersao);
3183 // Report rollback data
3184 RollbackNode rn_new(&m_env->getMap(), p, this);
3185 if(rollback() && rn_new != rn_old){
3186 RollbackAction action;
3187 action.setSetNode(p, rn_old, rn_new);
3188 rollback()->reportAction(action);
3191 else if(command == TOSERVER_INVENTORY_FIELDS)
3193 std::string datastring((char*)&data[2], datasize-2);
3194 std::istringstream is(datastring, std::ios_base::binary);
3196 std::string formname = deSerializeString(is);
3197 int num = readU16(is);
3198 std::map<std::string, std::string> fields;
3199 for(int k=0; k<num; k++){
3200 std::string fieldname = deSerializeString(is);
3201 std::string fieldvalue = deSerializeLongString(is);
3202 fields[fieldname] = fieldvalue;
3205 m_script->on_playerReceiveFields(playersao, formname, fields);
3209 infostream<<"Server::ProcessData(): Ignoring "
3210 "unknown command "<<command<<std::endl;
3214 catch(SendFailedException &e)
3216 errorstream<<"Server::ProcessData(): SendFailedException: "
3222 void Server::setTimeOfDay(u32 time)
3224 m_env->setTimeOfDay(time);
3225 m_time_of_day_send_timer = 0;
3228 void Server::onMapEditEvent(MapEditEvent *event)
3230 //infostream<<"Server::onMapEditEvent()"<<std::endl;
3231 if(m_ignore_map_edit_events)
3233 if(m_ignore_map_edit_events_area.contains(event->getArea()))
3235 MapEditEvent *e = event->clone();
3236 m_unsent_map_edit_queue.push_back(e);
3239 Inventory* Server::getInventory(const InventoryLocation &loc)
3242 case InventoryLocation::UNDEFINED:
3245 case InventoryLocation::CURRENT_PLAYER:
3248 case InventoryLocation::PLAYER:
3250 Player *player = m_env->getPlayer(loc.name.c_str());
3253 PlayerSAO *playersao = player->getPlayerSAO();
3256 return playersao->getInventory();
3259 case InventoryLocation::NODEMETA:
3261 NodeMetadata *meta = m_env->getMap().getNodeMetadata(loc.p);
3264 return meta->getInventory();
3267 case InventoryLocation::DETACHED:
3269 if(m_detached_inventories.count(loc.name) == 0)
3271 return m_detached_inventories[loc.name];
3279 void Server::setInventoryModified(const InventoryLocation &loc)
3282 case InventoryLocation::UNDEFINED:
3285 case InventoryLocation::PLAYER:
3287 Player *player = m_env->getPlayer(loc.name.c_str());
3290 PlayerSAO *playersao = player->getPlayerSAO();
3293 playersao->m_inventory_not_sent = true;
3294 playersao->m_wielded_item_not_sent = true;
3297 case InventoryLocation::NODEMETA:
3299 v3s16 blockpos = getNodeBlockPos(loc.p);
3301 MapBlock *block = m_env->getMap().getBlockNoCreateNoEx(blockpos);
3303 block->raiseModified(MOD_STATE_WRITE_NEEDED);
3305 setBlockNotSent(blockpos);
3308 case InventoryLocation::DETACHED:
3310 sendDetachedInventoryToAll(loc.name);
3318 void Server::peerAdded(con::Peer *peer)
3320 DSTACK(__FUNCTION_NAME);
3321 verbosestream<<"Server::peerAdded(): peer->id="
3322 <<peer->id<<std::endl;
3325 c.type = PEER_ADDED;
3326 c.peer_id = peer->id;
3328 m_peer_change_queue.push_back(c);
3331 void Server::deletingPeer(con::Peer *peer, bool timeout)
3333 DSTACK(__FUNCTION_NAME);
3334 verbosestream<<"Server::deletingPeer(): peer->id="
3335 <<peer->id<<", timeout="<<timeout<<std::endl;
3338 c.type = PEER_REMOVED;
3339 c.peer_id = peer->id;
3340 c.timeout = timeout;
3341 m_peer_change_queue.push_back(c);
3348 void Server::SendMovement(con::Connection &con, u16 peer_id)
3350 DSTACK(__FUNCTION_NAME);
3351 std::ostringstream os(std::ios_base::binary);
3353 writeU16(os, TOCLIENT_MOVEMENT);
3354 writeF1000(os, g_settings->getFloat("movement_acceleration_default"));
3355 writeF1000(os, g_settings->getFloat("movement_acceleration_air"));
3356 writeF1000(os, g_settings->getFloat("movement_acceleration_fast"));
3357 writeF1000(os, g_settings->getFloat("movement_speed_walk"));
3358 writeF1000(os, g_settings->getFloat("movement_speed_crouch"));
3359 writeF1000(os, g_settings->getFloat("movement_speed_fast"));
3360 writeF1000(os, g_settings->getFloat("movement_speed_climb"));
3361 writeF1000(os, g_settings->getFloat("movement_speed_jump"));
3362 writeF1000(os, g_settings->getFloat("movement_liquid_fluidity"));
3363 writeF1000(os, g_settings->getFloat("movement_liquid_fluidity_smooth"));
3364 writeF1000(os, g_settings->getFloat("movement_liquid_sink"));
3365 writeF1000(os, g_settings->getFloat("movement_gravity"));
3368 std::string s = os.str();
3369 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3371 con.Send(peer_id, 0, data, true);
3374 void Server::SendHP(con::Connection &con, u16 peer_id, u8 hp)
3376 DSTACK(__FUNCTION_NAME);
3377 std::ostringstream os(std::ios_base::binary);
3379 writeU16(os, TOCLIENT_HP);
3383 std::string s = os.str();
3384 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3386 con.Send(peer_id, 0, data, true);
3389 void Server::SendBreath(con::Connection &con, u16 peer_id, u16 breath)
3391 DSTACK(__FUNCTION_NAME);
3392 std::ostringstream os(std::ios_base::binary);
3394 writeU16(os, TOCLIENT_BREATH);
3395 writeU16(os, breath);
3398 std::string s = os.str();
3399 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3401 con.Send(peer_id, 0, data, true);
3404 void Server::SendAccessDenied(con::Connection &con, u16 peer_id,
3405 const std::wstring &reason)
3407 DSTACK(__FUNCTION_NAME);
3408 std::ostringstream os(std::ios_base::binary);
3410 writeU16(os, TOCLIENT_ACCESS_DENIED);
3411 os<<serializeWideString(reason);
3414 std::string s = os.str();
3415 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3417 con.Send(peer_id, 0, data, true);
3420 void Server::SendDeathscreen(con::Connection &con, u16 peer_id,
3421 bool set_camera_point_target, v3f camera_point_target)
3423 DSTACK(__FUNCTION_NAME);
3424 std::ostringstream os(std::ios_base::binary);
3426 writeU16(os, TOCLIENT_DEATHSCREEN);
3427 writeU8(os, set_camera_point_target);
3428 writeV3F1000(os, camera_point_target);
3431 std::string s = os.str();
3432 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3434 con.Send(peer_id, 0, data, true);
3437 void Server::SendItemDef(con::Connection &con, u16 peer_id,
3438 IItemDefManager *itemdef, u16 protocol_version)
3440 DSTACK(__FUNCTION_NAME);
3441 std::ostringstream os(std::ios_base::binary);
3445 u32 length of the next item
3446 zlib-compressed serialized ItemDefManager
3448 writeU16(os, TOCLIENT_ITEMDEF);
3449 std::ostringstream tmp_os(std::ios::binary);
3450 itemdef->serialize(tmp_os, protocol_version);
3451 std::ostringstream tmp_os2(std::ios::binary);
3452 compressZlib(tmp_os.str(), tmp_os2);
3453 os<<serializeLongString(tmp_os2.str());
3456 std::string s = os.str();
3457 verbosestream<<"Server: Sending item definitions to id("<<peer_id
3458 <<"): size="<<s.size()<<std::endl;
3459 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3461 con.Send(peer_id, 0, data, true);
3464 void Server::SendNodeDef(con::Connection &con, u16 peer_id,
3465 INodeDefManager *nodedef, u16 protocol_version)
3467 DSTACK(__FUNCTION_NAME);
3468 std::ostringstream os(std::ios_base::binary);
3472 u32 length of the next item
3473 zlib-compressed serialized NodeDefManager
3475 writeU16(os, TOCLIENT_NODEDEF);
3476 std::ostringstream tmp_os(std::ios::binary);
3477 nodedef->serialize(tmp_os, protocol_version);
3478 std::ostringstream tmp_os2(std::ios::binary);
3479 compressZlib(tmp_os.str(), tmp_os2);
3480 os<<serializeLongString(tmp_os2.str());
3483 std::string s = os.str();
3484 verbosestream<<"Server: Sending node definitions to id("<<peer_id
3485 <<"): size="<<s.size()<<std::endl;
3486 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3488 con.Send(peer_id, 0, data, true);
3492 Non-static send methods
3495 void Server::SendInventory(u16 peer_id)
3497 DSTACK(__FUNCTION_NAME);
3499 PlayerSAO *playersao = getPlayerSAO(peer_id);
3502 playersao->m_inventory_not_sent = false;
3508 std::ostringstream os;
3509 playersao->getInventory()->serialize(os);
3511 std::string s = os.str();
3513 SharedBuffer<u8> data(s.size()+2);
3514 writeU16(&data[0], TOCLIENT_INVENTORY);
3515 memcpy(&data[2], s.c_str(), s.size());
3518 m_con.Send(peer_id, 0, data, true);
3521 void Server::SendChatMessage(u16 peer_id, const std::wstring &message)
3523 DSTACK(__FUNCTION_NAME);
3525 std::ostringstream os(std::ios_base::binary);
3529 writeU16(buf, TOCLIENT_CHAT_MESSAGE);
3530 os.write((char*)buf, 2);
3533 writeU16(buf, message.size());
3534 os.write((char*)buf, 2);
3537 for(u32 i=0; i<message.size(); i++)
3541 os.write((char*)buf, 2);
3545 std::string s = os.str();
3546 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3548 m_con.Send(peer_id, 0, data, true);
3551 void Server::SendShowFormspecMessage(u16 peer_id, const std::string formspec,
3552 const std::string formname)
3554 DSTACK(__FUNCTION_NAME);
3556 std::ostringstream os(std::ios_base::binary);
3560 writeU16(buf, TOCLIENT_SHOW_FORMSPEC);
3561 os.write((char*)buf, 2);
3562 os<<serializeLongString(formspec);
3563 os<<serializeString(formname);
3566 std::string s = os.str();
3567 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3569 m_con.Send(peer_id, 0, data, true);
3572 // Spawns a particle on peer with peer_id
3573 void Server::SendSpawnParticle(u16 peer_id, v3f pos, v3f velocity, v3f acceleration,
3574 float expirationtime, float size, bool collisiondetection,
3575 std::string texture)
3577 DSTACK(__FUNCTION_NAME);
3579 std::ostringstream os(std::ios_base::binary);
3580 writeU16(os, TOCLIENT_SPAWN_PARTICLE);
3581 writeV3F1000(os, pos);
3582 writeV3F1000(os, velocity);
3583 writeV3F1000(os, acceleration);
3584 writeF1000(os, expirationtime);
3585 writeF1000(os, size);
3586 writeU8(os, collisiondetection);
3587 os<<serializeLongString(texture);
3590 std::string s = os.str();
3591 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3593 m_con.Send(peer_id, 0, data, true);
3596 // Spawns a particle on all peers
3597 void Server::SendSpawnParticleAll(v3f pos, v3f velocity, v3f acceleration,
3598 float expirationtime, float size, bool collisiondetection,
3599 std::string texture)
3601 for(std::map<u16, RemoteClient*>::iterator
3602 i = m_clients.begin();
3603 i != m_clients.end(); i++)
3605 // Get client and check that it is valid
3606 RemoteClient *client = i->second;
3607 assert(client->peer_id == i->first);
3608 if(client->serialization_version == SER_FMT_VER_INVALID)
3611 SendSpawnParticle(client->peer_id, pos, velocity, acceleration,
3612 expirationtime, size, collisiondetection, texture);
3616 // Adds a ParticleSpawner on peer with peer_id
3617 void Server::SendAddParticleSpawner(u16 peer_id, u16 amount, float spawntime, v3f minpos, v3f maxpos,
3618 v3f minvel, v3f maxvel, v3f minacc, v3f maxacc, float minexptime, float maxexptime,
3619 float minsize, float maxsize, bool collisiondetection, std::string texture, u32 id)
3621 DSTACK(__FUNCTION_NAME);
3623 std::ostringstream os(std::ios_base::binary);
3624 writeU16(os, TOCLIENT_ADD_PARTICLESPAWNER);
3626 writeU16(os, amount);
3627 writeF1000(os, spawntime);
3628 writeV3F1000(os, minpos);
3629 writeV3F1000(os, maxpos);
3630 writeV3F1000(os, minvel);
3631 writeV3F1000(os, maxvel);
3632 writeV3F1000(os, minacc);
3633 writeV3F1000(os, maxacc);
3634 writeF1000(os, minexptime);
3635 writeF1000(os, maxexptime);
3636 writeF1000(os, minsize);
3637 writeF1000(os, maxsize);
3638 writeU8(os, collisiondetection);
3639 os<<serializeLongString(texture);
3643 std::string s = os.str();
3644 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3646 m_con.Send(peer_id, 0, data, true);
3649 // Adds a ParticleSpawner on all peers
3650 void Server::SendAddParticleSpawnerAll(u16 amount, float spawntime, v3f minpos, v3f maxpos,
3651 v3f minvel, v3f maxvel, v3f minacc, v3f maxacc, float minexptime, float maxexptime,
3652 float minsize, float maxsize, bool collisiondetection, std::string texture, u32 id)
3654 for(std::map<u16, RemoteClient*>::iterator
3655 i = m_clients.begin();
3656 i != m_clients.end(); i++)
3658 // Get client and check that it is valid
3659 RemoteClient *client = i->second;
3660 assert(client->peer_id == i->first);
3661 if(client->serialization_version == SER_FMT_VER_INVALID)
3664 SendAddParticleSpawner(client->peer_id, amount, spawntime,
3665 minpos, maxpos, minvel, maxvel, minacc, maxacc,
3666 minexptime, maxexptime, minsize, maxsize, collisiondetection, texture, id);
3670 void Server::SendDeleteParticleSpawner(u16 peer_id, u32 id)
3672 DSTACK(__FUNCTION_NAME);
3674 std::ostringstream os(std::ios_base::binary);
3675 writeU16(os, TOCLIENT_DELETE_PARTICLESPAWNER);
3680 std::string s = os.str();
3681 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3683 m_con.Send(peer_id, 0, data, true);
3686 void Server::SendDeleteParticleSpawnerAll(u32 id)
3688 for(std::map<u16, RemoteClient*>::iterator
3689 i = m_clients.begin();
3690 i != m_clients.end(); i++)
3692 // Get client and check that it is valid
3693 RemoteClient *client = i->second;
3694 assert(client->peer_id == i->first);
3695 if(client->serialization_version == SER_FMT_VER_INVALID)
3698 SendDeleteParticleSpawner(client->peer_id, id);
3702 void Server::SendHUDAdd(u16 peer_id, u32 id, HudElement *form)
3704 std::ostringstream os(std::ios_base::binary);
3707 writeU16(os, TOCLIENT_HUDADD);
3709 writeU8(os, (u8)form->type);
3710 writeV2F1000(os, form->pos);
3711 os << serializeString(form->name);
3712 writeV2F1000(os, form->scale);
3713 os << serializeString(form->text);
3714 writeU32(os, form->number);
3715 writeU32(os, form->item);
3716 writeU32(os, form->dir);
3717 writeV2F1000(os, form->align);
3718 writeV2F1000(os, form->offset);
3721 std::string s = os.str();
3722 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3724 m_con.Send(peer_id, 0, data, true);
3727 void Server::SendHUDRemove(u16 peer_id, u32 id)
3729 std::ostringstream os(std::ios_base::binary);
3732 writeU16(os, TOCLIENT_HUDRM);
3736 std::string s = os.str();
3737 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3739 m_con.Send(peer_id, 0, data, true);
3742 void Server::SendHUDChange(u16 peer_id, u32 id, HudElementStat stat, void *value)
3744 std::ostringstream os(std::ios_base::binary);
3747 writeU16(os, TOCLIENT_HUDCHANGE);
3749 writeU8(os, (u8)stat);
3752 case HUD_STAT_SCALE:
3753 case HUD_STAT_ALIGN:
3754 case HUD_STAT_OFFSET:
3755 writeV2F1000(os, *(v2f *)value);
3759 os << serializeString(*(std::string *)value);
3761 case HUD_STAT_NUMBER:
3765 writeU32(os, *(u32 *)value);
3770 std::string s = os.str();
3771 SharedBuffer<u8> data((u8 *)s.c_str(), s.size());
3773 m_con.Send(peer_id, 0, data, true);
3776 void Server::SendHUDSetFlags(u16 peer_id, u32 flags, u32 mask)
3778 std::ostringstream os(std::ios_base::binary);
3781 writeU16(os, TOCLIENT_HUD_SET_FLAGS);
3782 writeU32(os, flags);
3786 std::string s = os.str();
3787 SharedBuffer<u8> data((u8 *)s.c_str(), s.size());
3789 m_con.Send(peer_id, 0, data, true);
3792 void Server::SendHUDSetParam(u16 peer_id, u16 param, const std::string &value)
3794 std::ostringstream os(std::ios_base::binary);
3797 writeU16(os, TOCLIENT_HUD_SET_PARAM);
3798 writeU16(os, param);
3799 os<<serializeString(value);
3802 std::string s = os.str();
3803 SharedBuffer<u8> data((u8 *)s.c_str(), s.size());
3805 m_con.Send(peer_id, 0, data, true);
3808 void Server::BroadcastChatMessage(const std::wstring &message)
3810 for(std::map<u16, RemoteClient*>::iterator
3811 i = m_clients.begin();
3812 i != m_clients.end(); ++i)
3814 // Get client and check that it is valid
3815 RemoteClient *client = i->second;
3816 assert(client->peer_id == i->first);
3817 if(client->serialization_version == SER_FMT_VER_INVALID)
3820 SendChatMessage(client->peer_id, message);
3824 void Server::SendTimeOfDay(u16 peer_id, u16 time, f32 time_speed)
3826 DSTACK(__FUNCTION_NAME);
3829 SharedBuffer<u8> data(2+2+4);
3830 writeU16(&data[0], TOCLIENT_TIME_OF_DAY);
3831 writeU16(&data[2], time);
3832 writeF1000(&data[4], time_speed);
3835 m_con.Send(peer_id, 0, data, true);
3838 void Server::SendPlayerHP(u16 peer_id)
3840 DSTACK(__FUNCTION_NAME);
3841 PlayerSAO *playersao = getPlayerSAO(peer_id);
3843 playersao->m_hp_not_sent = false;
3844 SendHP(m_con, peer_id, playersao->getHP());
3846 // Send to other clients
3847 std::string str = gob_cmd_punched(playersao->readDamage(), playersao->getHP());
3848 ActiveObjectMessage aom(playersao->getId(), true, str);
3849 playersao->m_messages_out.push_back(aom);
3852 void Server::SendPlayerBreath(u16 peer_id)
3854 DSTACK(__FUNCTION_NAME);
3855 PlayerSAO *playersao = getPlayerSAO(peer_id);
3857 playersao->m_breath_not_sent = false;
3858 SendBreath(m_con, peer_id, playersao->getBreath());
3861 void Server::SendMovePlayer(u16 peer_id)
3863 DSTACK(__FUNCTION_NAME);
3864 Player *player = m_env->getPlayer(peer_id);
3867 std::ostringstream os(std::ios_base::binary);
3868 writeU16(os, TOCLIENT_MOVE_PLAYER);
3869 writeV3F1000(os, player->getPosition());
3870 writeF1000(os, player->getPitch());
3871 writeF1000(os, player->getYaw());
3874 v3f pos = player->getPosition();
3875 f32 pitch = player->getPitch();
3876 f32 yaw = player->getYaw();
3877 verbosestream<<"Server: Sending TOCLIENT_MOVE_PLAYER"
3878 <<" pos=("<<pos.X<<","<<pos.Y<<","<<pos.Z<<")"
3885 std::string s = os.str();
3886 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3888 m_con.Send(peer_id, 0, data, true);
3891 void Server::SendPlayerPrivileges(u16 peer_id)
3893 Player *player = m_env->getPlayer(peer_id);
3895 if(player->peer_id == PEER_ID_INEXISTENT)
3898 std::set<std::string> privs;
3899 m_script->getAuth(player->getName(), NULL, &privs);
3901 std::ostringstream os(std::ios_base::binary);
3902 writeU16(os, TOCLIENT_PRIVILEGES);
3903 writeU16(os, privs.size());
3904 for(std::set<std::string>::const_iterator i = privs.begin();
3905 i != privs.end(); i++){
3906 os<<serializeString(*i);
3910 std::string s = os.str();
3911 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3913 m_con.Send(peer_id, 0, data, true);
3916 void Server::SendPlayerInventoryFormspec(u16 peer_id)
3918 Player *player = m_env->getPlayer(peer_id);
3920 if(player->peer_id == PEER_ID_INEXISTENT)
3923 std::ostringstream os(std::ios_base::binary);
3924 writeU16(os, TOCLIENT_INVENTORY_FORMSPEC);
3925 os<<serializeLongString(player->inventory_formspec);
3928 std::string s = os.str();
3929 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3931 m_con.Send(peer_id, 0, data, true);
3934 s32 Server::playSound(const SimpleSoundSpec &spec,
3935 const ServerSoundParams ¶ms)
3937 // Find out initial position of sound
3938 bool pos_exists = false;
3939 v3f pos = params.getPos(m_env, &pos_exists);
3940 // If position is not found while it should be, cancel sound
3941 if(pos_exists != (params.type != ServerSoundParams::SSP_LOCAL))
3943 // Filter destination clients
3944 std::set<RemoteClient*> dst_clients;
3945 if(params.to_player != "")
3947 Player *player = m_env->getPlayer(params.to_player.c_str());
3949 infostream<<"Server::playSound: Player \""<<params.to_player
3950 <<"\" not found"<<std::endl;
3953 if(player->peer_id == PEER_ID_INEXISTENT){
3954 infostream<<"Server::playSound: Player \""<<params.to_player
3955 <<"\" not connected"<<std::endl;
3958 RemoteClient *client = getClient(player->peer_id);
3959 dst_clients.insert(client);
3963 for(std::map<u16, RemoteClient*>::iterator
3964 i = m_clients.begin(); i != m_clients.end(); ++i)
3966 RemoteClient *client = i->second;
3967 Player *player = m_env->getPlayer(client->peer_id);
3971 if(player->getPosition().getDistanceFrom(pos) >
3972 params.max_hear_distance)
3975 dst_clients.insert(client);
3978 if(dst_clients.size() == 0)
3981 s32 id = m_next_sound_id++;
3982 // The sound will exist as a reference in m_playing_sounds
3983 m_playing_sounds[id] = ServerPlayingSound();
3984 ServerPlayingSound &psound = m_playing_sounds[id];
3985 psound.params = params;
3986 for(std::set<RemoteClient*>::iterator i = dst_clients.begin();
3987 i != dst_clients.end(); i++)
3988 psound.clients.insert((*i)->peer_id);
3990 std::ostringstream os(std::ios_base::binary);
3991 writeU16(os, TOCLIENT_PLAY_SOUND);
3993 os<<serializeString(spec.name);
3994 writeF1000(os, spec.gain * params.gain);
3995 writeU8(os, params.type);
3996 writeV3F1000(os, pos);
3997 writeU16(os, params.object);
3998 writeU8(os, params.loop);
4000 std::string s = os.str();
4001 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
4003 for(std::set<RemoteClient*>::iterator i = dst_clients.begin();
4004 i != dst_clients.end(); i++){
4006 m_con.Send((*i)->peer_id, 0, data, true);
4010 void Server::stopSound(s32 handle)
4012 // Get sound reference
4013 std::map<s32, ServerPlayingSound>::iterator i =
4014 m_playing_sounds.find(handle);
4015 if(i == m_playing_sounds.end())
4017 ServerPlayingSound &psound = i->second;
4019 std::ostringstream os(std::ios_base::binary);
4020 writeU16(os, TOCLIENT_STOP_SOUND);
4021 writeS32(os, handle);
4023 std::string s = os.str();
4024 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
4026 for(std::set<u16>::iterator i = psound.clients.begin();
4027 i != psound.clients.end(); i++){
4029 m_con.Send(*i, 0, data, true);
4031 // Remove sound reference
4032 m_playing_sounds.erase(i);
4035 void Server::sendRemoveNode(v3s16 p, u16 ignore_id,
4036 std::list<u16> *far_players, float far_d_nodes)
4038 float maxd = far_d_nodes*BS;
4039 v3f p_f = intToFloat(p, BS);
4043 SharedBuffer<u8> reply(replysize);
4044 writeU16(&reply[0], TOCLIENT_REMOVENODE);
4045 writeS16(&reply[2], p.X);
4046 writeS16(&reply[4], p.Y);
4047 writeS16(&reply[6], p.Z);
4049 for(std::map<u16, RemoteClient*>::iterator
4050 i = m_clients.begin();
4051 i != m_clients.end(); ++i)
4053 // Get client and check that it is valid
4054 RemoteClient *client = i->second;
4055 assert(client->peer_id == i->first);
4056 if(client->serialization_version == SER_FMT_VER_INVALID)
4059 // Don't send if it's the same one
4060 if(client->peer_id == ignore_id)
4066 Player *player = m_env->getPlayer(client->peer_id);
4069 // If player is far away, only set modified blocks not sent
4070 v3f player_pos = player->getPosition();
4071 if(player_pos.getDistanceFrom(p_f) > maxd)
4073 far_players->push_back(client->peer_id);
4080 m_con.Send(client->peer_id, 0, reply, true);
4084 void Server::sendAddNode(v3s16 p, MapNode n, u16 ignore_id,
4085 std::list<u16> *far_players, float far_d_nodes,
4086 bool remove_metadata)
4088 float maxd = far_d_nodes*BS;
4089 v3f p_f = intToFloat(p, BS);
4091 for(std::map<u16, RemoteClient*>::iterator
4092 i = m_clients.begin();
4093 i != m_clients.end(); ++i)
4095 // Get client and check that it is valid
4096 RemoteClient *client = i->second;
4097 assert(client->peer_id == i->first);
4098 if(client->serialization_version == SER_FMT_VER_INVALID)
4101 // Don't send if it's the same one
4102 if(client->peer_id == ignore_id)
4108 Player *player = m_env->getPlayer(client->peer_id);
4111 // If player is far away, only set modified blocks not sent
4112 v3f player_pos = player->getPosition();
4113 if(player_pos.getDistanceFrom(p_f) > maxd)
4115 far_players->push_back(client->peer_id);
4122 u32 replysize = 9 + MapNode::serializedLength(client->serialization_version);
4123 SharedBuffer<u8> reply(replysize);
4124 writeU16(&reply[0], TOCLIENT_ADDNODE);
4125 writeS16(&reply[2], p.X);
4126 writeS16(&reply[4], p.Y);
4127 writeS16(&reply[6], p.Z);
4128 n.serialize(&reply[8], client->serialization_version);
4129 u32 index = 8 + MapNode::serializedLength(client->serialization_version);
4130 writeU8(&reply[index], remove_metadata ? 0 : 1);
4132 if (!remove_metadata) {
4133 if (client->net_proto_version <= 21) {
4134 // Old clients always clear metadata; fix it
4135 // by sending the full block again.
4136 client->SetBlockNotSent(p);
4141 m_con.Send(client->peer_id, 0, reply, true);
4145 void Server::setBlockNotSent(v3s16 p)
4147 for(std::map<u16, RemoteClient*>::iterator
4148 i = m_clients.begin();
4149 i != m_clients.end(); ++i)
4151 RemoteClient *client = i->second;
4152 client->SetBlockNotSent(p);
4156 void Server::SendBlockNoLock(u16 peer_id, MapBlock *block, u8 ver, u16 net_proto_version)
4158 DSTACK(__FUNCTION_NAME);
4160 v3s16 p = block->getPos();
4164 bool completely_air = true;
4165 for(s16 z0=0; z0<MAP_BLOCKSIZE; z0++)
4166 for(s16 x0=0; x0<MAP_BLOCKSIZE; x0++)
4167 for(s16 y0=0; y0<MAP_BLOCKSIZE; y0++)
4169 if(block->getNodeNoEx(v3s16(x0,y0,z0)).d != CONTENT_AIR)
4171 completely_air = false;
4172 x0 = y0 = z0 = MAP_BLOCKSIZE; // Break out
4177 infostream<<"Server: Sending block ("<<p.X<<","<<p.Y<<","<<p.Z<<"): ";
4179 infostream<<"[completely air] ";
4180 infostream<<std::endl;
4184 Create a packet with the block in the right format
4187 std::ostringstream os(std::ios_base::binary);
4188 block->serialize(os, ver, false);
4189 block->serializeNetworkSpecific(os, net_proto_version);
4190 std::string s = os.str();
4191 SharedBuffer<u8> blockdata((u8*)s.c_str(), s.size());
4193 u32 replysize = 8 + blockdata.getSize();
4194 SharedBuffer<u8> reply(replysize);
4195 writeU16(&reply[0], TOCLIENT_BLOCKDATA);
4196 writeS16(&reply[2], p.X);
4197 writeS16(&reply[4], p.Y);
4198 writeS16(&reply[6], p.Z);
4199 memcpy(&reply[8], *blockdata, blockdata.getSize());
4201 /*infostream<<"Server: Sending block ("<<p.X<<","<<p.Y<<","<<p.Z<<")"
4202 <<": \tpacket size: "<<replysize<<std::endl;*/
4207 m_con.Send(peer_id, 1, reply, true);
4210 void Server::SendBlocks(float dtime)
4212 DSTACK(__FUNCTION_NAME);
4214 JMutexAutoLock envlock(m_env_mutex);
4215 JMutexAutoLock conlock(m_con_mutex);
4217 ScopeProfiler sp(g_profiler, "Server: sel and send blocks to clients");
4219 std::vector<PrioritySortedBlockTransfer> queue;
4221 s32 total_sending = 0;
4224 ScopeProfiler sp(g_profiler, "Server: selecting blocks for sending");
4226 for(std::map<u16, RemoteClient*>::iterator
4227 i = m_clients.begin();
4228 i != m_clients.end(); ++i)
4230 RemoteClient *client = i->second;
4231 assert(client->peer_id == i->first);
4233 // If definitions and textures have not been sent, don't
4234 // send MapBlocks either
4235 if(!client->definitions_sent)
4238 total_sending += client->SendingCount();
4240 if(client->serialization_version == SER_FMT_VER_INVALID)
4243 client->GetNextBlocks(this, dtime, queue);
4248 // Lowest priority number comes first.
4249 // Lowest is most important.
4250 std::sort(queue.begin(), queue.end());
4252 for(u32 i=0; i<queue.size(); i++)
4254 //TODO: Calculate limit dynamically
4255 if(total_sending >= g_settings->getS32
4256 ("max_simultaneous_block_sends_server_total"))
4259 PrioritySortedBlockTransfer q = queue[i];
4261 MapBlock *block = NULL;
4264 block = m_env->getMap().getBlockNoCreate(q.pos);
4266 catch(InvalidPositionException &e)
4271 RemoteClient *client = getClientNoEx(q.peer_id);
4277 SendBlockNoLock(q.peer_id, block, client->serialization_version, client->net_proto_version);
4279 client->SentBlock(q.pos);
4285 void Server::fillMediaCache()
4287 DSTACK(__FUNCTION_NAME);
4289 infostream<<"Server: Calculating media file checksums"<<std::endl;
4291 // Collect all media file paths
4292 std::list<std::string> paths;
4293 for(std::vector<ModSpec>::iterator i = m_mods.begin();
4294 i != m_mods.end(); i++){
4295 const ModSpec &mod = *i;
4296 paths.push_back(mod.path + DIR_DELIM + "textures");
4297 paths.push_back(mod.path + DIR_DELIM + "sounds");
4298 paths.push_back(mod.path + DIR_DELIM + "media");
4299 paths.push_back(mod.path + DIR_DELIM + "models");
4301 paths.push_back(porting::path_user + DIR_DELIM + "textures" + DIR_DELIM + "server");
4303 // Collect media file information from paths into cache
4304 for(std::list<std::string>::iterator i = paths.begin();
4305 i != paths.end(); i++)
4307 std::string mediapath = *i;
4308 std::vector<fs::DirListNode> dirlist = fs::GetDirListing(mediapath);
4309 for(u32 j=0; j<dirlist.size(); j++){
4310 if(dirlist[j].dir) // Ignode dirs
4312 std::string filename = dirlist[j].name;
4313 // If name contains illegal characters, ignore the file
4314 if(!string_allowed(filename, TEXTURENAME_ALLOWED_CHARS)){
4315 infostream<<"Server: ignoring illegal file name: \""
4316 <<filename<<"\""<<std::endl;
4319 // If name is not in a supported format, ignore it
4320 const char *supported_ext[] = {
4321 ".png", ".jpg", ".bmp", ".tga",
4322 ".pcx", ".ppm", ".psd", ".wal", ".rgb",
4324 ".x", ".b3d", ".md2", ".obj",
4327 if(removeStringEnd(filename, supported_ext) == ""){
4328 infostream<<"Server: ignoring unsupported file extension: \""
4329 <<filename<<"\""<<std::endl;
4332 // Ok, attempt to load the file and add to cache
4333 std::string filepath = mediapath + DIR_DELIM + filename;
4335 std::ifstream fis(filepath.c_str(), std::ios_base::binary);
4336 if(fis.good() == false){
4337 errorstream<<"Server::fillMediaCache(): Could not open \""
4338 <<filename<<"\" for reading"<<std::endl;
4341 std::ostringstream tmp_os(std::ios_base::binary);
4345 fis.read(buf, 1024);
4346 std::streamsize len = fis.gcount();
4347 tmp_os.write(buf, len);
4356 errorstream<<"Server::fillMediaCache(): Failed to read \""
4357 <<filename<<"\""<<std::endl;
4360 if(tmp_os.str().length() == 0){
4361 errorstream<<"Server::fillMediaCache(): Empty file \""
4362 <<filepath<<"\""<<std::endl;
4367 sha1.addBytes(tmp_os.str().c_str(), tmp_os.str().length());
4369 unsigned char *digest = sha1.getDigest();
4370 std::string sha1_base64 = base64_encode(digest, 20);
4371 std::string sha1_hex = hex_encode((char*)digest, 20);
4375 this->m_media[filename] = MediaInfo(filepath, sha1_base64);
4376 verbosestream<<"Server: "<<sha1_hex<<" is "<<filename<<std::endl;
4381 struct SendableMediaAnnouncement
4384 std::string sha1_digest;
4386 SendableMediaAnnouncement(const std::string name_="",
4387 const std::string sha1_digest_=""):
4389 sha1_digest(sha1_digest_)
4393 void Server::sendMediaAnnouncement(u16 peer_id)
4395 DSTACK(__FUNCTION_NAME);
4397 verbosestream<<"Server: Announcing files to id("<<peer_id<<")"
4400 std::list<SendableMediaAnnouncement> file_announcements;
4402 for(std::map<std::string, MediaInfo>::iterator i = m_media.begin();
4403 i != m_media.end(); i++){
4405 file_announcements.push_back(
4406 SendableMediaAnnouncement(i->first, i->second.sha1_digest));
4410 std::ostringstream os(std::ios_base::binary);
4418 u16 length of sha1_digest
4423 writeU16(os, TOCLIENT_ANNOUNCE_MEDIA);
4424 writeU16(os, file_announcements.size());
4426 for(std::list<SendableMediaAnnouncement>::iterator
4427 j = file_announcements.begin();
4428 j != file_announcements.end(); ++j){
4429 os<<serializeString(j->name);
4430 os<<serializeString(j->sha1_digest);
4432 os<<serializeString(g_settings->get("remote_media"));
4435 std::string s = os.str();
4436 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
4439 m_con.Send(peer_id, 0, data, true);
4442 struct SendableMedia
4448 SendableMedia(const std::string &name_="", const std::string path_="",
4449 const std::string &data_=""):
4456 void Server::sendRequestedMedia(u16 peer_id,
4457 const std::list<std::string> &tosend)
4459 DSTACK(__FUNCTION_NAME);
4461 verbosestream<<"Server::sendRequestedMedia(): "
4462 <<"Sending files to client"<<std::endl;
4466 // Put 5kB in one bunch (this is not accurate)
4467 u32 bytes_per_bunch = 5000;
4469 std::vector< std::list<SendableMedia> > file_bunches;
4470 file_bunches.push_back(std::list<SendableMedia>());
4472 u32 file_size_bunch_total = 0;
4474 for(std::list<std::string>::const_iterator i = tosend.begin();
4475 i != tosend.end(); ++i)
4477 const std::string &name = *i;
4479 if(m_media.find(name) == m_media.end()){
4480 errorstream<<"Server::sendRequestedMedia(): Client asked for "
4481 <<"unknown file \""<<(name)<<"\""<<std::endl;
4485 //TODO get path + name
4486 std::string tpath = m_media[name].path;
4489 std::ifstream fis(tpath.c_str(), std::ios_base::binary);
4490 if(fis.good() == false){
4491 errorstream<<"Server::sendRequestedMedia(): Could not open \""
4492 <<tpath<<"\" for reading"<<std::endl;
4495 std::ostringstream tmp_os(std::ios_base::binary);
4499 fis.read(buf, 1024);
4500 std::streamsize len = fis.gcount();
4501 tmp_os.write(buf, len);
4502 file_size_bunch_total += len;
4511 errorstream<<"Server::sendRequestedMedia(): Failed to read \""
4512 <<name<<"\""<<std::endl;
4515 /*infostream<<"Server::sendRequestedMedia(): Loaded \""
4516 <<tname<<"\""<<std::endl;*/
4518 file_bunches[file_bunches.size()-1].push_back(
4519 SendableMedia(name, tpath, tmp_os.str()));
4521 // Start next bunch if got enough data
4522 if(file_size_bunch_total >= bytes_per_bunch){
4523 file_bunches.push_back(std::list<SendableMedia>());
4524 file_size_bunch_total = 0;
4529 /* Create and send packets */
4531 u32 num_bunches = file_bunches.size();
4532 for(u32 i=0; i<num_bunches; i++)
4534 std::ostringstream os(std::ios_base::binary);
4538 u16 total number of texture bunches
4539 u16 index of this bunch
4540 u32 number of files in this bunch
4549 writeU16(os, TOCLIENT_MEDIA);
4550 writeU16(os, num_bunches);
4552 writeU32(os, file_bunches[i].size());
4554 for(std::list<SendableMedia>::iterator
4555 j = file_bunches[i].begin();
4556 j != file_bunches[i].end(); ++j){
4557 os<<serializeString(j->name);
4558 os<<serializeLongString(j->data);
4562 std::string s = os.str();
4563 verbosestream<<"Server::sendRequestedMedia(): bunch "
4564 <<i<<"/"<<num_bunches
4565 <<" files="<<file_bunches[i].size()
4566 <<" size=" <<s.size()<<std::endl;
4567 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
4569 m_con.Send(peer_id, 0, data, true);
4573 void Server::sendDetachedInventory(const std::string &name, u16 peer_id)
4575 if(m_detached_inventories.count(name) == 0){
4576 errorstream<<__FUNCTION_NAME<<": \""<<name<<"\" not found"<<std::endl;
4579 Inventory *inv = m_detached_inventories[name];
4581 std::ostringstream os(std::ios_base::binary);
4582 writeU16(os, TOCLIENT_DETACHED_INVENTORY);
4583 os<<serializeString(name);
4587 std::string s = os.str();
4588 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
4590 m_con.Send(peer_id, 0, data, true);
4593 void Server::sendDetachedInventoryToAll(const std::string &name)
4595 DSTACK(__FUNCTION_NAME);
4597 for(std::map<u16, RemoteClient*>::iterator
4598 i = m_clients.begin();
4599 i != m_clients.end(); ++i){
4600 RemoteClient *client = i->second;
4601 sendDetachedInventory(name, client->peer_id);
4605 void Server::sendDetachedInventories(u16 peer_id)
4607 DSTACK(__FUNCTION_NAME);
4609 for(std::map<std::string, Inventory*>::iterator
4610 i = m_detached_inventories.begin();
4611 i != m_detached_inventories.end(); i++){
4612 const std::string &name = i->first;
4613 //Inventory *inv = i->second;
4614 sendDetachedInventory(name, peer_id);
4622 void Server::DiePlayer(u16 peer_id)
4624 DSTACK(__FUNCTION_NAME);
4626 PlayerSAO *playersao = getPlayerSAO(peer_id);
4629 infostream<<"Server::DiePlayer(): Player "
4630 <<playersao->getPlayer()->getName()
4631 <<" dies"<<std::endl;
4633 playersao->setHP(0);
4635 // Trigger scripted stuff
4636 m_script->on_dieplayer(playersao);
4638 SendPlayerHP(peer_id);
4639 SendDeathscreen(m_con, peer_id, false, v3f(0,0,0));
4642 void Server::RespawnPlayer(u16 peer_id)
4644 DSTACK(__FUNCTION_NAME);
4646 PlayerSAO *playersao = getPlayerSAO(peer_id);
4649 infostream<<"Server::RespawnPlayer(): Player "
4650 <<playersao->getPlayer()->getName()
4651 <<" respawns"<<std::endl;
4653 playersao->setHP(PLAYER_MAX_HP);
4655 bool repositioned = m_script->on_respawnplayer(playersao);
4657 v3f pos = findSpawnPos(m_env->getServerMap());
4658 playersao->setPos(pos);
4662 void Server::DenyAccess(u16 peer_id, const std::wstring &reason)
4664 DSTACK(__FUNCTION_NAME);
4666 SendAccessDenied(m_con, peer_id, reason);
4668 RemoteClient *client = getClientNoEx(peer_id);
4670 client->denied = true;
4672 // If there are way too many clients, get rid of denied new ones immediately
4673 if((int)m_clients.size() > 2 * g_settings->getU16("max_users")){
4674 verbosestream<<"Server: DenyAccess: Too many clients; getting rid of "
4675 <<"peer_id="<<peer_id<<" immediately"<<std::endl;
4676 // Delete peer to stop sending it data
4677 m_con.DeletePeer(peer_id);
4678 // Delete client also to stop block sends and other stuff
4679 DeleteClient(peer_id, CDR_DENY);
4683 void Server::DeleteClient(u16 peer_id, ClientDeletionReason reason)
4685 DSTACK(__FUNCTION_NAME);
4688 std::map<u16, RemoteClient*>::iterator n;
4689 n = m_clients.find(peer_id);
4690 // The client may not exist; clients are immediately removed if their
4691 // access is denied, and this event occurs later then.
4692 if(n == m_clients.end())
4696 Mark objects to be not known by the client
4698 RemoteClient *client = n->second;
4700 for(std::set<u16>::iterator
4701 i = client->m_known_objects.begin();
4702 i != client->m_known_objects.end(); ++i)
4706 ServerActiveObject* obj = m_env->getActiveObject(id);
4708 if(obj && obj->m_known_by_count > 0)
4709 obj->m_known_by_count--;
4713 Clear references to playing sounds
4715 for(std::map<s32, ServerPlayingSound>::iterator
4716 i = m_playing_sounds.begin();
4717 i != m_playing_sounds.end();)
4719 ServerPlayingSound &psound = i->second;
4720 psound.clients.erase(peer_id);
4721 if(psound.clients.size() == 0)
4722 m_playing_sounds.erase(i++);
4727 Player *player = m_env->getPlayer(peer_id);
4729 // Collect information about leaving in chat
4730 std::wstring message;
4732 if(player != NULL && reason != CDR_DENY)
4734 std::wstring name = narrow_to_wide(player->getName());
4737 message += L" left the game.";
4738 if(reason == CDR_TIMEOUT)
4739 message += L" (timed out)";
4743 /* Run scripts and remove from environment */
4747 PlayerSAO *playersao = player->getPlayerSAO();
4750 m_script->on_leaveplayer(playersao);
4752 playersao->disconnected();
4760 if(player != NULL && reason != CDR_DENY)
4762 std::ostringstream os(std::ios_base::binary);
4763 for(std::map<u16, RemoteClient*>::iterator
4764 i = m_clients.begin();
4765 i != m_clients.end(); ++i)
4767 RemoteClient *client = i->second;
4768 assert(client->peer_id == i->first);
4769 if(client->serialization_version == SER_FMT_VER_INVALID)
4772 Player *player = m_env->getPlayer(client->peer_id);
4775 // Get name of player
4776 os<<player->getName()<<" ";
4779 actionstream<<player->getName()<<" "
4780 <<(reason==CDR_TIMEOUT?"times out.":"leaves game.")
4781 <<" List of players: "<<os.str()<<std::endl;
4786 delete m_clients[peer_id];
4787 m_clients.erase(peer_id);
4789 // Send leave chat message to all remaining clients
4790 if(message.length() != 0)
4791 BroadcastChatMessage(message);
4794 void Server::UpdateCrafting(u16 peer_id)
4796 DSTACK(__FUNCTION_NAME);
4798 Player* player = m_env->getPlayer(peer_id);
4801 // Get a preview for crafting
4803 InventoryLocation loc;
4804 loc.setPlayer(player->getName());
4805 getCraftingResult(&player->inventory, preview, false, this);
4806 m_env->getScriptIface()->item_CraftPredict(preview, player->getPlayerSAO(), (&player->inventory)->getList("craft"), loc);
4808 // Put the new preview in
4809 InventoryList *plist = player->inventory.getList("craftpreview");
4811 assert(plist->getSize() >= 1);
4812 plist->changeItem(0, preview);
4815 RemoteClient* Server::getClient(u16 peer_id)
4817 RemoteClient *client = getClientNoEx(peer_id);
4819 throw ClientNotFoundException("Client not found");
4822 RemoteClient* Server::getClientNoEx(u16 peer_id)
4824 std::map<u16, RemoteClient*>::iterator n;
4825 n = m_clients.find(peer_id);
4826 // The client may not exist; clients are immediately removed if their
4827 // access is denied, and this event occurs later then.
4828 if(n == m_clients.end())
4833 std::string Server::getPlayerName(u16 peer_id)
4835 Player *player = m_env->getPlayer(peer_id);
4837 return "[id="+itos(peer_id)+"]";
4838 return player->getName();
4841 PlayerSAO* Server::getPlayerSAO(u16 peer_id)
4843 Player *player = m_env->getPlayer(peer_id);
4846 return player->getPlayerSAO();
4849 std::wstring Server::getStatusString()
4851 std::wostringstream os(std::ios_base::binary);
4854 os<<L"version="<<narrow_to_wide(minetest_version_simple);
4856 os<<L", uptime="<<m_uptime.get();
4858 os<<L", max_lag="<<m_env->getMaxLagEstimate();
4859 // Information about clients
4860 std::map<u16, RemoteClient*>::iterator i;
4863 for(i = m_clients.begin(), first = true;
4864 i != m_clients.end(); ++i)
4866 // Get client and check that it is valid
4867 RemoteClient *client = i->second;
4868 assert(client->peer_id == i->first);
4869 if(client->serialization_version == SER_FMT_VER_INVALID)
4872 Player *player = m_env->getPlayer(client->peer_id);
4873 // Get name of player
4874 std::wstring name = L"unknown";
4876 name = narrow_to_wide(player->getName());
4877 // Add name to information string
4885 if(((ServerMap*)(&m_env->getMap()))->isSavingEnabled() == false)
4886 os<<std::endl<<L"# Server: "<<" WARNING: Map saving is disabled.";
4887 if(g_settings->get("motd") != "")
4888 os<<std::endl<<L"# Server: "<<narrow_to_wide(g_settings->get("motd"));
4892 std::set<std::string> Server::getPlayerEffectivePrivs(const std::string &name)
4894 std::set<std::string> privs;
4895 m_script->getAuth(name, NULL, &privs);
4899 bool Server::checkPriv(const std::string &name, const std::string &priv)
4901 std::set<std::string> privs = getPlayerEffectivePrivs(name);
4902 return (privs.count(priv) != 0);
4905 void Server::reportPrivsModified(const std::string &name)
4908 for(std::map<u16, RemoteClient*>::iterator
4909 i = m_clients.begin();
4910 i != m_clients.end(); ++i){
4911 RemoteClient *client = i->second;
4912 Player *player = m_env->getPlayer(client->peer_id);
4913 reportPrivsModified(player->getName());
4916 Player *player = m_env->getPlayer(name.c_str());
4919 SendPlayerPrivileges(player->peer_id);
4920 PlayerSAO *sao = player->getPlayerSAO();
4923 sao->updatePrivileges(
4924 getPlayerEffectivePrivs(name),
4929 void Server::reportInventoryFormspecModified(const std::string &name)
4931 Player *player = m_env->getPlayer(name.c_str());
4934 SendPlayerInventoryFormspec(player->peer_id);
4937 void Server::setIpBanned(const std::string &ip, const std::string &name)
4939 m_banmanager->add(ip, name);
4942 void Server::unsetIpBanned(const std::string &ip_or_name)
4944 m_banmanager->remove(ip_or_name);
4947 std::string Server::getBanDescription(const std::string &ip_or_name)
4949 return m_banmanager->getBanDescription(ip_or_name);
4952 void Server::notifyPlayer(const char *name, const std::wstring msg, const bool prepend = true)
4954 Player *player = m_env->getPlayer(name);
4958 SendChatMessage(player->peer_id, std::wstring(L"Server -!- ")+msg);
4960 SendChatMessage(player->peer_id, msg);
4963 bool Server::showFormspec(const char *playername, const std::string &formspec, const std::string &formname)
4965 Player *player = m_env->getPlayer(playername);
4969 infostream<<"showFormspec: couldn't find player:"<<playername<<std::endl;
4973 SendShowFormspecMessage(player->peer_id, formspec, formname);
4977 u32 Server::hudAdd(Player *player, HudElement *form) {
4981 u32 id = player->getFreeHudID();
4982 if (id < player->hud.size())
4983 player->hud[id] = form;
4985 player->hud.push_back(form);
4987 SendHUDAdd(player->peer_id, id, form);
4991 bool Server::hudRemove(Player *player, u32 id) {
4992 if (!player || id >= player->hud.size() || !player->hud[id])
4995 delete player->hud[id];
4996 player->hud[id] = NULL;
4998 SendHUDRemove(player->peer_id, id);
5002 bool Server::hudChange(Player *player, u32 id, HudElementStat stat, void *data) {
5006 SendHUDChange(player->peer_id, id, stat, data);
5010 bool Server::hudSetFlags(Player *player, u32 flags, u32 mask) {
5014 SendHUDSetFlags(player->peer_id, flags, mask);
5018 bool Server::hudSetHotbarItemcount(Player *player, s32 hotbar_itemcount) {
5021 if (hotbar_itemcount <= 0 || hotbar_itemcount > HUD_HOTBAR_ITEMCOUNT_MAX)
5024 std::ostringstream os(std::ios::binary);
5025 writeS32(os, hotbar_itemcount);
5026 SendHUDSetParam(player->peer_id, HUD_PARAM_HOTBAR_ITEMCOUNT, os.str());
5030 void Server::hudSetHotbarImage(Player *player, std::string name) {
5034 SendHUDSetParam(player->peer_id, HUD_PARAM_HOTBAR_IMAGE, name);
5037 void Server::hudSetHotbarSelectedImage(Player *player, std::string name) {
5041 SendHUDSetParam(player->peer_id, HUD_PARAM_HOTBAR_SELECTED_IMAGE, name);
5044 void Server::notifyPlayers(const std::wstring msg)
5046 BroadcastChatMessage(msg);
5049 void Server::spawnParticle(const char *playername, v3f pos,
5050 v3f velocity, v3f acceleration,
5051 float expirationtime, float size, bool
5052 collisiondetection, std::string texture)
5054 Player *player = m_env->getPlayer(playername);
5057 SendSpawnParticle(player->peer_id, pos, velocity, acceleration,
5058 expirationtime, size, collisiondetection, texture);
5061 void Server::spawnParticleAll(v3f pos, v3f velocity, v3f acceleration,
5062 float expirationtime, float size,
5063 bool collisiondetection, std::string texture)
5065 SendSpawnParticleAll(pos, velocity, acceleration,
5066 expirationtime, size, collisiondetection, texture);
5069 u32 Server::addParticleSpawner(const char *playername,
5070 u16 amount, float spawntime,
5071 v3f minpos, v3f maxpos,
5072 v3f minvel, v3f maxvel,
5073 v3f minacc, v3f maxacc,
5074 float minexptime, float maxexptime,
5075 float minsize, float maxsize,
5076 bool collisiondetection, std::string texture)
5078 Player *player = m_env->getPlayer(playername);
5083 for(;;) // look for unused particlespawner id
5086 if (std::find(m_particlespawner_ids.begin(),
5087 m_particlespawner_ids.end(), id)
5088 == m_particlespawner_ids.end())
5090 m_particlespawner_ids.push_back(id);
5095 SendAddParticleSpawner(player->peer_id, amount, spawntime,
5096 minpos, maxpos, minvel, maxvel, minacc, maxacc,
5097 minexptime, maxexptime, minsize, maxsize,
5098 collisiondetection, texture, id);
5103 u32 Server::addParticleSpawnerAll(u16 amount, float spawntime,
5104 v3f minpos, v3f maxpos,
5105 v3f minvel, v3f maxvel,
5106 v3f minacc, v3f maxacc,
5107 float minexptime, float maxexptime,
5108 float minsize, float maxsize,
5109 bool collisiondetection, std::string texture)
5112 for(;;) // look for unused particlespawner id
5115 if (std::find(m_particlespawner_ids.begin(),
5116 m_particlespawner_ids.end(), id)
5117 == m_particlespawner_ids.end())
5119 m_particlespawner_ids.push_back(id);
5124 SendAddParticleSpawnerAll(amount, spawntime,
5125 minpos, maxpos, minvel, maxvel, minacc, maxacc,
5126 minexptime, maxexptime, minsize, maxsize,
5127 collisiondetection, texture, id);
5132 void Server::deleteParticleSpawner(const char *playername, u32 id)
5134 Player *player = m_env->getPlayer(playername);
5138 m_particlespawner_ids.erase(
5139 std::remove(m_particlespawner_ids.begin(),
5140 m_particlespawner_ids.end(), id),
5141 m_particlespawner_ids.end());
5142 SendDeleteParticleSpawner(player->peer_id, id);
5145 void Server::deleteParticleSpawnerAll(u32 id)
5147 m_particlespawner_ids.erase(
5148 std::remove(m_particlespawner_ids.begin(),
5149 m_particlespawner_ids.end(), id),
5150 m_particlespawner_ids.end());
5151 SendDeleteParticleSpawnerAll(id);
5154 Inventory* Server::createDetachedInventory(const std::string &name)
5156 if(m_detached_inventories.count(name) > 0){
5157 infostream<<"Server clearing detached inventory \""<<name<<"\""<<std::endl;
5158 delete m_detached_inventories[name];
5160 infostream<<"Server creating detached inventory \""<<name<<"\""<<std::endl;
5162 Inventory *inv = new Inventory(m_itemdef);
5164 m_detached_inventories[name] = inv;
5165 sendDetachedInventoryToAll(name);
5172 BoolScopeSet(bool *dst, bool val):
5175 m_orig_state = *m_dst;
5180 *m_dst = m_orig_state;
5187 // actions: time-reversed list
5188 // Return value: success/failure
5189 bool Server::rollbackRevertActions(const std::list<RollbackAction> &actions,
5190 std::list<std::string> *log)
5192 infostream<<"Server::rollbackRevertActions(len="<<actions.size()<<")"<<std::endl;
5193 ServerMap *map = (ServerMap*)(&m_env->getMap());
5194 // Disable rollback report sink while reverting
5195 BoolScopeSet rollback_scope_disable(&m_rollback_sink_enabled, false);
5197 // Fail if no actions to handle
5198 if(actions.empty()){
5199 log->push_back("Nothing to do.");
5206 for(std::list<RollbackAction>::const_iterator
5207 i = actions.begin();
5208 i != actions.end(); i++)
5210 const RollbackAction &action = *i;
5212 bool success = action.applyRevert(map, this, this);
5215 std::ostringstream os;
5216 os<<"Revert of step ("<<num_tried<<") "<<action.toString()<<" failed";
5217 infostream<<"Map::rollbackRevertActions(): "<<os.str()<<std::endl;
5219 log->push_back(os.str());
5221 std::ostringstream os;
5222 os<<"Successfully reverted step ("<<num_tried<<") "<<action.toString();
5223 infostream<<"Map::rollbackRevertActions(): "<<os.str()<<std::endl;
5225 log->push_back(os.str());
5229 infostream<<"Map::rollbackRevertActions(): "<<num_failed<<"/"<<num_tried
5230 <<" failed"<<std::endl;
5232 // Call it done if less than half failed
5233 return num_failed <= num_tried/2;
5236 // IGameDef interface
5238 IItemDefManager* Server::getItemDefManager()
5242 INodeDefManager* Server::getNodeDefManager()
5246 ICraftDefManager* Server::getCraftDefManager()
5250 ITextureSource* Server::getTextureSource()
5254 IShaderSource* Server::getShaderSource()
5258 u16 Server::allocateUnknownNodeId(const std::string &name)
5260 return m_nodedef->allocateDummy(name);
5262 ISoundManager* Server::getSoundManager()
5264 return &dummySoundManager;
5266 MtEventManager* Server::getEventManager()
5270 IRollbackReportSink* Server::getRollbackReportSink()
5272 if(!m_enable_rollback_recording)
5274 if(!m_rollback_sink_enabled)
5279 IWritableItemDefManager* Server::getWritableItemDefManager()
5283 IWritableNodeDefManager* Server::getWritableNodeDefManager()
5287 IWritableCraftDefManager* Server::getWritableCraftDefManager()
5292 const ModSpec* Server::getModSpec(const std::string &modname)
5294 for(std::vector<ModSpec>::iterator i = m_mods.begin();
5295 i != m_mods.end(); i++){
5296 const ModSpec &mod = *i;
5297 if(mod.name == modname)
5302 void Server::getModNames(std::list<std::string> &modlist)
5304 for(std::vector<ModSpec>::iterator i = m_mods.begin(); i != m_mods.end(); i++)
5306 modlist.push_back(i->name);
5309 std::string Server::getBuiltinLuaPath()
5311 return porting::path_share + DIR_DELIM + "builtin";
5314 v3f findSpawnPos(ServerMap &map)
5316 //return v3f(50,50,50)*BS;
5321 nodepos = v2s16(0,0);
5326 s16 water_level = map.m_mgparams->water_level;
5328 // Try to find a good place a few times
5329 for(s32 i=0; i<1000; i++)
5332 // We're going to try to throw the player to this position
5333 v2s16 nodepos2d = v2s16(
5334 -range + (myrand() % (range * 2)),
5335 -range + (myrand() % (range * 2)));
5337 // Get ground height at point
5338 s16 groundheight = map.findGroundLevel(nodepos2d);
5339 if (groundheight <= water_level) // Don't go underwater
5341 if (groundheight > water_level + 6) // Don't go to high places
5344 nodepos = v3s16(nodepos2d.X, groundheight, nodepos2d.Y);
5345 bool is_good = false;
5347 for (s32 i = 0; i < 10; i++) {
5348 v3s16 blockpos = getNodeBlockPos(nodepos);
5349 map.emergeBlock(blockpos, true);
5350 content_t c = map.getNodeNoEx(nodepos).getContent();
5351 if (c == CONTENT_AIR || c == CONTENT_IGNORE) {
5353 if (air_count >= 2){
5361 // Found a good place
5362 //infostream<<"Searched through "<<i<<" places."<<std::endl;
5368 return intToFloat(nodepos, BS);
5371 PlayerSAO* Server::emergePlayer(const char *name, u16 peer_id)
5373 RemotePlayer *player = NULL;
5374 bool newplayer = false;
5377 Try to get an existing player
5379 player = static_cast<RemotePlayer*>(m_env->getPlayer(name));
5381 // If player is already connected, cancel
5382 if(player != NULL && player->peer_id != 0)
5384 infostream<<"emergePlayer(): Player already connected"<<std::endl;
5389 If player with the wanted peer_id already exists, cancel.
5391 if(m_env->getPlayer(peer_id) != NULL)
5393 infostream<<"emergePlayer(): Player with wrong name but same"
5394 " peer_id already exists"<<std::endl;
5399 Create a new player if it doesn't exist yet
5404 player = new RemotePlayer(this);
5405 player->updateName(name);
5407 /* Set player position */
5408 infostream<<"Server: Finding spawn place for player \""
5409 <<name<<"\""<<std::endl;
5410 v3f pos = findSpawnPos(m_env->getServerMap());
5411 player->setPosition(pos);
5413 /* Add player to environment */
5414 m_env->addPlayer(player);
5418 Create a new player active object
5420 PlayerSAO *playersao = new PlayerSAO(m_env, player, peer_id,
5421 getPlayerEffectivePrivs(player->getName()),
5424 /* Clean up old HUD elements from previous sessions */
5425 player->hud.clear();
5427 /* Add object to environment */
5428 m_env->addActiveObject(playersao);
5432 m_script->on_newplayer(playersao);
5434 m_script->on_joinplayer(playersao);
5439 void Server::handlePeerChange(PeerChange &c)
5441 JMutexAutoLock envlock(m_env_mutex);
5442 JMutexAutoLock conlock(m_con_mutex);
5444 if(c.type == PEER_ADDED)
5451 std::map<u16, RemoteClient*>::iterator n;
5452 n = m_clients.find(c.peer_id);
5453 // The client shouldn't already exist
5454 assert(n == m_clients.end());
5457 RemoteClient *client = new RemoteClient();
5458 client->peer_id = c.peer_id;
5459 m_clients[client->peer_id] = client;
5462 else if(c.type == PEER_REMOVED)
5468 DeleteClient(c.peer_id, c.timeout?CDR_TIMEOUT:CDR_LEAVE);
5477 void Server::handlePeerChanges()
5479 while(m_peer_change_queue.size() > 0)
5481 PeerChange c = m_peer_change_queue.pop_front();
5483 verbosestream<<"Server: Handling peer change: "
5484 <<"id="<<c.peer_id<<", timeout="<<c.timeout
5487 handlePeerChange(c);
5491 void dedicated_server_loop(Server &server, bool &kill)
5493 DSTACK(__FUNCTION_NAME);
5495 verbosestream<<"dedicated_server_loop()"<<std::endl;
5497 IntervalLimiter m_profiler_interval;
5501 float steplen = g_settings->getFloat("dedicated_server_step");
5502 // This is kind of a hack but can be done like this
5503 // because server.step() is very light
5505 ScopeProfiler sp(g_profiler, "dedicated server sleep");
5506 sleep_ms((int)(steplen*1000.0));
5508 server.step(steplen);
5510 if(server.getShutdownRequested() || kill)
5512 infostream<<"Dedicated server quitting"<<std::endl;
5514 if(g_settings->getBool("server_announce") == true)
5515 ServerList::sendAnnounce("delete");
5523 float profiler_print_interval =
5524 g_settings->getFloat("profiler_print_interval");
5525 if(profiler_print_interval != 0)
5527 if(m_profiler_interval.step(steplen, profiler_print_interval))
5529 infostream<<"Profiler:"<<std::endl;
5530 g_profiler->print(infostream);
5531 g_profiler->clear();