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 SimpleThread
82 ServerThread(Server *server):
91 void * ServerThread::Thread()
95 log_register_thread("ServerThread");
97 DSTACK(__FUNCTION_NAME);
99 BEGIN_DEBUG_EXCEPTION_HANDLER
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;
680 throw ServerError("Supplied empty world path");
682 if(!gamespec.isValid())
683 throw ServerError("Supplied invalid gamespec");
685 infostream<<"Server created for gameid \""<<m_gamespec.id<<"\"";
686 if(m_simple_singleplayer_mode)
687 infostream<<" in simple singleplayer mode"<<std::endl;
689 infostream<<std::endl;
690 infostream<<"- world: "<<m_path_world<<std::endl;
691 infostream<<"- game: "<<m_gamespec.path<<std::endl;
693 // Initialize default settings and override defaults with those provided
695 set_default_settings(g_settings);
696 Settings gamedefaults;
697 getGameMinetestConfig(gamespec.path, gamedefaults);
698 override_default_settings(g_settings, &gamedefaults);
700 // Create server thread
701 m_thread = new ServerThread(this);
703 // Create emerge manager
704 m_emerge = new EmergeManager(this);
706 // Create ban manager
707 std::string ban_path = m_path_world+DIR_DELIM+"ipban.txt";
708 m_banmanager = new BanManager(ban_path);
710 // Create rollback manager
711 std::string rollback_path = m_path_world+DIR_DELIM+"rollback.txt";
712 m_rollback = createRollbackManager(rollback_path, this);
714 // Create world if it doesn't exist
715 if(!initializeWorld(m_path_world, m_gamespec.id))
716 throw ServerError("Failed to initialize world");
718 ModConfiguration modconf(m_path_world);
719 m_mods = modconf.getMods();
720 std::vector<ModSpec> unsatisfied_mods = modconf.getUnsatisfiedMods();
721 // complain about mods with unsatisfied dependencies
722 if(!modconf.isConsistent())
724 for(std::vector<ModSpec>::iterator it = unsatisfied_mods.begin();
725 it != unsatisfied_mods.end(); ++it)
728 errorstream << "mod \"" << mod.name << "\" has unsatisfied dependencies: ";
729 for(std::set<std::string>::iterator dep_it = mod.unsatisfied_depends.begin();
730 dep_it != mod.unsatisfied_depends.end(); ++dep_it)
731 errorstream << " \"" << *dep_it << "\"";
732 errorstream << std::endl;
736 Settings worldmt_settings;
737 std::string worldmt = m_path_world + DIR_DELIM + "world.mt";
738 worldmt_settings.readConfigFile(worldmt.c_str());
739 std::vector<std::string> names = worldmt_settings.getNames();
740 std::set<std::string> load_mod_names;
741 for(std::vector<std::string>::iterator it = names.begin();
742 it != names.end(); ++it)
744 std::string name = *it;
745 if(name.compare(0,9,"load_mod_")==0 && worldmt_settings.getBool(name))
746 load_mod_names.insert(name.substr(9));
748 // complain about mods declared to be loaded, but not found
749 for(std::vector<ModSpec>::iterator it = m_mods.begin();
750 it != m_mods.end(); ++it)
751 load_mod_names.erase((*it).name);
752 for(std::vector<ModSpec>::iterator it = unsatisfied_mods.begin();
753 it != unsatisfied_mods.end(); ++it)
754 load_mod_names.erase((*it).name);
755 if(!load_mod_names.empty())
757 errorstream << "The following mods could not be found:";
758 for(std::set<std::string>::iterator it = load_mod_names.begin();
759 it != load_mod_names.end(); ++it)
760 errorstream << " \"" << (*it) << "\"";
761 errorstream << std::endl;
764 // Path to builtin.lua
765 std::string builtinpath = getBuiltinLuaPath() + DIR_DELIM + "builtin.lua";
768 JMutexAutoLock envlock(m_env_mutex);
769 JMutexAutoLock conlock(m_con_mutex);
771 // Initialize scripting
773 infostream<<"Server: Initializing Lua"<<std::endl;
775 m_script = new GameScripting(this);
778 // Load and run builtin.lua
779 infostream<<"Server: Loading builtin.lua [\""
780 <<builtinpath<<"\"]"<<std::endl;
781 bool success = m_script->loadMod(builtinpath, "__builtin");
783 errorstream<<"Server: Failed to load and run "
784 <<builtinpath<<std::endl;
785 throw ModError("Failed to load and run "+builtinpath);
788 infostream<<"Server: Loading mods: ";
789 for(std::vector<ModSpec>::iterator i = m_mods.begin();
790 i != m_mods.end(); i++){
791 const ModSpec &mod = *i;
792 infostream<<mod.name<<" ";
794 infostream<<std::endl;
795 // Load and run "mod" scripts
796 for(std::vector<ModSpec>::iterator i = m_mods.begin();
797 i != m_mods.end(); i++){
798 const ModSpec &mod = *i;
799 std::string scriptpath = mod.path + DIR_DELIM + "init.lua";
800 infostream<<" ["<<padStringRight(mod.name, 12)<<"] [\""
801 <<scriptpath<<"\"]"<<std::endl;
802 bool success = m_script->loadMod(scriptpath, mod.name);
804 errorstream<<"Server: Failed to load and run "
805 <<scriptpath<<std::endl;
806 throw ModError("Failed to load and run "+scriptpath);
810 // Read Textures and calculate sha1 sums
813 // Apply item aliases in the node definition manager
814 m_nodedef->updateAliases(m_itemdef);
816 // Initialize Environment
817 ServerMap *servermap = new ServerMap(path_world, this, m_emerge);
818 m_env = new ServerEnvironment(servermap, m_script, this, m_emerge);
820 // Run some callbacks after the MG params have been set up but before activation
821 MapgenParams *mgparams = servermap->getMapgenParams();
822 m_script->environment_OnMapgenInit(mgparams);
824 // Initialize mapgens
825 m_emerge->initMapgens(mgparams);
827 // Give environment reference to scripting api
828 m_script->initializeEnvironment(m_env);
830 // Register us to receive map edit events
831 servermap->addEventReceiver(this);
833 // If file exists, load environment metadata
834 if(fs::PathExists(m_path_world+DIR_DELIM+"env_meta.txt"))
836 infostream<<"Server: Loading environment metadata"<<std::endl;
837 m_env->loadMeta(m_path_world);
841 infostream<<"Server: Loading players"<<std::endl;
842 m_env->deSerializePlayers(m_path_world);
845 Add some test ActiveBlockModifiers to environment
847 add_legacy_abms(m_env, m_nodedef);
849 m_liquid_transform_every = g_settings->getFloat("liquid_update");
854 infostream<<"Server destructing"<<std::endl;
857 Send shutdown message
860 JMutexAutoLock conlock(m_con_mutex);
862 std::wstring line = L"*** Server shutting down";
865 Send the message to clients
867 for(std::map<u16, RemoteClient*>::iterator
868 i = m_clients.begin();
869 i != m_clients.end(); ++i)
871 // Get client and check that it is valid
872 RemoteClient *client = i->second;
873 assert(client->peer_id == i->first);
874 if(client->serialization_version == SER_FMT_VER_INVALID)
878 SendChatMessage(client->peer_id, line);
880 catch(con::PeerNotFoundException &e)
886 JMutexAutoLock envlock(m_env_mutex);
887 JMutexAutoLock conlock(m_con_mutex);
890 Execute script shutdown hooks
892 m_script->on_shutdown();
896 JMutexAutoLock envlock(m_env_mutex);
901 infostream<<"Server: Saving players"<<std::endl;
902 m_env->serializePlayers(m_path_world);
905 Save environment metadata
907 infostream<<"Server: Saving environment metadata"<<std::endl;
908 m_env->saveMeta(m_path_world);
917 //shutdown all emerge threads first!
924 JMutexAutoLock clientslock(m_con_mutex);
926 for(std::map<u16, RemoteClient*>::iterator
927 i = m_clients.begin();
928 i != m_clients.end(); ++i)
936 // Delete things in the reverse order of creation
945 // Deinitialize scripting
946 infostream<<"Server: Deinitializing scripting"<<std::endl;
949 // Delete detached inventories
951 for(std::map<std::string, Inventory*>::iterator
952 i = m_detached_inventories.begin();
953 i != m_detached_inventories.end(); i++){
959 void Server::start(unsigned short port)
961 DSTACK(__FUNCTION_NAME);
962 infostream<<"Starting server on port "<<port<<"..."<<std::endl;
964 // Stop thread if already running
967 // Initialize connection
968 m_con.SetTimeoutMs(30);
972 m_thread->setRun(true);
975 // ASCII art for the win!
977 <<" .__ __ __ "<<std::endl
978 <<" _____ |__| ____ _____/ |_ ____ _______/ |_ "<<std::endl
979 <<" / \\| |/ \\_/ __ \\ __\\/ __ \\ / ___/\\ __\\"<<std::endl
980 <<"| Y Y \\ | | \\ ___/| | \\ ___/ \\___ \\ | | "<<std::endl
981 <<"|__|_| /__|___| /\\___ >__| \\___ >____ > |__| "<<std::endl
982 <<" \\/ \\/ \\/ \\/ \\/ "<<std::endl;
983 actionstream<<"World at ["<<m_path_world<<"]"<<std::endl;
984 actionstream<<"Server for gameid=\""<<m_gamespec.id
985 <<"\" listening on port "<<port<<"."<<std::endl;
990 DSTACK(__FUNCTION_NAME);
992 infostream<<"Server: Stopping and waiting threads"<<std::endl;
994 // Stop threads (set run=false first so both start stopping)
995 m_thread->setRun(false);
996 //m_emergethread.setRun(false);
998 //m_emergethread.stop();
1000 infostream<<"Server: Threads stopped"<<std::endl;
1003 void Server::step(float dtime)
1005 DSTACK(__FUNCTION_NAME);
1010 JMutexAutoLock lock(m_step_dtime_mutex);
1011 m_step_dtime += dtime;
1013 // Throw if fatal error occurred in thread
1014 std::string async_err = m_async_fatal_error.get();
1015 if(async_err != ""){
1016 throw ServerError(async_err);
1020 void Server::AsyncRunStep()
1022 DSTACK(__FUNCTION_NAME);
1024 g_profiler->add("Server::AsyncRunStep (num)", 1);
1028 JMutexAutoLock lock1(m_step_dtime_mutex);
1029 dtime = m_step_dtime;
1033 // Send blocks to clients
1040 g_profiler->add("Server::AsyncRunStep with dtime (num)", 1);
1042 //infostream<<"Server steps "<<dtime<<std::endl;
1043 //infostream<<"Server::AsyncRunStep(): dtime="<<dtime<<std::endl;
1046 JMutexAutoLock lock1(m_step_dtime_mutex);
1047 m_step_dtime -= dtime;
1054 m_uptime.set(m_uptime.get() + dtime);
1058 // Process connection's timeouts
1059 JMutexAutoLock lock2(m_con_mutex);
1060 ScopeProfiler sp(g_profiler, "Server: connection timeout processing");
1061 m_con.RunTimeouts(dtime);
1065 // This has to be called so that the client list gets synced
1066 // with the peer list of the connection
1067 handlePeerChanges();
1071 Update time of day and overall game time
1074 JMutexAutoLock envlock(m_env_mutex);
1076 m_env->setTimeOfDaySpeed(g_settings->getFloat("time_speed"));
1079 Send to clients at constant intervals
1082 m_time_of_day_send_timer -= dtime;
1083 if(m_time_of_day_send_timer < 0.0)
1085 m_time_of_day_send_timer = g_settings->getFloat("time_send_interval");
1087 //JMutexAutoLock envlock(m_env_mutex);
1088 JMutexAutoLock conlock(m_con_mutex);
1090 u16 time = m_env->getTimeOfDay();
1091 float time_speed = g_settings->getFloat("time_speed");
1093 for(std::map<u16, RemoteClient*>::iterator
1094 i = m_clients.begin();
1095 i != m_clients.end(); ++i)
1097 RemoteClient *client = i->second;
1098 SendTimeOfDay(client->peer_id, time, time_speed);
1104 JMutexAutoLock lock(m_env_mutex);
1105 // Figure out and report maximum lag to environment
1106 float max_lag = m_env->getMaxLagEstimate();
1107 max_lag *= 0.9998; // Decrease slowly (about half per 5 minutes)
1108 if(dtime > max_lag){
1109 if(dtime > 0.1 && dtime > max_lag * 2.0)
1110 infostream<<"Server: Maximum lag peaked to "<<dtime
1114 m_env->reportMaxLagEstimate(max_lag);
1116 ScopeProfiler sp(g_profiler, "SEnv step");
1117 ScopeProfiler sp2(g_profiler, "SEnv step avg", SPT_AVG);
1121 const float map_timer_and_unload_dtime = 2.92;
1122 if(m_map_timer_and_unload_interval.step(dtime, map_timer_and_unload_dtime))
1124 JMutexAutoLock lock(m_env_mutex);
1125 // Run Map's timers and unload unused data
1126 ScopeProfiler sp(g_profiler, "Server: map timer and unload");
1127 m_env->getMap().timerUpdate(map_timer_and_unload_dtime,
1128 g_settings->getFloat("server_unload_unused_data_timeout"));
1139 JMutexAutoLock lock(m_env_mutex);
1140 JMutexAutoLock lock2(m_con_mutex);
1142 ScopeProfiler sp(g_profiler, "Server: handle players");
1144 for(std::map<u16, RemoteClient*>::iterator
1145 i = m_clients.begin();
1146 i != m_clients.end(); ++i)
1148 RemoteClient *client = i->second;
1149 PlayerSAO *playersao = getPlayerSAO(client->peer_id);
1150 if(playersao == NULL)
1154 Handle player HPs (die if hp=0)
1156 if(playersao->m_hp_not_sent && g_settings->getBool("enable_damage"))
1158 if(playersao->getHP() == 0)
1159 DiePlayer(client->peer_id);
1161 SendPlayerHP(client->peer_id);
1165 Send player breath if changed
1167 if(playersao->m_breath_not_sent){
1168 SendPlayerBreath(client->peer_id);
1172 Send player inventories if necessary
1174 if(playersao->m_moved){
1175 SendMovePlayer(client->peer_id);
1176 playersao->m_moved = false;
1178 if(playersao->m_inventory_not_sent){
1179 UpdateCrafting(client->peer_id);
1180 SendInventory(client->peer_id);
1185 /* Transform liquids */
1186 m_liquid_transform_timer += dtime;
1187 if(m_liquid_transform_timer >= m_liquid_transform_every)
1189 m_liquid_transform_timer -= m_liquid_transform_every;
1191 JMutexAutoLock lock(m_env_mutex);
1193 ScopeProfiler sp(g_profiler, "Server: liquid transform");
1195 std::map<v3s16, MapBlock*> modified_blocks;
1196 m_env->getMap().transformLiquids(modified_blocks);
1201 core::map<v3s16, MapBlock*> lighting_modified_blocks;
1202 ServerMap &map = ((ServerMap&)m_env->getMap());
1203 map.updateLighting(modified_blocks, lighting_modified_blocks);
1205 // Add blocks modified by lighting to modified_blocks
1206 for(core::map<v3s16, MapBlock*>::Iterator
1207 i = lighting_modified_blocks.getIterator();
1208 i.atEnd() == false; i++)
1210 MapBlock *block = i.getNode()->getValue();
1211 modified_blocks.insert(block->getPos(), block);
1215 Set the modified blocks unsent for all the clients
1218 JMutexAutoLock lock2(m_con_mutex);
1220 for(std::map<u16, RemoteClient*>::iterator
1221 i = m_clients.begin();
1222 i != m_clients.end(); ++i)
1224 RemoteClient *client = i->second;
1226 if(modified_blocks.size() > 0)
1228 // Remove block from sent history
1229 client->SetBlocksNotSent(modified_blocks);
1234 // Periodically print some info
1236 float &counter = m_print_info_timer;
1242 JMutexAutoLock lock2(m_con_mutex);
1243 m_clients_names.clear();
1244 if(m_clients.size() != 0)
1245 infostream<<"Players:"<<std::endl;
1246 for(std::map<u16, RemoteClient*>::iterator
1247 i = m_clients.begin();
1248 i != m_clients.end(); ++i)
1250 //u16 peer_id = i.getNode()->getKey();
1251 RemoteClient *client = i->second;
1252 Player *player = m_env->getPlayer(client->peer_id);
1255 infostream<<"* "<<player->getName()<<"\t";
1256 client->PrintInfo(infostream);
1257 m_clients_names.push_back(player->getName());
1264 // send masterserver announce
1266 float &counter = m_masterserver_timer;
1267 if(!isSingleplayer() && (!counter || counter >= 300.0) && g_settings->getBool("server_announce") == true)
1269 ServerList::sendAnnounce(!counter ? "start" : "update", m_clients_names, m_uptime.get(), m_env->getGameTime(), m_gamespec.id, m_mods);
1276 //if(g_settings->getBool("enable_experimental"))
1280 Check added and deleted active objects
1283 //infostream<<"Server: Checking added and deleted active objects"<<std::endl;
1284 JMutexAutoLock envlock(m_env_mutex);
1285 JMutexAutoLock conlock(m_con_mutex);
1287 ScopeProfiler sp(g_profiler, "Server: checking added and deleted objs");
1289 // Radius inside which objects are active
1290 s16 radius = g_settings->getS16("active_object_send_range_blocks");
1291 radius *= MAP_BLOCKSIZE;
1293 for(std::map<u16, RemoteClient*>::iterator
1294 i = m_clients.begin();
1295 i != m_clients.end(); ++i)
1297 RemoteClient *client = i->second;
1299 // If definitions and textures have not been sent, don't
1300 // send objects either
1301 if(!client->definitions_sent)
1304 Player *player = m_env->getPlayer(client->peer_id);
1307 // This can happen if the client timeouts somehow
1308 /*infostream<<"WARNING: "<<__FUNCTION_NAME<<": Client "
1310 <<" has no associated player"<<std::endl;*/
1313 v3s16 pos = floatToInt(player->getPosition(), BS);
1315 std::set<u16> removed_objects;
1316 std::set<u16> added_objects;
1317 m_env->getRemovedActiveObjects(pos, radius,
1318 client->m_known_objects, removed_objects);
1319 m_env->getAddedActiveObjects(pos, radius,
1320 client->m_known_objects, added_objects);
1322 // Ignore if nothing happened
1323 if(removed_objects.size() == 0 && added_objects.size() == 0)
1325 //infostream<<"active objects: none changed"<<std::endl;
1329 std::string data_buffer;
1333 // Handle removed objects
1334 writeU16((u8*)buf, removed_objects.size());
1335 data_buffer.append(buf, 2);
1336 for(std::set<u16>::iterator
1337 i = removed_objects.begin();
1338 i != removed_objects.end(); ++i)
1342 ServerActiveObject* obj = m_env->getActiveObject(id);
1344 // Add to data buffer for sending
1345 writeU16((u8*)buf, id);
1346 data_buffer.append(buf, 2);
1348 // Remove from known objects
1349 client->m_known_objects.erase(id);
1351 if(obj && obj->m_known_by_count > 0)
1352 obj->m_known_by_count--;
1355 // Handle added objects
1356 writeU16((u8*)buf, added_objects.size());
1357 data_buffer.append(buf, 2);
1358 for(std::set<u16>::iterator
1359 i = added_objects.begin();
1360 i != added_objects.end(); ++i)
1364 ServerActiveObject* obj = m_env->getActiveObject(id);
1367 u8 type = ACTIVEOBJECT_TYPE_INVALID;
1369 infostream<<"WARNING: "<<__FUNCTION_NAME
1370 <<": NULL object"<<std::endl;
1372 type = obj->getSendType();
1374 // Add to data buffer for sending
1375 writeU16((u8*)buf, id);
1376 data_buffer.append(buf, 2);
1377 writeU8((u8*)buf, type);
1378 data_buffer.append(buf, 1);
1381 data_buffer.append(serializeLongString(
1382 obj->getClientInitializationData(client->net_proto_version)));
1384 data_buffer.append(serializeLongString(""));
1386 // Add to known objects
1387 client->m_known_objects.insert(id);
1390 obj->m_known_by_count++;
1394 SharedBuffer<u8> reply(2 + data_buffer.size());
1395 writeU16(&reply[0], TOCLIENT_ACTIVE_OBJECT_REMOVE_ADD);
1396 memcpy((char*)&reply[2], data_buffer.c_str(),
1397 data_buffer.size());
1399 m_con.Send(client->peer_id, 0, reply, true);
1401 verbosestream<<"Server: Sent object remove/add: "
1402 <<removed_objects.size()<<" removed, "
1403 <<added_objects.size()<<" added, "
1404 <<"packet size is "<<reply.getSize()<<std::endl;
1409 Collect a list of all the objects known by the clients
1410 and report it back to the environment.
1413 core::map<u16, bool> all_known_objects;
1415 for(core::map<u16, RemoteClient*>::Iterator
1416 i = m_clients.getIterator();
1417 i.atEnd() == false; i++)
1419 RemoteClient *client = i.getNode()->getValue();
1420 // Go through all known objects of client
1421 for(core::map<u16, bool>::Iterator
1422 i = client->m_known_objects.getIterator();
1423 i.atEnd()==false; i++)
1425 u16 id = i.getNode()->getKey();
1426 all_known_objects[id] = true;
1430 m_env->setKnownActiveObjects(whatever);
1436 Send object messages
1439 JMutexAutoLock envlock(m_env_mutex);
1440 JMutexAutoLock conlock(m_con_mutex);
1442 ScopeProfiler sp(g_profiler, "Server: sending object messages");
1445 // Value = data sent by object
1446 std::map<u16, std::list<ActiveObjectMessage>* > buffered_messages;
1448 // Get active object messages from environment
1451 ActiveObjectMessage aom = m_env->getActiveObjectMessage();
1455 std::list<ActiveObjectMessage>* message_list = NULL;
1456 std::map<u16, std::list<ActiveObjectMessage>* >::iterator n;
1457 n = buffered_messages.find(aom.id);
1458 if(n == buffered_messages.end())
1460 message_list = new std::list<ActiveObjectMessage>;
1461 buffered_messages[aom.id] = message_list;
1465 message_list = n->second;
1467 message_list->push_back(aom);
1470 // Route data to every client
1471 for(std::map<u16, RemoteClient*>::iterator
1472 i = m_clients.begin();
1473 i != m_clients.end(); ++i)
1475 RemoteClient *client = i->second;
1476 std::string reliable_data;
1477 std::string unreliable_data;
1478 // Go through all objects in message buffer
1479 for(std::map<u16, std::list<ActiveObjectMessage>* >::iterator
1480 j = buffered_messages.begin();
1481 j != buffered_messages.end(); ++j)
1483 // If object is not known by client, skip it
1485 if(client->m_known_objects.find(id) == client->m_known_objects.end())
1487 // Get message list of object
1488 std::list<ActiveObjectMessage>* list = j->second;
1489 // Go through every message
1490 for(std::list<ActiveObjectMessage>::iterator
1491 k = list->begin(); k != list->end(); ++k)
1493 // Compose the full new data with header
1494 ActiveObjectMessage aom = *k;
1495 std::string new_data;
1498 writeU16((u8*)&buf[0], aom.id);
1499 new_data.append(buf, 2);
1501 new_data += serializeString(aom.datastring);
1502 // Add data to buffer
1504 reliable_data += new_data;
1506 unreliable_data += new_data;
1510 reliable_data and unreliable_data are now ready.
1513 if(reliable_data.size() > 0)
1515 SharedBuffer<u8> reply(2 + reliable_data.size());
1516 writeU16(&reply[0], TOCLIENT_ACTIVE_OBJECT_MESSAGES);
1517 memcpy((char*)&reply[2], reliable_data.c_str(),
1518 reliable_data.size());
1520 m_con.Send(client->peer_id, 0, reply, true);
1522 if(unreliable_data.size() > 0)
1524 SharedBuffer<u8> reply(2 + unreliable_data.size());
1525 writeU16(&reply[0], TOCLIENT_ACTIVE_OBJECT_MESSAGES);
1526 memcpy((char*)&reply[2], unreliable_data.c_str(),
1527 unreliable_data.size());
1528 // Send as unreliable
1529 m_con.Send(client->peer_id, 0, reply, false);
1532 /*if(reliable_data.size() > 0 || unreliable_data.size() > 0)
1534 infostream<<"Server: Size of object message data: "
1535 <<"reliable: "<<reliable_data.size()
1536 <<", unreliable: "<<unreliable_data.size()
1541 // Clear buffered_messages
1542 for(std::map<u16, std::list<ActiveObjectMessage>* >::iterator
1543 i = buffered_messages.begin();
1544 i != buffered_messages.end(); ++i)
1550 } // enable_experimental
1553 Send queued-for-sending map edit events.
1556 // We will be accessing the environment and the connection
1557 JMutexAutoLock lock(m_env_mutex);
1558 JMutexAutoLock conlock(m_con_mutex);
1560 // Don't send too many at a time
1563 // Single change sending is disabled if queue size is not small
1564 bool disable_single_change_sending = false;
1565 if(m_unsent_map_edit_queue.size() >= 4)
1566 disable_single_change_sending = true;
1568 int event_count = m_unsent_map_edit_queue.size();
1570 // We'll log the amount of each
1573 while(m_unsent_map_edit_queue.size() != 0)
1575 MapEditEvent* event = m_unsent_map_edit_queue.pop_front();
1577 // Players far away from the change are stored here.
1578 // Instead of sending the changes, MapBlocks are set not sent
1580 std::list<u16> far_players;
1582 if(event->type == MEET_ADDNODE || event->type == MEET_SWAPNODE)
1584 //infostream<<"Server: MEET_ADDNODE"<<std::endl;
1585 prof.add("MEET_ADDNODE", 1);
1586 if(disable_single_change_sending)
1587 sendAddNode(event->p, event->n, event->already_known_by_peer,
1588 &far_players, 5, event->type == MEET_ADDNODE);
1590 sendAddNode(event->p, event->n, event->already_known_by_peer,
1591 &far_players, 30, event->type == MEET_ADDNODE);
1593 else if(event->type == MEET_REMOVENODE)
1595 //infostream<<"Server: MEET_REMOVENODE"<<std::endl;
1596 prof.add("MEET_REMOVENODE", 1);
1597 if(disable_single_change_sending)
1598 sendRemoveNode(event->p, event->already_known_by_peer,
1601 sendRemoveNode(event->p, event->already_known_by_peer,
1604 else if(event->type == MEET_BLOCK_NODE_METADATA_CHANGED)
1606 infostream<<"Server: MEET_BLOCK_NODE_METADATA_CHANGED"<<std::endl;
1607 prof.add("MEET_BLOCK_NODE_METADATA_CHANGED", 1);
1608 setBlockNotSent(event->p);
1610 else if(event->type == MEET_OTHER)
1612 infostream<<"Server: MEET_OTHER"<<std::endl;
1613 prof.add("MEET_OTHER", 1);
1614 for(std::set<v3s16>::iterator
1615 i = event->modified_blocks.begin();
1616 i != event->modified_blocks.end(); ++i)
1618 setBlockNotSent(*i);
1623 prof.add("unknown", 1);
1624 infostream<<"WARNING: Server: Unknown MapEditEvent "
1625 <<((u32)event->type)<<std::endl;
1629 Set blocks not sent to far players
1631 if(far_players.size() > 0)
1633 // Convert list format to that wanted by SetBlocksNotSent
1634 std::map<v3s16, MapBlock*> modified_blocks2;
1635 for(std::set<v3s16>::iterator
1636 i = event->modified_blocks.begin();
1637 i != event->modified_blocks.end(); ++i)
1639 modified_blocks2[*i] =
1640 m_env->getMap().getBlockNoCreateNoEx(*i);
1642 // Set blocks not sent
1643 for(std::list<u16>::iterator
1644 i = far_players.begin();
1645 i != far_players.end(); ++i)
1648 RemoteClient *client = getClient(peer_id);
1651 client->SetBlocksNotSent(modified_blocks2);
1657 /*// Don't send too many at a time
1659 if(count >= 1 && m_unsent_map_edit_queue.size() < 100)
1663 if(event_count >= 5){
1664 infostream<<"Server: MapEditEvents:"<<std::endl;
1665 prof.print(infostream);
1666 } else if(event_count != 0){
1667 verbosestream<<"Server: MapEditEvents:"<<std::endl;
1668 prof.print(verbosestream);
1674 Trigger emergethread (it somehow gets to a non-triggered but
1675 bysy state sometimes)
1678 float &counter = m_emergethread_trigger_timer;
1684 m_emerge->triggerAllThreads();
1686 // Update m_enable_rollback_recording here too
1687 m_enable_rollback_recording =
1688 g_settings->getBool("enable_rollback_recording");
1692 // Save map, players and auth stuff
1694 float &counter = m_savemap_timer;
1696 if(counter >= g_settings->getFloat("server_map_save_interval"))
1699 JMutexAutoLock lock(m_env_mutex);
1701 ScopeProfiler sp(g_profiler, "Server: saving stuff");
1704 if(m_banmanager->isModified())
1705 m_banmanager->save();
1707 // Save changed parts of map
1708 m_env->getMap().save(MOD_STATE_WRITE_NEEDED);
1711 m_env->serializePlayers(m_path_world);
1713 // Save environment metadata
1714 m_env->saveMeta(m_path_world);
1719 void Server::Receive()
1721 DSTACK(__FUNCTION_NAME);
1722 SharedBuffer<u8> data;
1727 JMutexAutoLock conlock(m_con_mutex);
1728 datasize = m_con.Receive(peer_id, data);
1731 // This has to be called so that the client list gets synced
1732 // with the peer list of the connection
1733 handlePeerChanges();
1735 ProcessData(*data, datasize, peer_id);
1737 catch(con::InvalidIncomingDataException &e)
1739 infostream<<"Server::Receive(): "
1740 "InvalidIncomingDataException: what()="
1741 <<e.what()<<std::endl;
1743 catch(con::PeerNotFoundException &e)
1745 //NOTE: This is not needed anymore
1747 // The peer has been disconnected.
1748 // Find the associated player and remove it.
1750 /*JMutexAutoLock envlock(m_env_mutex);
1752 infostream<<"ServerThread: peer_id="<<peer_id
1753 <<" has apparently closed connection. "
1754 <<"Removing player."<<std::endl;
1756 m_env->removePlayer(peer_id);*/
1760 void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
1762 DSTACK(__FUNCTION_NAME);
1763 // Environment is locked first.
1764 JMutexAutoLock envlock(m_env_mutex);
1765 JMutexAutoLock conlock(m_con_mutex);
1767 ScopeProfiler sp(g_profiler, "Server::ProcessData");
1771 Address address = m_con.GetPeerAddress(peer_id);
1772 addr_s = address.serializeString();
1774 // drop player if is ip is banned
1775 if(m_banmanager->isIpBanned(addr_s)){
1776 std::string ban_name = m_banmanager->getBanName(addr_s);
1777 infostream<<"Server: A banned client tried to connect from "
1778 <<addr_s<<"; banned name was "
1779 <<ban_name<<std::endl;
1780 // This actually doesn't seem to transfer to the client
1781 DenyAccess(peer_id, L"Your ip is banned. Banned name was "
1782 +narrow_to_wide(ban_name));
1783 m_con.DeletePeer(peer_id);
1787 catch(con::PeerNotFoundException &e)
1789 infostream<<"Server::ProcessData(): Cancelling: peer "
1790 <<peer_id<<" not found"<<std::endl;
1794 u8 peer_ser_ver = getClient(peer_id)->serialization_version;
1802 ToServerCommand command = (ToServerCommand)readU16(&data[0]);
1804 if(command == TOSERVER_INIT)
1806 // [0] u16 TOSERVER_INIT
1807 // [2] u8 SER_FMT_VER_HIGHEST_READ
1808 // [3] u8[20] player_name
1809 // [23] u8[28] password <--- can be sent without this, from old versions
1811 if(datasize < 2+1+PLAYERNAME_SIZE)
1814 // If net_proto_version is set, this client has already been handled
1815 if(getClient(peer_id)->net_proto_version != 0){
1816 verbosestream<<"Server: Ignoring multiple TOSERVER_INITs from "
1817 <<addr_s<<" (peer_id="<<peer_id<<")"<<std::endl;
1821 verbosestream<<"Server: Got TOSERVER_INIT from "<<addr_s<<" (peer_id="
1822 <<peer_id<<")"<<std::endl;
1824 // Do not allow multiple players in simple singleplayer mode.
1825 // This isn't a perfect way to do it, but will suffice for now.
1826 if(m_simple_singleplayer_mode && m_clients.size() > 1){
1827 infostream<<"Server: Not allowing another client ("<<addr_s
1828 <<") to connect in simple singleplayer mode"<<std::endl;
1829 DenyAccess(peer_id, L"Running in simple singleplayer mode.");
1833 // First byte after command is maximum supported
1834 // serialization version
1835 u8 client_max = data[2];
1836 u8 our_max = SER_FMT_VER_HIGHEST_READ;
1837 // Use the highest version supported by both
1838 u8 deployed = std::min(client_max, our_max);
1839 // If it's lower than the lowest supported, give up.
1840 if(deployed < SER_FMT_VER_LOWEST)
1841 deployed = SER_FMT_VER_INVALID;
1843 //peer->serialization_version = deployed;
1844 getClient(peer_id)->pending_serialization_version = deployed;
1846 if(deployed == SER_FMT_VER_INVALID)
1848 actionstream<<"Server: A mismatched client tried to connect from "
1849 <<addr_s<<std::endl;
1850 infostream<<"Server: Cannot negotiate serialization version with "
1851 <<addr_s<<std::endl;
1852 DenyAccess(peer_id, std::wstring(
1853 L"Your client's version is not supported.\n"
1854 L"Server version is ")
1855 + narrow_to_wide(minetest_version_simple) + L"."
1861 Read and check network protocol version
1864 u16 min_net_proto_version = 0;
1865 if(datasize >= 2+1+PLAYERNAME_SIZE+PASSWORD_SIZE+2)
1866 min_net_proto_version = readU16(&data[2+1+PLAYERNAME_SIZE+PASSWORD_SIZE]);
1868 // Use same version as minimum and maximum if maximum version field
1869 // doesn't exist (backwards compatibility)
1870 u16 max_net_proto_version = min_net_proto_version;
1871 if(datasize >= 2+1+PLAYERNAME_SIZE+PASSWORD_SIZE+2+2)
1872 max_net_proto_version = readU16(&data[2+1+PLAYERNAME_SIZE+PASSWORD_SIZE+2]);
1874 // Start with client's maximum version
1875 u16 net_proto_version = max_net_proto_version;
1877 // Figure out a working version if it is possible at all
1878 if(max_net_proto_version >= SERVER_PROTOCOL_VERSION_MIN ||
1879 min_net_proto_version <= SERVER_PROTOCOL_VERSION_MAX)
1881 // If maximum is larger than our maximum, go with our maximum
1882 if(max_net_proto_version > SERVER_PROTOCOL_VERSION_MAX)
1883 net_proto_version = SERVER_PROTOCOL_VERSION_MAX;
1884 // Else go with client's maximum
1886 net_proto_version = max_net_proto_version;
1889 verbosestream<<"Server: "<<addr_s<<": Protocol version: min: "
1890 <<min_net_proto_version<<", max: "<<max_net_proto_version
1891 <<", chosen: "<<net_proto_version<<std::endl;
1893 getClient(peer_id)->net_proto_version = net_proto_version;
1895 if(net_proto_version < SERVER_PROTOCOL_VERSION_MIN ||
1896 net_proto_version > SERVER_PROTOCOL_VERSION_MAX)
1898 actionstream<<"Server: A mismatched client tried to connect from "
1899 <<addr_s<<std::endl;
1900 DenyAccess(peer_id, std::wstring(
1901 L"Your client's version is not supported.\n"
1902 L"Server version is ")
1903 + narrow_to_wide(minetest_version_simple) + L",\n"
1904 + L"server's PROTOCOL_VERSION is "
1905 + narrow_to_wide(itos(SERVER_PROTOCOL_VERSION_MIN))
1907 + narrow_to_wide(itos(SERVER_PROTOCOL_VERSION_MAX))
1908 + L", client's PROTOCOL_VERSION is "
1909 + narrow_to_wide(itos(min_net_proto_version))
1911 + narrow_to_wide(itos(max_net_proto_version))
1916 if(g_settings->getBool("strict_protocol_version_checking"))
1918 if(net_proto_version != LATEST_PROTOCOL_VERSION)
1920 actionstream<<"Server: A mismatched (strict) client tried to "
1921 <<"connect from "<<addr_s<<std::endl;
1922 DenyAccess(peer_id, std::wstring(
1923 L"Your client's version is not supported.\n"
1924 L"Server version is ")
1925 + narrow_to_wide(minetest_version_simple) + L",\n"
1926 + L"server's PROTOCOL_VERSION (strict) is "
1927 + narrow_to_wide(itos(LATEST_PROTOCOL_VERSION))
1928 + L", client's PROTOCOL_VERSION is "
1929 + narrow_to_wide(itos(min_net_proto_version))
1931 + narrow_to_wide(itos(max_net_proto_version))
1942 char playername[PLAYERNAME_SIZE];
1943 for(u32 i=0; i<PLAYERNAME_SIZE-1; i++)
1945 playername[i] = data[3+i];
1947 playername[PLAYERNAME_SIZE-1] = 0;
1949 if(playername[0]=='\0')
1951 actionstream<<"Server: Player with an empty name "
1952 <<"tried to connect from "<<addr_s<<std::endl;
1953 DenyAccess(peer_id, L"Empty name");
1957 if(string_allowed(playername, PLAYERNAME_ALLOWED_CHARS)==false)
1959 actionstream<<"Server: Player with an invalid name "
1960 <<"tried to connect from "<<addr_s<<std::endl;
1961 DenyAccess(peer_id, L"Name contains unallowed characters");
1965 if(!isSingleplayer() && strcasecmp(playername, "singleplayer") == 0)
1967 actionstream<<"Server: Player with the name \"singleplayer\" "
1968 <<"tried to connect from "<<addr_s<<std::endl;
1969 DenyAccess(peer_id, L"Name is not allowed");
1973 infostream<<"Server: New connection: \""<<playername<<"\" from "
1974 <<addr_s<<" (peer_id="<<peer_id<<")"<<std::endl;
1977 char given_password[PASSWORD_SIZE];
1978 if(datasize < 2+1+PLAYERNAME_SIZE+PASSWORD_SIZE)
1980 // old version - assume blank password
1981 given_password[0] = 0;
1985 for(u32 i=0; i<PASSWORD_SIZE-1; i++)
1987 given_password[i] = data[23+i];
1989 given_password[PASSWORD_SIZE-1] = 0;
1992 if(!base64_is_valid(given_password)){
1993 actionstream<<"Server: "<<playername
1994 <<" supplied invalid password hash"<<std::endl;
1995 DenyAccess(peer_id, L"Invalid password hash");
1999 // Enforce user limit.
2000 // Don't enforce for users that have some admin right
2001 if(m_clients.size() >= g_settings->getU16("max_users") &&
2002 !checkPriv(playername, "server") &&
2003 !checkPriv(playername, "ban") &&
2004 !checkPriv(playername, "privs") &&
2005 !checkPriv(playername, "password") &&
2006 playername != g_settings->get("name"))
2008 actionstream<<"Server: "<<playername<<" tried to join, but there"
2009 <<" are already max_users="
2010 <<g_settings->getU16("max_users")<<" players."<<std::endl;
2011 DenyAccess(peer_id, L"Too many users.");
2015 std::string checkpwd; // Password hash to check against
2016 bool has_auth = m_script->getAuth(playername, &checkpwd, NULL);
2018 // If no authentication info exists for user, create it
2020 if(!isSingleplayer() &&
2021 g_settings->getBool("disallow_empty_password") &&
2022 std::string(given_password) == ""){
2023 actionstream<<"Server: "<<playername
2024 <<" supplied empty password"<<std::endl;
2025 DenyAccess(peer_id, L"Empty passwords are "
2026 L"disallowed. Set a password and try again.");
2029 std::wstring raw_default_password =
2030 narrow_to_wide(g_settings->get("default_password"));
2031 std::string initial_password =
2032 translatePassword(playername, raw_default_password);
2034 // If default_password is empty, allow any initial password
2035 if (raw_default_password.length() == 0)
2036 initial_password = given_password;
2038 m_script->createAuth(playername, initial_password);
2041 has_auth = m_script->getAuth(playername, &checkpwd, NULL);
2044 actionstream<<"Server: "<<playername<<" cannot be authenticated"
2045 <<" (auth handler does not work?)"<<std::endl;
2046 DenyAccess(peer_id, L"Not allowed to login");
2050 if(given_password != checkpwd){
2051 actionstream<<"Server: "<<playername<<" supplied wrong password"
2053 DenyAccess(peer_id, L"Wrong password");
2058 PlayerSAO *playersao = emergePlayer(playername, peer_id);
2060 // If failed, cancel
2061 if(playersao == NULL)
2063 RemotePlayer *player =
2064 static_cast<RemotePlayer*>(m_env->getPlayer(playername));
2065 if(player && player->peer_id != 0){
2066 errorstream<<"Server: "<<playername<<": Failed to emerge player"
2067 <<" (player allocated to an another client)"<<std::endl;
2068 DenyAccess(peer_id, L"Another client is connected with this "
2069 L"name. If your client closed unexpectedly, try again in "
2072 errorstream<<"Server: "<<playername<<": Failed to emerge player"
2074 DenyAccess(peer_id, L"Could not allocate player.");
2080 Answer with a TOCLIENT_INIT
2083 SharedBuffer<u8> reply(2+1+6+8+4);
2084 writeU16(&reply[0], TOCLIENT_INIT);
2085 writeU8(&reply[2], deployed);
2086 writeV3S16(&reply[2+1], floatToInt(playersao->getPlayer()->getPosition()+v3f(0,BS/2,0), BS));
2087 writeU64(&reply[2+1+6], m_env->getServerMap().getSeed());
2088 writeF1000(&reply[2+1+6+8], g_settings->getFloat("dedicated_server_step"));
2091 m_con.Send(peer_id, 0, reply, true);
2095 Send complete position information
2097 SendMovePlayer(peer_id);
2102 if(command == TOSERVER_INIT2)
2104 verbosestream<<"Server: Got TOSERVER_INIT2 from "
2105 <<peer_id<<std::endl;
2107 Player *player = m_env->getPlayer(peer_id);
2109 verbosestream<<"Server: TOSERVER_INIT2: "
2110 <<"Player not found; ignoring."<<std::endl;
2114 RemoteClient *client = getClient(peer_id);
2115 client->serialization_version =
2116 getClient(peer_id)->pending_serialization_version;
2119 Send some initialization data
2122 infostream<<"Server: Sending content to "
2123 <<getPlayerName(peer_id)<<std::endl;
2125 // Send player movement settings
2126 SendMovement(m_con, peer_id);
2128 // Send item definitions
2129 SendItemDef(m_con, peer_id, m_itemdef, client->net_proto_version);
2131 // Send node definitions
2132 SendNodeDef(m_con, peer_id, m_nodedef, client->net_proto_version);
2134 // Send media announcement
2135 sendMediaAnnouncement(peer_id);
2138 SendPlayerPrivileges(peer_id);
2140 // Send inventory formspec
2141 SendPlayerInventoryFormspec(peer_id);
2144 UpdateCrafting(peer_id);
2145 SendInventory(peer_id);
2148 if(g_settings->getBool("enable_damage"))
2149 SendPlayerHP(peer_id);
2152 SendPlayerBreath(peer_id);
2154 // Send detached inventories
2155 sendDetachedInventories(peer_id);
2157 // Show death screen if necessary
2159 SendDeathscreen(m_con, peer_id, false, v3f(0,0,0));
2163 u16 time = m_env->getTimeOfDay();
2164 float time_speed = g_settings->getFloat("time_speed");
2165 SendTimeOfDay(peer_id, time, time_speed);
2168 // Note things in chat if not in simple singleplayer mode
2169 if(!m_simple_singleplayer_mode)
2171 // Send information about server to player in chat
2172 SendChatMessage(peer_id, getStatusString());
2174 // Send information about joining in chat
2176 std::wstring name = L"unknown";
2177 Player *player = m_env->getPlayer(peer_id);
2179 name = narrow_to_wide(player->getName());
2181 std::wstring message;
2184 message += L" joined the game.";
2185 BroadcastChatMessage(message);
2189 // Warnings about protocol version can be issued here
2190 if(getClient(peer_id)->net_proto_version < LATEST_PROTOCOL_VERSION)
2192 SendChatMessage(peer_id, L"# Server: WARNING: YOUR CLIENT'S "
2193 L"VERSION MAY NOT BE FULLY COMPATIBLE WITH THIS SERVER!");
2200 std::ostringstream os(std::ios_base::binary);
2201 for(std::map<u16, RemoteClient*>::iterator
2202 i = m_clients.begin();
2203 i != m_clients.end(); ++i)
2205 RemoteClient *client = i->second;
2206 assert(client->peer_id == i->first);
2207 if(client->serialization_version == SER_FMT_VER_INVALID)
2210 Player *player = m_env->getPlayer(client->peer_id);
2213 // Get name of player
2214 os<<player->getName()<<" ";
2217 actionstream<<player->getName()<<" ["<<addr_s<<"] "<<"joins game. List of players: "
2218 <<os.str()<<std::endl;
2224 if(peer_ser_ver == SER_FMT_VER_INVALID)
2226 infostream<<"Server::ProcessData(): Cancelling: Peer"
2227 " serialization format invalid or not initialized."
2228 " Skipping incoming command="<<command<<std::endl;
2232 Player *player = m_env->getPlayer(peer_id);
2234 infostream<<"Server::ProcessData(): Cancelling: "
2235 "No player for peer_id="<<peer_id
2240 PlayerSAO *playersao = player->getPlayerSAO();
2241 if(playersao == NULL){
2242 infostream<<"Server::ProcessData(): Cancelling: "
2243 "No player object for peer_id="<<peer_id
2248 if(command == TOSERVER_PLAYERPOS)
2250 if(datasize < 2+12+12+4+4)
2254 v3s32 ps = readV3S32(&data[start+2]);
2255 v3s32 ss = readV3S32(&data[start+2+12]);
2256 f32 pitch = (f32)readS32(&data[2+12+12]) / 100.0;
2257 f32 yaw = (f32)readS32(&data[2+12+12+4]) / 100.0;
2259 if(datasize >= 2+12+12+4+4+4)
2260 keyPressed = (u32)readU32(&data[2+12+12+4+4]);
2261 v3f position((f32)ps.X/100., (f32)ps.Y/100., (f32)ps.Z/100.);
2262 v3f speed((f32)ss.X/100., (f32)ss.Y/100., (f32)ss.Z/100.);
2263 pitch = wrapDegrees(pitch);
2264 yaw = wrapDegrees(yaw);
2266 player->setPosition(position);
2267 player->setSpeed(speed);
2268 player->setPitch(pitch);
2269 player->setYaw(yaw);
2270 player->keyPressed=keyPressed;
2271 player->control.up = (bool)(keyPressed&1);
2272 player->control.down = (bool)(keyPressed&2);
2273 player->control.left = (bool)(keyPressed&4);
2274 player->control.right = (bool)(keyPressed&8);
2275 player->control.jump = (bool)(keyPressed&16);
2276 player->control.aux1 = (bool)(keyPressed&32);
2277 player->control.sneak = (bool)(keyPressed&64);
2278 player->control.LMB = (bool)(keyPressed&128);
2279 player->control.RMB = (bool)(keyPressed&256);
2281 bool cheated = playersao->checkMovementCheat();
2284 m_script->on_cheat(playersao, "moved_too_fast");
2287 /*infostream<<"Server::ProcessData(): Moved player "<<peer_id<<" to "
2288 <<"("<<position.X<<","<<position.Y<<","<<position.Z<<")"
2289 <<" pitch="<<pitch<<" yaw="<<yaw<<std::endl;*/
2291 else if(command == TOSERVER_GOTBLOCKS)
2304 u16 count = data[2];
2305 for(u16 i=0; i<count; i++)
2307 if((s16)datasize < 2+1+(i+1)*6)
2308 throw con::InvalidIncomingDataException
2309 ("GOTBLOCKS length is too short");
2310 v3s16 p = readV3S16(&data[2+1+i*6]);
2311 /*infostream<<"Server: GOTBLOCKS ("
2312 <<p.X<<","<<p.Y<<","<<p.Z<<")"<<std::endl;*/
2313 RemoteClient *client = getClient(peer_id);
2314 client->GotBlock(p);
2317 else if(command == TOSERVER_DELETEDBLOCKS)
2330 u16 count = data[2];
2331 for(u16 i=0; i<count; i++)
2333 if((s16)datasize < 2+1+(i+1)*6)
2334 throw con::InvalidIncomingDataException
2335 ("DELETEDBLOCKS length is too short");
2336 v3s16 p = readV3S16(&data[2+1+i*6]);
2337 /*infostream<<"Server: DELETEDBLOCKS ("
2338 <<p.X<<","<<p.Y<<","<<p.Z<<")"<<std::endl;*/
2339 RemoteClient *client = getClient(peer_id);
2340 client->SetBlockNotSent(p);
2343 else if(command == TOSERVER_CLICK_OBJECT)
2345 infostream<<"Server: CLICK_OBJECT not supported anymore"<<std::endl;
2348 else if(command == TOSERVER_CLICK_ACTIVEOBJECT)
2350 infostream<<"Server: CLICK_ACTIVEOBJECT not supported anymore"<<std::endl;
2353 else if(command == TOSERVER_GROUND_ACTION)
2355 infostream<<"Server: GROUND_ACTION not supported anymore"<<std::endl;
2359 else if(command == TOSERVER_RELEASE)
2361 infostream<<"Server: RELEASE not supported anymore"<<std::endl;
2364 else if(command == TOSERVER_SIGNTEXT)
2366 infostream<<"Server: SIGNTEXT not supported anymore"
2370 else if(command == TOSERVER_SIGNNODETEXT)
2372 infostream<<"Server: SIGNNODETEXT not supported anymore"
2376 else if(command == TOSERVER_INVENTORY_ACTION)
2378 // Strip command and create a stream
2379 std::string datastring((char*)&data[2], datasize-2);
2380 verbosestream<<"TOSERVER_INVENTORY_ACTION: data="<<datastring<<std::endl;
2381 std::istringstream is(datastring, std::ios_base::binary);
2383 InventoryAction *a = InventoryAction::deSerialize(is);
2386 infostream<<"TOSERVER_INVENTORY_ACTION: "
2387 <<"InventoryAction::deSerialize() returned NULL"
2392 // If something goes wrong, this player is to blame
2393 RollbackScopeActor rollback_scope(m_rollback,
2394 std::string("player:")+player->getName());
2397 Note: Always set inventory not sent, to repair cases
2398 where the client made a bad prediction.
2402 Handle restrictions and special cases of the move action
2404 if(a->getType() == IACTION_MOVE)
2406 IMoveAction *ma = (IMoveAction*)a;
2408 ma->from_inv.applyCurrentPlayer(player->getName());
2409 ma->to_inv.applyCurrentPlayer(player->getName());
2411 setInventoryModified(ma->from_inv);
2412 setInventoryModified(ma->to_inv);
2414 bool from_inv_is_current_player =
2415 (ma->from_inv.type == InventoryLocation::PLAYER) &&
2416 (ma->from_inv.name == player->getName());
2418 bool to_inv_is_current_player =
2419 (ma->to_inv.type == InventoryLocation::PLAYER) &&
2420 (ma->to_inv.name == player->getName());
2423 Disable moving items out of craftpreview
2425 if(ma->from_list == "craftpreview")
2427 infostream<<"Ignoring IMoveAction from "
2428 <<(ma->from_inv.dump())<<":"<<ma->from_list
2429 <<" to "<<(ma->to_inv.dump())<<":"<<ma->to_list
2430 <<" because src is "<<ma->from_list<<std::endl;
2436 Disable moving items into craftresult and craftpreview
2438 if(ma->to_list == "craftpreview" || ma->to_list == "craftresult")
2440 infostream<<"Ignoring IMoveAction from "
2441 <<(ma->from_inv.dump())<<":"<<ma->from_list
2442 <<" to "<<(ma->to_inv.dump())<<":"<<ma->to_list
2443 <<" because dst is "<<ma->to_list<<std::endl;
2448 // Disallow moving items in elsewhere than player's inventory
2449 // if not allowed to interact
2450 if(!checkPriv(player->getName(), "interact") &&
2451 (!from_inv_is_current_player ||
2452 !to_inv_is_current_player))
2454 infostream<<"Cannot move outside of player's inventory: "
2455 <<"No interact privilege"<<std::endl;
2461 Handle restrictions and special cases of the drop action
2463 else if(a->getType() == IACTION_DROP)
2465 IDropAction *da = (IDropAction*)a;
2467 da->from_inv.applyCurrentPlayer(player->getName());
2469 setInventoryModified(da->from_inv);
2472 Disable dropping items out of craftpreview
2474 if(da->from_list == "craftpreview")
2476 infostream<<"Ignoring IDropAction from "
2477 <<(da->from_inv.dump())<<":"<<da->from_list
2478 <<" because src is "<<da->from_list<<std::endl;
2483 // Disallow dropping items if not allowed to interact
2484 if(!checkPriv(player->getName(), "interact"))
2491 Handle restrictions and special cases of the craft action
2493 else if(a->getType() == IACTION_CRAFT)
2495 ICraftAction *ca = (ICraftAction*)a;
2497 ca->craft_inv.applyCurrentPlayer(player->getName());
2499 setInventoryModified(ca->craft_inv);
2501 //bool craft_inv_is_current_player =
2502 // (ca->craft_inv.type == InventoryLocation::PLAYER) &&
2503 // (ca->craft_inv.name == player->getName());
2505 // Disallow crafting if not allowed to interact
2506 if(!checkPriv(player->getName(), "interact"))
2508 infostream<<"Cannot craft: "
2509 <<"No interact privilege"<<std::endl;
2516 a->apply(this, playersao, this);
2520 else if(command == TOSERVER_CHAT_MESSAGE)
2528 std::string datastring((char*)&data[2], datasize-2);
2529 std::istringstream is(datastring, std::ios_base::binary);
2532 is.read((char*)buf, 2);
2533 u16 len = readU16(buf);
2535 std::wstring message;
2536 for(u16 i=0; i<len; i++)
2538 is.read((char*)buf, 2);
2539 message += (wchar_t)readU16(buf);
2542 // If something goes wrong, this player is to blame
2543 RollbackScopeActor rollback_scope(m_rollback,
2544 std::string("player:")+player->getName());
2546 // Get player name of this client
2547 std::wstring name = narrow_to_wide(player->getName());
2550 bool ate = m_script->on_chat_message(player->getName(),
2551 wide_to_narrow(message));
2552 // If script ate the message, don't proceed
2556 // Line to send to players
2558 // Whether to send to the player that sent the line
2559 bool send_to_sender = false;
2560 // Whether to send to other players
2561 bool send_to_others = false;
2563 // Commands are implemented in Lua, so only catch invalid
2564 // commands that were not "eaten" and send an error back
2565 if(message[0] == L'/')
2567 message = message.substr(1);
2568 send_to_sender = true;
2569 if(message.length() == 0)
2570 line += L"-!- Empty command";
2572 line += L"-!- Invalid command: " + str_split(message, L' ')[0];
2576 if(checkPriv(player->getName(), "shout")){
2581 send_to_others = true;
2583 line += L"-!- You don't have permission to shout.";
2584 send_to_sender = true;
2591 actionstream<<"CHAT: "<<wide_to_narrow(line)<<std::endl;
2594 Send the message to clients
2596 for(std::map<u16, RemoteClient*>::iterator
2597 i = m_clients.begin();
2598 i != m_clients.end(); ++i)
2600 // Get client and check that it is valid
2601 RemoteClient *client = i->second;
2602 assert(client->peer_id == i->first);
2603 if(client->serialization_version == SER_FMT_VER_INVALID)
2607 bool sender_selected = (peer_id == client->peer_id);
2608 if(sender_selected == true && send_to_sender == false)
2610 if(sender_selected == false && send_to_others == false)
2613 SendChatMessage(client->peer_id, line);
2617 else if(command == TOSERVER_DAMAGE)
2619 std::string datastring((char*)&data[2], datasize-2);
2620 std::istringstream is(datastring, std::ios_base::binary);
2621 u8 damage = readU8(is);
2623 if(g_settings->getBool("enable_damage"))
2625 actionstream<<player->getName()<<" damaged by "
2626 <<(int)damage<<" hp at "<<PP(player->getPosition()/BS)
2629 playersao->setHP(playersao->getHP() - damage);
2631 if(playersao->getHP() == 0 && playersao->m_hp_not_sent)
2634 if(playersao->m_hp_not_sent)
2635 SendPlayerHP(peer_id);
2638 else if(command == TOSERVER_BREATH)
2640 std::string datastring((char*)&data[2], datasize-2);
2641 std::istringstream is(datastring, std::ios_base::binary);
2642 u16 breath = readU16(is);
2643 playersao->setBreath(breath);
2645 else if(command == TOSERVER_PASSWORD)
2648 [0] u16 TOSERVER_PASSWORD
2649 [2] u8[28] old password
2650 [30] u8[28] new password
2653 if(datasize != 2+PASSWORD_SIZE*2)
2655 /*char password[PASSWORD_SIZE];
2656 for(u32 i=0; i<PASSWORD_SIZE-1; i++)
2657 password[i] = data[2+i];
2658 password[PASSWORD_SIZE-1] = 0;*/
2660 for(u32 i=0; i<PASSWORD_SIZE-1; i++)
2668 for(u32 i=0; i<PASSWORD_SIZE-1; i++)
2670 char c = data[2+PASSWORD_SIZE+i];
2676 if(!base64_is_valid(newpwd)){
2677 infostream<<"Server: "<<player->getName()<<" supplied invalid password hash"<<std::endl;
2678 // Wrong old password supplied!!
2679 SendChatMessage(peer_id, L"Invalid new password hash supplied. Password NOT changed.");
2683 infostream<<"Server: Client requests a password change from "
2684 <<"'"<<oldpwd<<"' to '"<<newpwd<<"'"<<std::endl;
2686 std::string playername = player->getName();
2688 std::string checkpwd;
2689 m_script->getAuth(playername, &checkpwd, NULL);
2691 if(oldpwd != checkpwd)
2693 infostream<<"Server: invalid old password"<<std::endl;
2694 // Wrong old password supplied!!
2695 SendChatMessage(peer_id, L"Invalid old password supplied. Password NOT changed.");
2699 bool success = m_script->setPassword(playername, newpwd);
2701 actionstream<<player->getName()<<" changes password"<<std::endl;
2702 SendChatMessage(peer_id, L"Password change successful.");
2704 actionstream<<player->getName()<<" tries to change password but "
2705 <<"it fails"<<std::endl;
2706 SendChatMessage(peer_id, L"Password change failed or inavailable.");
2709 else if(command == TOSERVER_PLAYERITEM)
2714 u16 item = readU16(&data[2]);
2715 playersao->setWieldIndex(item);
2717 else if(command == TOSERVER_RESPAWN)
2719 if(player->hp != 0 || !g_settings->getBool("enable_damage"))
2722 RespawnPlayer(peer_id);
2724 actionstream<<player->getName()<<" respawns at "
2725 <<PP(player->getPosition()/BS)<<std::endl;
2727 // ActiveObject is added to environment in AsyncRunStep after
2728 // the previous addition has been succesfully removed
2730 else if(command == TOSERVER_REQUEST_MEDIA) {
2731 std::string datastring((char*)&data[2], datasize-2);
2732 std::istringstream is(datastring, std::ios_base::binary);
2734 std::list<MediaRequest> tosend;
2735 u16 numfiles = readU16(is);
2737 infostream<<"Sending "<<numfiles<<" files to "
2738 <<getPlayerName(peer_id)<<std::endl;
2739 verbosestream<<"TOSERVER_REQUEST_MEDIA: "<<std::endl;
2741 for(int i = 0; i < numfiles; i++) {
2742 std::string name = deSerializeString(is);
2743 tosend.push_back(MediaRequest(name));
2744 verbosestream<<"TOSERVER_REQUEST_MEDIA: requested file "
2748 sendRequestedMedia(peer_id, tosend);
2750 // Now the client should know about everything
2751 // (definitions and files)
2752 getClient(peer_id)->definitions_sent = true;
2754 else if(command == TOSERVER_RECEIVED_MEDIA) {
2755 getClient(peer_id)->definitions_sent = true;
2757 else if(command == TOSERVER_INTERACT)
2759 std::string datastring((char*)&data[2], datasize-2);
2760 std::istringstream is(datastring, std::ios_base::binary);
2766 [5] u32 length of the next item
2767 [9] serialized PointedThing
2769 0: start digging (from undersurface) or use
2770 1: stop digging (all parameters ignored)
2771 2: digging completed
2772 3: place block or item (to abovesurface)
2775 u8 action = readU8(is);
2776 u16 item_i = readU16(is);
2777 std::istringstream tmp_is(deSerializeLongString(is), std::ios::binary);
2778 PointedThing pointed;
2779 pointed.deSerialize(tmp_is);
2781 verbosestream<<"TOSERVER_INTERACT: action="<<(int)action<<", item="
2782 <<item_i<<", pointed="<<pointed.dump()<<std::endl;
2786 verbosestream<<"TOSERVER_INTERACT: "<<player->getName()
2787 <<" tried to interact, but is dead!"<<std::endl;
2791 v3f player_pos = playersao->getLastGoodPosition();
2793 // Update wielded item
2794 playersao->setWieldIndex(item_i);
2796 // Get pointed to node (undefined if not POINTEDTYPE_NODE)
2797 v3s16 p_under = pointed.node_undersurface;
2798 v3s16 p_above = pointed.node_abovesurface;
2800 // Get pointed to object (NULL if not POINTEDTYPE_OBJECT)
2801 ServerActiveObject *pointed_object = NULL;
2802 if(pointed.type == POINTEDTHING_OBJECT)
2804 pointed_object = m_env->getActiveObject(pointed.object_id);
2805 if(pointed_object == NULL)
2807 verbosestream<<"TOSERVER_INTERACT: "
2808 "pointed object is NULL"<<std::endl;
2814 v3f pointed_pos_under = player_pos;
2815 v3f pointed_pos_above = player_pos;
2816 if(pointed.type == POINTEDTHING_NODE)
2818 pointed_pos_under = intToFloat(p_under, BS);
2819 pointed_pos_above = intToFloat(p_above, BS);
2821 else if(pointed.type == POINTEDTHING_OBJECT)
2823 pointed_pos_under = pointed_object->getBasePosition();
2824 pointed_pos_above = pointed_pos_under;
2828 Check that target is reasonably close
2829 (only when digging or placing things)
2831 if(action == 0 || action == 2 || action == 3)
2833 float d = player_pos.getDistanceFrom(pointed_pos_under);
2834 float max_d = BS * 14; // Just some large enough value
2836 actionstream<<"Player "<<player->getName()
2837 <<" tried to access "<<pointed.dump()
2839 <<"d="<<d<<", max_d="<<max_d
2840 <<". ignoring."<<std::endl;
2841 // Re-send block to revert change on client-side
2842 RemoteClient *client = getClient(peer_id);
2843 v3s16 blockpos = getNodeBlockPos(floatToInt(pointed_pos_under, BS));
2844 client->SetBlockNotSent(blockpos);
2846 m_script->on_cheat(playersao, "interacted_too_far");
2853 Make sure the player is allowed to do it
2855 if(!checkPriv(player->getName(), "interact"))
2857 actionstream<<player->getName()<<" attempted to interact with "
2858 <<pointed.dump()<<" without 'interact' privilege"
2860 // Re-send block to revert change on client-side
2861 RemoteClient *client = getClient(peer_id);
2862 // Digging completed -> under
2864 v3s16 blockpos = getNodeBlockPos(floatToInt(pointed_pos_under, BS));
2865 client->SetBlockNotSent(blockpos);
2867 // Placement -> above
2869 v3s16 blockpos = getNodeBlockPos(floatToInt(pointed_pos_above, BS));
2870 client->SetBlockNotSent(blockpos);
2876 If something goes wrong, this player is to blame
2878 RollbackScopeActor rollback_scope(m_rollback,
2879 std::string("player:")+player->getName());
2882 0: start digging or punch object
2886 if(pointed.type == POINTEDTHING_NODE)
2889 NOTE: This can be used in the future to check if
2890 somebody is cheating, by checking the timing.
2892 MapNode n(CONTENT_IGNORE);
2895 n = m_env->getMap().getNode(p_under);
2897 catch(InvalidPositionException &e)
2899 infostream<<"Server: Not punching: Node not found."
2900 <<" Adding block to emerge queue."
2902 m_emerge->enqueueBlockEmerge(peer_id, getNodeBlockPos(p_above), false);
2904 if(n.getContent() != CONTENT_IGNORE)
2905 m_script->node_on_punch(p_under, n, playersao);
2907 playersao->noCheatDigStart(p_under);
2909 else if(pointed.type == POINTEDTHING_OBJECT)
2911 // Skip if object has been removed
2912 if(pointed_object->m_removed)
2915 actionstream<<player->getName()<<" punches object "
2916 <<pointed.object_id<<": "
2917 <<pointed_object->getDescription()<<std::endl;
2919 ItemStack punchitem = playersao->getWieldedItem();
2920 ToolCapabilities toolcap =
2921 punchitem.getToolCapabilities(m_itemdef);
2922 v3f dir = (pointed_object->getBasePosition() -
2923 (player->getPosition() + player->getEyeOffset())
2925 float time_from_last_punch =
2926 playersao->resetTimeFromLastPunch();
2927 pointed_object->punch(dir, &toolcap, playersao,
2928 time_from_last_punch);
2936 else if(action == 1)
2941 2: Digging completed
2943 else if(action == 2)
2945 // Only digging of nodes
2946 if(pointed.type == POINTEDTHING_NODE)
2948 MapNode n(CONTENT_IGNORE);
2951 n = m_env->getMap().getNode(p_under);
2953 catch(InvalidPositionException &e)
2955 infostream<<"Server: Not finishing digging: Node not found."
2956 <<" Adding block to emerge queue."
2958 m_emerge->enqueueBlockEmerge(peer_id, getNodeBlockPos(p_above), false);
2961 /* Cheat prevention */
2962 bool is_valid_dig = true;
2963 if(!isSingleplayer() && !g_settings->getBool("disable_anticheat"))
2965 v3s16 nocheat_p = playersao->getNoCheatDigPos();
2966 float nocheat_t = playersao->getNoCheatDigTime();
2967 playersao->noCheatDigEnd();
2968 // If player didn't start digging this, ignore dig
2969 if(nocheat_p != p_under){
2970 infostream<<"Server: NoCheat: "<<player->getName()
2971 <<" started digging "
2972 <<PP(nocheat_p)<<" and completed digging "
2973 <<PP(p_under)<<"; not digging."<<std::endl;
2974 is_valid_dig = false;
2976 m_script->on_cheat(playersao, "finished_unknown_dig");
2978 // Get player's wielded item
2979 ItemStack playeritem;
2980 InventoryList *mlist = playersao->getInventory()->getList("main");
2982 playeritem = mlist->getItem(playersao->getWieldIndex());
2983 ToolCapabilities playeritem_toolcap =
2984 playeritem.getToolCapabilities(m_itemdef);
2985 // Get diggability and expected digging time
2986 DigParams params = getDigParams(m_nodedef->get(n).groups,
2987 &playeritem_toolcap);
2988 // If can't dig, try hand
2989 if(!params.diggable){
2990 const ItemDefinition &hand = m_itemdef->get("");
2991 const ToolCapabilities *tp = hand.tool_capabilities;
2993 params = getDigParams(m_nodedef->get(n).groups, tp);
2995 // If can't dig, ignore dig
2996 if(!params.diggable){
2997 infostream<<"Server: NoCheat: "<<player->getName()
2998 <<" completed digging "<<PP(p_under)
2999 <<", which is not diggable with tool. not digging."
3001 is_valid_dig = false;
3003 m_script->on_cheat(playersao, "dug_unbreakable");
3005 // Check digging time
3006 // If already invalidated, we don't have to
3008 // Well not our problem then
3010 // Clean and long dig
3011 else if(params.time > 2.0 && nocheat_t * 1.2 > params.time){
3012 // All is good, but grab time from pool; don't care if
3013 // it's actually available
3014 playersao->getDigPool().grab(params.time);
3016 // Short or laggy dig
3017 // Try getting the time from pool
3018 else if(playersao->getDigPool().grab(params.time)){
3023 infostream<<"Server: NoCheat: "<<player->getName()
3024 <<" completed digging "<<PP(p_under)
3025 <<"too fast; not digging."<<std::endl;
3026 is_valid_dig = false;
3028 m_script->on_cheat(playersao, "dug_too_fast");
3032 /* Actually dig node */
3034 if(is_valid_dig && n.getContent() != CONTENT_IGNORE)
3035 m_script->node_on_dig(p_under, n, playersao);
3037 // Send unusual result (that is, node not being removed)
3038 if(m_env->getMap().getNodeNoEx(p_under).getContent() != CONTENT_AIR)
3040 // Re-send block to revert change on client-side
3041 RemoteClient *client = getClient(peer_id);
3042 v3s16 blockpos = getNodeBlockPos(floatToInt(pointed_pos_under, BS));
3043 client->SetBlockNotSent(blockpos);
3049 3: place block or right-click object
3051 else if(action == 3)
3053 ItemStack item = playersao->getWieldedItem();
3055 // Reset build time counter
3056 if(pointed.type == POINTEDTHING_NODE &&
3057 item.getDefinition(m_itemdef).type == ITEM_NODE)
3058 getClient(peer_id)->m_time_from_building = 0.0;
3060 if(pointed.type == POINTEDTHING_OBJECT)
3062 // Right click object
3064 // Skip if object has been removed
3065 if(pointed_object->m_removed)
3068 actionstream<<player->getName()<<" right-clicks object "
3069 <<pointed.object_id<<": "
3070 <<pointed_object->getDescription()<<std::endl;
3073 pointed_object->rightClick(playersao);
3075 else if(m_script->item_OnPlace(
3076 item, playersao, pointed))
3078 // Placement was handled in lua
3080 // Apply returned ItemStack
3081 playersao->setWieldedItem(item);
3084 // If item has node placement prediction, always send the
3085 // blocks to make sure the client knows what exactly happened
3086 if(item.getDefinition(m_itemdef).node_placement_prediction != ""){
3087 RemoteClient *client = getClient(peer_id);
3088 v3s16 blockpos = getNodeBlockPos(floatToInt(pointed_pos_above, BS));
3089 client->SetBlockNotSent(blockpos);
3090 v3s16 blockpos2 = getNodeBlockPos(floatToInt(pointed_pos_under, BS));
3091 if(blockpos2 != blockpos){
3092 client->SetBlockNotSent(blockpos2);
3100 else if(action == 4)
3102 ItemStack item = playersao->getWieldedItem();
3104 actionstream<<player->getName()<<" uses "<<item.name
3105 <<", pointing at "<<pointed.dump()<<std::endl;
3107 if(m_script->item_OnUse(
3108 item, playersao, pointed))
3110 // Apply returned ItemStack
3111 playersao->setWieldedItem(item);
3118 Catch invalid actions
3122 infostream<<"WARNING: Server: Invalid action "
3123 <<action<<std::endl;
3126 else if(command == TOSERVER_REMOVED_SOUNDS)
3128 std::string datastring((char*)&data[2], datasize-2);
3129 std::istringstream is(datastring, std::ios_base::binary);
3131 int num = readU16(is);
3132 for(int k=0; k<num; k++){
3133 s32 id = readS32(is);
3134 std::map<s32, ServerPlayingSound>::iterator i =
3135 m_playing_sounds.find(id);
3136 if(i == m_playing_sounds.end())
3138 ServerPlayingSound &psound = i->second;
3139 psound.clients.erase(peer_id);
3140 if(psound.clients.size() == 0)
3141 m_playing_sounds.erase(i++);
3144 else if(command == TOSERVER_NODEMETA_FIELDS)
3146 std::string datastring((char*)&data[2], datasize-2);
3147 std::istringstream is(datastring, std::ios_base::binary);
3149 v3s16 p = readV3S16(is);
3150 std::string formname = deSerializeString(is);
3151 int num = readU16(is);
3152 std::map<std::string, std::string> fields;
3153 for(int k=0; k<num; k++){
3154 std::string fieldname = deSerializeString(is);
3155 std::string fieldvalue = deSerializeLongString(is);
3156 fields[fieldname] = fieldvalue;
3159 // If something goes wrong, this player is to blame
3160 RollbackScopeActor rollback_scope(m_rollback,
3161 std::string("player:")+player->getName());
3163 // Check the target node for rollback data; leave others unnoticed
3164 RollbackNode rn_old(&m_env->getMap(), p, this);
3166 m_script->node_on_receive_fields(p, formname, fields,playersao);
3168 // Report rollback data
3169 RollbackNode rn_new(&m_env->getMap(), p, this);
3170 if(rollback() && rn_new != rn_old){
3171 RollbackAction action;
3172 action.setSetNode(p, rn_old, rn_new);
3173 rollback()->reportAction(action);
3176 else if(command == TOSERVER_INVENTORY_FIELDS)
3178 std::string datastring((char*)&data[2], datasize-2);
3179 std::istringstream is(datastring, std::ios_base::binary);
3181 std::string formname = deSerializeString(is);
3182 int num = readU16(is);
3183 std::map<std::string, std::string> fields;
3184 for(int k=0; k<num; k++){
3185 std::string fieldname = deSerializeString(is);
3186 std::string fieldvalue = deSerializeLongString(is);
3187 fields[fieldname] = fieldvalue;
3190 m_script->on_playerReceiveFields(playersao, formname, fields);
3194 infostream<<"Server::ProcessData(): Ignoring "
3195 "unknown command "<<command<<std::endl;
3199 catch(SendFailedException &e)
3201 errorstream<<"Server::ProcessData(): SendFailedException: "
3207 void Server::setTimeOfDay(u32 time)
3209 m_env->setTimeOfDay(time);
3210 m_time_of_day_send_timer = 0;
3213 void Server::onMapEditEvent(MapEditEvent *event)
3215 //infostream<<"Server::onMapEditEvent()"<<std::endl;
3216 if(m_ignore_map_edit_events)
3218 if(m_ignore_map_edit_events_area.contains(event->getArea()))
3220 MapEditEvent *e = event->clone();
3221 m_unsent_map_edit_queue.push_back(e);
3224 Inventory* Server::getInventory(const InventoryLocation &loc)
3227 case InventoryLocation::UNDEFINED:
3230 case InventoryLocation::CURRENT_PLAYER:
3233 case InventoryLocation::PLAYER:
3235 Player *player = m_env->getPlayer(loc.name.c_str());
3238 PlayerSAO *playersao = player->getPlayerSAO();
3241 return playersao->getInventory();
3244 case InventoryLocation::NODEMETA:
3246 NodeMetadata *meta = m_env->getMap().getNodeMetadata(loc.p);
3249 return meta->getInventory();
3252 case InventoryLocation::DETACHED:
3254 if(m_detached_inventories.count(loc.name) == 0)
3256 return m_detached_inventories[loc.name];
3264 void Server::setInventoryModified(const InventoryLocation &loc)
3267 case InventoryLocation::UNDEFINED:
3270 case InventoryLocation::PLAYER:
3272 Player *player = m_env->getPlayer(loc.name.c_str());
3275 PlayerSAO *playersao = player->getPlayerSAO();
3278 playersao->m_inventory_not_sent = true;
3279 playersao->m_wielded_item_not_sent = true;
3282 case InventoryLocation::NODEMETA:
3284 v3s16 blockpos = getNodeBlockPos(loc.p);
3286 MapBlock *block = m_env->getMap().getBlockNoCreateNoEx(blockpos);
3288 block->raiseModified(MOD_STATE_WRITE_NEEDED);
3290 setBlockNotSent(blockpos);
3293 case InventoryLocation::DETACHED:
3295 sendDetachedInventoryToAll(loc.name);
3303 void Server::peerAdded(con::Peer *peer)
3305 DSTACK(__FUNCTION_NAME);
3306 verbosestream<<"Server::peerAdded(): peer->id="
3307 <<peer->id<<std::endl;
3310 c.type = PEER_ADDED;
3311 c.peer_id = peer->id;
3313 m_peer_change_queue.push_back(c);
3316 void Server::deletingPeer(con::Peer *peer, bool timeout)
3318 DSTACK(__FUNCTION_NAME);
3319 verbosestream<<"Server::deletingPeer(): peer->id="
3320 <<peer->id<<", timeout="<<timeout<<std::endl;
3323 c.type = PEER_REMOVED;
3324 c.peer_id = peer->id;
3325 c.timeout = timeout;
3326 m_peer_change_queue.push_back(c);
3333 void Server::SendMovement(con::Connection &con, u16 peer_id)
3335 DSTACK(__FUNCTION_NAME);
3336 std::ostringstream os(std::ios_base::binary);
3338 writeU16(os, TOCLIENT_MOVEMENT);
3339 writeF1000(os, g_settings->getFloat("movement_acceleration_default"));
3340 writeF1000(os, g_settings->getFloat("movement_acceleration_air"));
3341 writeF1000(os, g_settings->getFloat("movement_acceleration_fast"));
3342 writeF1000(os, g_settings->getFloat("movement_speed_walk"));
3343 writeF1000(os, g_settings->getFloat("movement_speed_crouch"));
3344 writeF1000(os, g_settings->getFloat("movement_speed_fast"));
3345 writeF1000(os, g_settings->getFloat("movement_speed_climb"));
3346 writeF1000(os, g_settings->getFloat("movement_speed_jump"));
3347 writeF1000(os, g_settings->getFloat("movement_liquid_fluidity"));
3348 writeF1000(os, g_settings->getFloat("movement_liquid_fluidity_smooth"));
3349 writeF1000(os, g_settings->getFloat("movement_liquid_sink"));
3350 writeF1000(os, g_settings->getFloat("movement_gravity"));
3353 std::string s = os.str();
3354 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3356 con.Send(peer_id, 0, data, true);
3359 void Server::SendHP(con::Connection &con, u16 peer_id, u8 hp)
3361 DSTACK(__FUNCTION_NAME);
3362 std::ostringstream os(std::ios_base::binary);
3364 writeU16(os, TOCLIENT_HP);
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::SendBreath(con::Connection &con, u16 peer_id, u16 breath)
3376 DSTACK(__FUNCTION_NAME);
3377 std::ostringstream os(std::ios_base::binary);
3379 writeU16(os, TOCLIENT_BREATH);
3380 writeU16(os, breath);
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::SendAccessDenied(con::Connection &con, u16 peer_id,
3390 const std::wstring &reason)
3392 DSTACK(__FUNCTION_NAME);
3393 std::ostringstream os(std::ios_base::binary);
3395 writeU16(os, TOCLIENT_ACCESS_DENIED);
3396 os<<serializeWideString(reason);
3399 std::string s = os.str();
3400 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3402 con.Send(peer_id, 0, data, true);
3405 void Server::SendDeathscreen(con::Connection &con, u16 peer_id,
3406 bool set_camera_point_target, v3f camera_point_target)
3408 DSTACK(__FUNCTION_NAME);
3409 std::ostringstream os(std::ios_base::binary);
3411 writeU16(os, TOCLIENT_DEATHSCREEN);
3412 writeU8(os, set_camera_point_target);
3413 writeV3F1000(os, camera_point_target);
3416 std::string s = os.str();
3417 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3419 con.Send(peer_id, 0, data, true);
3422 void Server::SendItemDef(con::Connection &con, u16 peer_id,
3423 IItemDefManager *itemdef, u16 protocol_version)
3425 DSTACK(__FUNCTION_NAME);
3426 std::ostringstream os(std::ios_base::binary);
3430 u32 length of the next item
3431 zlib-compressed serialized ItemDefManager
3433 writeU16(os, TOCLIENT_ITEMDEF);
3434 std::ostringstream tmp_os(std::ios::binary);
3435 itemdef->serialize(tmp_os, protocol_version);
3436 std::ostringstream tmp_os2(std::ios::binary);
3437 compressZlib(tmp_os.str(), tmp_os2);
3438 os<<serializeLongString(tmp_os2.str());
3441 std::string s = os.str();
3442 verbosestream<<"Server: Sending item definitions to id("<<peer_id
3443 <<"): size="<<s.size()<<std::endl;
3444 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3446 con.Send(peer_id, 0, data, true);
3449 void Server::SendNodeDef(con::Connection &con, u16 peer_id,
3450 INodeDefManager *nodedef, u16 protocol_version)
3452 DSTACK(__FUNCTION_NAME);
3453 std::ostringstream os(std::ios_base::binary);
3457 u32 length of the next item
3458 zlib-compressed serialized NodeDefManager
3460 writeU16(os, TOCLIENT_NODEDEF);
3461 std::ostringstream tmp_os(std::ios::binary);
3462 nodedef->serialize(tmp_os, protocol_version);
3463 std::ostringstream tmp_os2(std::ios::binary);
3464 compressZlib(tmp_os.str(), tmp_os2);
3465 os<<serializeLongString(tmp_os2.str());
3468 std::string s = os.str();
3469 verbosestream<<"Server: Sending node definitions to id("<<peer_id
3470 <<"): size="<<s.size()<<std::endl;
3471 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3473 con.Send(peer_id, 0, data, true);
3477 Non-static send methods
3480 void Server::SendInventory(u16 peer_id)
3482 DSTACK(__FUNCTION_NAME);
3484 PlayerSAO *playersao = getPlayerSAO(peer_id);
3487 playersao->m_inventory_not_sent = false;
3493 std::ostringstream os;
3494 playersao->getInventory()->serialize(os);
3496 std::string s = os.str();
3498 SharedBuffer<u8> data(s.size()+2);
3499 writeU16(&data[0], TOCLIENT_INVENTORY);
3500 memcpy(&data[2], s.c_str(), s.size());
3503 m_con.Send(peer_id, 0, data, true);
3506 void Server::SendChatMessage(u16 peer_id, const std::wstring &message)
3508 DSTACK(__FUNCTION_NAME);
3510 std::ostringstream os(std::ios_base::binary);
3514 writeU16(buf, TOCLIENT_CHAT_MESSAGE);
3515 os.write((char*)buf, 2);
3518 writeU16(buf, message.size());
3519 os.write((char*)buf, 2);
3522 for(u32 i=0; i<message.size(); i++)
3526 os.write((char*)buf, 2);
3530 std::string s = os.str();
3531 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3533 m_con.Send(peer_id, 0, data, true);
3536 void Server::SendShowFormspecMessage(u16 peer_id, const std::string formspec,
3537 const std::string formname)
3539 DSTACK(__FUNCTION_NAME);
3541 std::ostringstream os(std::ios_base::binary);
3545 writeU16(buf, TOCLIENT_SHOW_FORMSPEC);
3546 os.write((char*)buf, 2);
3547 os<<serializeLongString(formspec);
3548 os<<serializeString(formname);
3551 std::string s = os.str();
3552 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3554 m_con.Send(peer_id, 0, data, true);
3557 // Spawns a particle on peer with peer_id
3558 void Server::SendSpawnParticle(u16 peer_id, v3f pos, v3f velocity, v3f acceleration,
3559 float expirationtime, float size, bool collisiondetection,
3560 std::string texture)
3562 DSTACK(__FUNCTION_NAME);
3564 std::ostringstream os(std::ios_base::binary);
3565 writeU16(os, TOCLIENT_SPAWN_PARTICLE);
3566 writeV3F1000(os, pos);
3567 writeV3F1000(os, velocity);
3568 writeV3F1000(os, acceleration);
3569 writeF1000(os, expirationtime);
3570 writeF1000(os, size);
3571 writeU8(os, collisiondetection);
3572 os<<serializeLongString(texture);
3575 std::string s = os.str();
3576 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3578 m_con.Send(peer_id, 0, data, true);
3581 // Spawns a particle on all peers
3582 void Server::SendSpawnParticleAll(v3f pos, v3f velocity, v3f acceleration,
3583 float expirationtime, float size, bool collisiondetection,
3584 std::string texture)
3586 for(std::map<u16, RemoteClient*>::iterator
3587 i = m_clients.begin();
3588 i != m_clients.end(); i++)
3590 // Get client and check that it is valid
3591 RemoteClient *client = i->second;
3592 assert(client->peer_id == i->first);
3593 if(client->serialization_version == SER_FMT_VER_INVALID)
3596 SendSpawnParticle(client->peer_id, pos, velocity, acceleration,
3597 expirationtime, size, collisiondetection, texture);
3601 // Adds a ParticleSpawner on peer with peer_id
3602 void Server::SendAddParticleSpawner(u16 peer_id, u16 amount, float spawntime, v3f minpos, v3f maxpos,
3603 v3f minvel, v3f maxvel, v3f minacc, v3f maxacc, float minexptime, float maxexptime,
3604 float minsize, float maxsize, bool collisiondetection, std::string texture, u32 id)
3606 DSTACK(__FUNCTION_NAME);
3608 std::ostringstream os(std::ios_base::binary);
3609 writeU16(os, TOCLIENT_ADD_PARTICLESPAWNER);
3611 writeU16(os, amount);
3612 writeF1000(os, spawntime);
3613 writeV3F1000(os, minpos);
3614 writeV3F1000(os, maxpos);
3615 writeV3F1000(os, minvel);
3616 writeV3F1000(os, maxvel);
3617 writeV3F1000(os, minacc);
3618 writeV3F1000(os, maxacc);
3619 writeF1000(os, minexptime);
3620 writeF1000(os, maxexptime);
3621 writeF1000(os, minsize);
3622 writeF1000(os, maxsize);
3623 writeU8(os, collisiondetection);
3624 os<<serializeLongString(texture);
3628 std::string s = os.str();
3629 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3631 m_con.Send(peer_id, 0, data, true);
3634 // Adds a ParticleSpawner on all peers
3635 void Server::SendAddParticleSpawnerAll(u16 amount, float spawntime, v3f minpos, v3f maxpos,
3636 v3f minvel, v3f maxvel, v3f minacc, v3f maxacc, float minexptime, float maxexptime,
3637 float minsize, float maxsize, bool collisiondetection, std::string texture, u32 id)
3639 for(std::map<u16, RemoteClient*>::iterator
3640 i = m_clients.begin();
3641 i != m_clients.end(); i++)
3643 // Get client and check that it is valid
3644 RemoteClient *client = i->second;
3645 assert(client->peer_id == i->first);
3646 if(client->serialization_version == SER_FMT_VER_INVALID)
3649 SendAddParticleSpawner(client->peer_id, amount, spawntime,
3650 minpos, maxpos, minvel, maxvel, minacc, maxacc,
3651 minexptime, maxexptime, minsize, maxsize, collisiondetection, texture, id);
3655 void Server::SendDeleteParticleSpawner(u16 peer_id, u32 id)
3657 DSTACK(__FUNCTION_NAME);
3659 std::ostringstream os(std::ios_base::binary);
3660 writeU16(os, TOCLIENT_DELETE_PARTICLESPAWNER);
3665 std::string s = os.str();
3666 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3668 m_con.Send(peer_id, 0, data, true);
3671 void Server::SendDeleteParticleSpawnerAll(u32 id)
3673 for(std::map<u16, RemoteClient*>::iterator
3674 i = m_clients.begin();
3675 i != m_clients.end(); i++)
3677 // Get client and check that it is valid
3678 RemoteClient *client = i->second;
3679 assert(client->peer_id == i->first);
3680 if(client->serialization_version == SER_FMT_VER_INVALID)
3683 SendDeleteParticleSpawner(client->peer_id, id);
3687 void Server::SendHUDAdd(u16 peer_id, u32 id, HudElement *form)
3689 std::ostringstream os(std::ios_base::binary);
3692 writeU16(os, TOCLIENT_HUDADD);
3694 writeU8(os, (u8)form->type);
3695 writeV2F1000(os, form->pos);
3696 os << serializeString(form->name);
3697 writeV2F1000(os, form->scale);
3698 os << serializeString(form->text);
3699 writeU32(os, form->number);
3700 writeU32(os, form->item);
3701 writeU32(os, form->dir);
3702 writeV2F1000(os, form->align);
3703 writeV2F1000(os, form->offset);
3706 std::string s = os.str();
3707 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3709 m_con.Send(peer_id, 0, data, true);
3712 void Server::SendHUDRemove(u16 peer_id, u32 id)
3714 std::ostringstream os(std::ios_base::binary);
3717 writeU16(os, TOCLIENT_HUDRM);
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::SendHUDChange(u16 peer_id, u32 id, HudElementStat stat, void *value)
3729 std::ostringstream os(std::ios_base::binary);
3732 writeU16(os, TOCLIENT_HUDCHANGE);
3734 writeU8(os, (u8)stat);
3737 case HUD_STAT_SCALE:
3738 case HUD_STAT_ALIGN:
3739 case HUD_STAT_OFFSET:
3740 writeV2F1000(os, *(v2f *)value);
3744 os << serializeString(*(std::string *)value);
3746 case HUD_STAT_NUMBER:
3750 writeU32(os, *(u32 *)value);
3755 std::string s = os.str();
3756 SharedBuffer<u8> data((u8 *)s.c_str(), s.size());
3758 m_con.Send(peer_id, 0, data, true);
3761 void Server::SendHUDSetFlags(u16 peer_id, u32 flags, u32 mask)
3763 std::ostringstream os(std::ios_base::binary);
3766 writeU16(os, TOCLIENT_HUD_SET_FLAGS);
3767 writeU32(os, flags);
3771 std::string s = os.str();
3772 SharedBuffer<u8> data((u8 *)s.c_str(), s.size());
3774 m_con.Send(peer_id, 0, data, true);
3777 void Server::SendHUDSetParam(u16 peer_id, u16 param, const std::string &value)
3779 std::ostringstream os(std::ios_base::binary);
3782 writeU16(os, TOCLIENT_HUD_SET_PARAM);
3783 writeU16(os, param);
3784 os<<serializeString(value);
3787 std::string s = os.str();
3788 SharedBuffer<u8> data((u8 *)s.c_str(), s.size());
3790 m_con.Send(peer_id, 0, data, true);
3793 void Server::BroadcastChatMessage(const std::wstring &message)
3795 for(std::map<u16, RemoteClient*>::iterator
3796 i = m_clients.begin();
3797 i != m_clients.end(); ++i)
3799 // Get client and check that it is valid
3800 RemoteClient *client = i->second;
3801 assert(client->peer_id == i->first);
3802 if(client->serialization_version == SER_FMT_VER_INVALID)
3805 SendChatMessage(client->peer_id, message);
3809 void Server::SendTimeOfDay(u16 peer_id, u16 time, f32 time_speed)
3811 DSTACK(__FUNCTION_NAME);
3814 SharedBuffer<u8> data(2+2+4);
3815 writeU16(&data[0], TOCLIENT_TIME_OF_DAY);
3816 writeU16(&data[2], time);
3817 writeF1000(&data[4], time_speed);
3820 m_con.Send(peer_id, 0, data, true);
3823 void Server::SendPlayerHP(u16 peer_id)
3825 DSTACK(__FUNCTION_NAME);
3826 PlayerSAO *playersao = getPlayerSAO(peer_id);
3828 playersao->m_hp_not_sent = false;
3829 SendHP(m_con, peer_id, playersao->getHP());
3831 // Send to other clients
3832 std::string str = gob_cmd_punched(playersao->readDamage(), playersao->getHP());
3833 ActiveObjectMessage aom(playersao->getId(), true, str);
3834 playersao->m_messages_out.push_back(aom);
3837 void Server::SendPlayerBreath(u16 peer_id)
3839 DSTACK(__FUNCTION_NAME);
3840 PlayerSAO *playersao = getPlayerSAO(peer_id);
3842 playersao->m_breath_not_sent = false;
3843 SendBreath(m_con, peer_id, playersao->getBreath());
3846 void Server::SendMovePlayer(u16 peer_id)
3848 DSTACK(__FUNCTION_NAME);
3849 Player *player = m_env->getPlayer(peer_id);
3852 std::ostringstream os(std::ios_base::binary);
3853 writeU16(os, TOCLIENT_MOVE_PLAYER);
3854 writeV3F1000(os, player->getPosition());
3855 writeF1000(os, player->getPitch());
3856 writeF1000(os, player->getYaw());
3859 v3f pos = player->getPosition();
3860 f32 pitch = player->getPitch();
3861 f32 yaw = player->getYaw();
3862 verbosestream<<"Server: Sending TOCLIENT_MOVE_PLAYER"
3863 <<" pos=("<<pos.X<<","<<pos.Y<<","<<pos.Z<<")"
3870 std::string s = os.str();
3871 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3873 m_con.Send(peer_id, 0, data, true);
3876 void Server::SendPlayerPrivileges(u16 peer_id)
3878 Player *player = m_env->getPlayer(peer_id);
3880 if(player->peer_id == PEER_ID_INEXISTENT)
3883 std::set<std::string> privs;
3884 m_script->getAuth(player->getName(), NULL, &privs);
3886 std::ostringstream os(std::ios_base::binary);
3887 writeU16(os, TOCLIENT_PRIVILEGES);
3888 writeU16(os, privs.size());
3889 for(std::set<std::string>::const_iterator i = privs.begin();
3890 i != privs.end(); i++){
3891 os<<serializeString(*i);
3895 std::string s = os.str();
3896 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3898 m_con.Send(peer_id, 0, data, true);
3901 void Server::SendPlayerInventoryFormspec(u16 peer_id)
3903 Player *player = m_env->getPlayer(peer_id);
3905 if(player->peer_id == PEER_ID_INEXISTENT)
3908 std::ostringstream os(std::ios_base::binary);
3909 writeU16(os, TOCLIENT_INVENTORY_FORMSPEC);
3910 os<<serializeLongString(player->inventory_formspec);
3913 std::string s = os.str();
3914 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3916 m_con.Send(peer_id, 0, data, true);
3919 s32 Server::playSound(const SimpleSoundSpec &spec,
3920 const ServerSoundParams ¶ms)
3922 // Find out initial position of sound
3923 bool pos_exists = false;
3924 v3f pos = params.getPos(m_env, &pos_exists);
3925 // If position is not found while it should be, cancel sound
3926 if(pos_exists != (params.type != ServerSoundParams::SSP_LOCAL))
3928 // Filter destination clients
3929 std::set<RemoteClient*> dst_clients;
3930 if(params.to_player != "")
3932 Player *player = m_env->getPlayer(params.to_player.c_str());
3934 infostream<<"Server::playSound: Player \""<<params.to_player
3935 <<"\" not found"<<std::endl;
3938 if(player->peer_id == PEER_ID_INEXISTENT){
3939 infostream<<"Server::playSound: Player \""<<params.to_player
3940 <<"\" not connected"<<std::endl;
3943 RemoteClient *client = getClient(player->peer_id);
3944 dst_clients.insert(client);
3948 for(std::map<u16, RemoteClient*>::iterator
3949 i = m_clients.begin(); i != m_clients.end(); ++i)
3951 RemoteClient *client = i->second;
3952 Player *player = m_env->getPlayer(client->peer_id);
3956 if(player->getPosition().getDistanceFrom(pos) >
3957 params.max_hear_distance)
3960 dst_clients.insert(client);
3963 if(dst_clients.size() == 0)
3966 s32 id = m_next_sound_id++;
3967 // The sound will exist as a reference in m_playing_sounds
3968 m_playing_sounds[id] = ServerPlayingSound();
3969 ServerPlayingSound &psound = m_playing_sounds[id];
3970 psound.params = params;
3971 for(std::set<RemoteClient*>::iterator i = dst_clients.begin();
3972 i != dst_clients.end(); i++)
3973 psound.clients.insert((*i)->peer_id);
3975 std::ostringstream os(std::ios_base::binary);
3976 writeU16(os, TOCLIENT_PLAY_SOUND);
3978 os<<serializeString(spec.name);
3979 writeF1000(os, spec.gain * params.gain);
3980 writeU8(os, params.type);
3981 writeV3F1000(os, pos);
3982 writeU16(os, params.object);
3983 writeU8(os, params.loop);
3985 std::string s = os.str();
3986 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3988 for(std::set<RemoteClient*>::iterator i = dst_clients.begin();
3989 i != dst_clients.end(); i++){
3991 m_con.Send((*i)->peer_id, 0, data, true);
3995 void Server::stopSound(s32 handle)
3997 // Get sound reference
3998 std::map<s32, ServerPlayingSound>::iterator i =
3999 m_playing_sounds.find(handle);
4000 if(i == m_playing_sounds.end())
4002 ServerPlayingSound &psound = i->second;
4004 std::ostringstream os(std::ios_base::binary);
4005 writeU16(os, TOCLIENT_STOP_SOUND);
4006 writeS32(os, handle);
4008 std::string s = os.str();
4009 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
4011 for(std::set<u16>::iterator i = psound.clients.begin();
4012 i != psound.clients.end(); i++){
4014 m_con.Send(*i, 0, data, true);
4016 // Remove sound reference
4017 m_playing_sounds.erase(i);
4020 void Server::sendRemoveNode(v3s16 p, u16 ignore_id,
4021 std::list<u16> *far_players, float far_d_nodes)
4023 float maxd = far_d_nodes*BS;
4024 v3f p_f = intToFloat(p, BS);
4028 SharedBuffer<u8> reply(replysize);
4029 writeU16(&reply[0], TOCLIENT_REMOVENODE);
4030 writeS16(&reply[2], p.X);
4031 writeS16(&reply[4], p.Y);
4032 writeS16(&reply[6], p.Z);
4034 for(std::map<u16, RemoteClient*>::iterator
4035 i = m_clients.begin();
4036 i != m_clients.end(); ++i)
4038 // Get client and check that it is valid
4039 RemoteClient *client = i->second;
4040 assert(client->peer_id == i->first);
4041 if(client->serialization_version == SER_FMT_VER_INVALID)
4044 // Don't send if it's the same one
4045 if(client->peer_id == ignore_id)
4051 Player *player = m_env->getPlayer(client->peer_id);
4054 // If player is far away, only set modified blocks not sent
4055 v3f player_pos = player->getPosition();
4056 if(player_pos.getDistanceFrom(p_f) > maxd)
4058 far_players->push_back(client->peer_id);
4065 m_con.Send(client->peer_id, 0, reply, true);
4069 void Server::sendAddNode(v3s16 p, MapNode n, u16 ignore_id,
4070 std::list<u16> *far_players, float far_d_nodes,
4071 bool remove_metadata)
4073 float maxd = far_d_nodes*BS;
4074 v3f p_f = intToFloat(p, BS);
4076 for(std::map<u16, RemoteClient*>::iterator
4077 i = m_clients.begin();
4078 i != m_clients.end(); ++i)
4080 // Get client and check that it is valid
4081 RemoteClient *client = i->second;
4082 assert(client->peer_id == i->first);
4083 if(client->serialization_version == SER_FMT_VER_INVALID)
4086 // Don't send if it's the same one
4087 if(client->peer_id == ignore_id)
4093 Player *player = m_env->getPlayer(client->peer_id);
4096 // If player is far away, only set modified blocks not sent
4097 v3f player_pos = player->getPosition();
4098 if(player_pos.getDistanceFrom(p_f) > maxd)
4100 far_players->push_back(client->peer_id);
4107 u32 replysize = 9 + MapNode::serializedLength(client->serialization_version);
4108 SharedBuffer<u8> reply(replysize);
4109 writeU16(&reply[0], TOCLIENT_ADDNODE);
4110 writeS16(&reply[2], p.X);
4111 writeS16(&reply[4], p.Y);
4112 writeS16(&reply[6], p.Z);
4113 n.serialize(&reply[8], client->serialization_version);
4114 u32 index = 8 + MapNode::serializedLength(client->serialization_version);
4115 writeU8(&reply[index], remove_metadata ? 0 : 1);
4117 if (!remove_metadata) {
4118 if (client->net_proto_version <= 21) {
4119 // Old clients always clear metadata; fix it
4120 // by sending the full block again.
4121 client->SetBlockNotSent(p);
4126 m_con.Send(client->peer_id, 0, reply, true);
4130 void Server::setBlockNotSent(v3s16 p)
4132 for(std::map<u16, RemoteClient*>::iterator
4133 i = m_clients.begin();
4134 i != m_clients.end(); ++i)
4136 RemoteClient *client = i->second;
4137 client->SetBlockNotSent(p);
4141 void Server::SendBlockNoLock(u16 peer_id, MapBlock *block, u8 ver, u16 net_proto_version)
4143 DSTACK(__FUNCTION_NAME);
4145 v3s16 p = block->getPos();
4149 bool completely_air = true;
4150 for(s16 z0=0; z0<MAP_BLOCKSIZE; z0++)
4151 for(s16 x0=0; x0<MAP_BLOCKSIZE; x0++)
4152 for(s16 y0=0; y0<MAP_BLOCKSIZE; y0++)
4154 if(block->getNodeNoEx(v3s16(x0,y0,z0)).d != CONTENT_AIR)
4156 completely_air = false;
4157 x0 = y0 = z0 = MAP_BLOCKSIZE; // Break out
4162 infostream<<"Server: Sending block ("<<p.X<<","<<p.Y<<","<<p.Z<<"): ";
4164 infostream<<"[completely air] ";
4165 infostream<<std::endl;
4169 Create a packet with the block in the right format
4172 std::ostringstream os(std::ios_base::binary);
4173 block->serialize(os, ver, false);
4174 block->serializeNetworkSpecific(os, net_proto_version);
4175 std::string s = os.str();
4176 SharedBuffer<u8> blockdata((u8*)s.c_str(), s.size());
4178 u32 replysize = 8 + blockdata.getSize();
4179 SharedBuffer<u8> reply(replysize);
4180 writeU16(&reply[0], TOCLIENT_BLOCKDATA);
4181 writeS16(&reply[2], p.X);
4182 writeS16(&reply[4], p.Y);
4183 writeS16(&reply[6], p.Z);
4184 memcpy(&reply[8], *blockdata, blockdata.getSize());
4186 /*infostream<<"Server: Sending block ("<<p.X<<","<<p.Y<<","<<p.Z<<")"
4187 <<": \tpacket size: "<<replysize<<std::endl;*/
4192 m_con.Send(peer_id, 1, reply, true);
4195 void Server::SendBlocks(float dtime)
4197 DSTACK(__FUNCTION_NAME);
4199 JMutexAutoLock envlock(m_env_mutex);
4200 JMutexAutoLock conlock(m_con_mutex);
4202 ScopeProfiler sp(g_profiler, "Server: sel and send blocks to clients");
4204 std::vector<PrioritySortedBlockTransfer> queue;
4206 s32 total_sending = 0;
4209 ScopeProfiler sp(g_profiler, "Server: selecting blocks for sending");
4211 for(std::map<u16, RemoteClient*>::iterator
4212 i = m_clients.begin();
4213 i != m_clients.end(); ++i)
4215 RemoteClient *client = i->second;
4216 assert(client->peer_id == i->first);
4218 // If definitions and textures have not been sent, don't
4219 // send MapBlocks either
4220 if(!client->definitions_sent)
4223 total_sending += client->SendingCount();
4225 if(client->serialization_version == SER_FMT_VER_INVALID)
4228 client->GetNextBlocks(this, dtime, queue);
4233 // Lowest priority number comes first.
4234 // Lowest is most important.
4235 std::sort(queue.begin(), queue.end());
4237 for(u32 i=0; i<queue.size(); i++)
4239 //TODO: Calculate limit dynamically
4240 if(total_sending >= g_settings->getS32
4241 ("max_simultaneous_block_sends_server_total"))
4244 PrioritySortedBlockTransfer q = queue[i];
4246 MapBlock *block = NULL;
4249 block = m_env->getMap().getBlockNoCreate(q.pos);
4251 catch(InvalidPositionException &e)
4256 RemoteClient *client = getClientNoEx(q.peer_id);
4262 SendBlockNoLock(q.peer_id, block, client->serialization_version, client->net_proto_version);
4264 client->SentBlock(q.pos);
4270 void Server::fillMediaCache()
4272 DSTACK(__FUNCTION_NAME);
4274 infostream<<"Server: Calculating media file checksums"<<std::endl;
4276 // Collect all media file paths
4277 std::list<std::string> paths;
4278 for(std::vector<ModSpec>::iterator i = m_mods.begin();
4279 i != m_mods.end(); i++){
4280 const ModSpec &mod = *i;
4281 paths.push_back(mod.path + DIR_DELIM + "textures");
4282 paths.push_back(mod.path + DIR_DELIM + "sounds");
4283 paths.push_back(mod.path + DIR_DELIM + "media");
4284 paths.push_back(mod.path + DIR_DELIM + "models");
4286 paths.push_back(porting::path_user + DIR_DELIM + "textures" + DIR_DELIM + "server");
4288 // Collect media file information from paths into cache
4289 for(std::list<std::string>::iterator i = paths.begin();
4290 i != paths.end(); i++)
4292 std::string mediapath = *i;
4293 std::vector<fs::DirListNode> dirlist = fs::GetDirListing(mediapath);
4294 for(u32 j=0; j<dirlist.size(); j++){
4295 if(dirlist[j].dir) // Ignode dirs
4297 std::string filename = dirlist[j].name;
4298 // If name contains illegal characters, ignore the file
4299 if(!string_allowed(filename, TEXTURENAME_ALLOWED_CHARS)){
4300 infostream<<"Server: ignoring illegal file name: \""
4301 <<filename<<"\""<<std::endl;
4304 // If name is not in a supported format, ignore it
4305 const char *supported_ext[] = {
4306 ".png", ".jpg", ".bmp", ".tga",
4307 ".pcx", ".ppm", ".psd", ".wal", ".rgb",
4309 ".x", ".b3d", ".md2", ".obj",
4312 if(removeStringEnd(filename, supported_ext) == ""){
4313 infostream<<"Server: ignoring unsupported file extension: \""
4314 <<filename<<"\""<<std::endl;
4317 // Ok, attempt to load the file and add to cache
4318 std::string filepath = mediapath + DIR_DELIM + filename;
4320 std::ifstream fis(filepath.c_str(), std::ios_base::binary);
4321 if(fis.good() == false){
4322 errorstream<<"Server::fillMediaCache(): Could not open \""
4323 <<filename<<"\" for reading"<<std::endl;
4326 std::ostringstream tmp_os(std::ios_base::binary);
4330 fis.read(buf, 1024);
4331 std::streamsize len = fis.gcount();
4332 tmp_os.write(buf, len);
4341 errorstream<<"Server::fillMediaCache(): Failed to read \""
4342 <<filename<<"\""<<std::endl;
4345 if(tmp_os.str().length() == 0){
4346 errorstream<<"Server::fillMediaCache(): Empty file \""
4347 <<filepath<<"\""<<std::endl;
4352 sha1.addBytes(tmp_os.str().c_str(), tmp_os.str().length());
4354 unsigned char *digest = sha1.getDigest();
4355 std::string sha1_base64 = base64_encode(digest, 20);
4356 std::string sha1_hex = hex_encode((char*)digest, 20);
4360 this->m_media[filename] = MediaInfo(filepath, sha1_base64);
4361 verbosestream<<"Server: "<<sha1_hex<<" is "<<filename<<std::endl;
4366 struct SendableMediaAnnouncement
4369 std::string sha1_digest;
4371 SendableMediaAnnouncement(const std::string name_="",
4372 const std::string sha1_digest_=""):
4374 sha1_digest(sha1_digest_)
4378 void Server::sendMediaAnnouncement(u16 peer_id)
4380 DSTACK(__FUNCTION_NAME);
4382 verbosestream<<"Server: Announcing files to id("<<peer_id<<")"
4385 std::list<SendableMediaAnnouncement> file_announcements;
4387 for(std::map<std::string, MediaInfo>::iterator i = m_media.begin();
4388 i != m_media.end(); i++){
4390 file_announcements.push_back(
4391 SendableMediaAnnouncement(i->first, i->second.sha1_digest));
4395 std::ostringstream os(std::ios_base::binary);
4403 u16 length of sha1_digest
4408 writeU16(os, TOCLIENT_ANNOUNCE_MEDIA);
4409 writeU16(os, file_announcements.size());
4411 for(std::list<SendableMediaAnnouncement>::iterator
4412 j = file_announcements.begin();
4413 j != file_announcements.end(); ++j){
4414 os<<serializeString(j->name);
4415 os<<serializeString(j->sha1_digest);
4417 os<<serializeString(g_settings->get("remote_media"));
4420 std::string s = os.str();
4421 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
4424 m_con.Send(peer_id, 0, data, true);
4427 struct SendableMedia
4433 SendableMedia(const std::string &name_="", const std::string path_="",
4434 const std::string &data_=""):
4441 void Server::sendRequestedMedia(u16 peer_id,
4442 const std::list<MediaRequest> &tosend)
4444 DSTACK(__FUNCTION_NAME);
4446 verbosestream<<"Server::sendRequestedMedia(): "
4447 <<"Sending files to client"<<std::endl;
4451 // Put 5kB in one bunch (this is not accurate)
4452 u32 bytes_per_bunch = 5000;
4454 std::vector< std::list<SendableMedia> > file_bunches;
4455 file_bunches.push_back(std::list<SendableMedia>());
4457 u32 file_size_bunch_total = 0;
4459 for(std::list<MediaRequest>::const_iterator i = tosend.begin();
4460 i != tosend.end(); ++i)
4462 if(m_media.find(i->name) == m_media.end()){
4463 errorstream<<"Server::sendRequestedMedia(): Client asked for "
4464 <<"unknown file \""<<(i->name)<<"\""<<std::endl;
4468 //TODO get path + name
4469 std::string tpath = m_media[(*i).name].path;
4472 std::ifstream fis(tpath.c_str(), std::ios_base::binary);
4473 if(fis.good() == false){
4474 errorstream<<"Server::sendRequestedMedia(): Could not open \""
4475 <<tpath<<"\" for reading"<<std::endl;
4478 std::ostringstream tmp_os(std::ios_base::binary);
4482 fis.read(buf, 1024);
4483 std::streamsize len = fis.gcount();
4484 tmp_os.write(buf, len);
4485 file_size_bunch_total += len;
4494 errorstream<<"Server::sendRequestedMedia(): Failed to read \""
4495 <<(*i).name<<"\""<<std::endl;
4498 /*infostream<<"Server::sendRequestedMedia(): Loaded \""
4499 <<tname<<"\""<<std::endl;*/
4501 file_bunches[file_bunches.size()-1].push_back(
4502 SendableMedia((*i).name, tpath, tmp_os.str()));
4504 // Start next bunch if got enough data
4505 if(file_size_bunch_total >= bytes_per_bunch){
4506 file_bunches.push_back(std::list<SendableMedia>());
4507 file_size_bunch_total = 0;
4512 /* Create and send packets */
4514 u32 num_bunches = file_bunches.size();
4515 for(u32 i=0; i<num_bunches; i++)
4517 std::ostringstream os(std::ios_base::binary);
4521 u16 total number of texture bunches
4522 u16 index of this bunch
4523 u32 number of files in this bunch
4532 writeU16(os, TOCLIENT_MEDIA);
4533 writeU16(os, num_bunches);
4535 writeU32(os, file_bunches[i].size());
4537 for(std::list<SendableMedia>::iterator
4538 j = file_bunches[i].begin();
4539 j != file_bunches[i].end(); ++j){
4540 os<<serializeString(j->name);
4541 os<<serializeLongString(j->data);
4545 std::string s = os.str();
4546 verbosestream<<"Server::sendRequestedMedia(): bunch "
4547 <<i<<"/"<<num_bunches
4548 <<" files="<<file_bunches[i].size()
4549 <<" size=" <<s.size()<<std::endl;
4550 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
4552 m_con.Send(peer_id, 0, data, true);
4556 void Server::sendDetachedInventory(const std::string &name, u16 peer_id)
4558 if(m_detached_inventories.count(name) == 0){
4559 errorstream<<__FUNCTION_NAME<<": \""<<name<<"\" not found"<<std::endl;
4562 Inventory *inv = m_detached_inventories[name];
4564 std::ostringstream os(std::ios_base::binary);
4565 writeU16(os, TOCLIENT_DETACHED_INVENTORY);
4566 os<<serializeString(name);
4570 std::string s = os.str();
4571 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
4573 m_con.Send(peer_id, 0, data, true);
4576 void Server::sendDetachedInventoryToAll(const std::string &name)
4578 DSTACK(__FUNCTION_NAME);
4580 for(std::map<u16, RemoteClient*>::iterator
4581 i = m_clients.begin();
4582 i != m_clients.end(); ++i){
4583 RemoteClient *client = i->second;
4584 sendDetachedInventory(name, client->peer_id);
4588 void Server::sendDetachedInventories(u16 peer_id)
4590 DSTACK(__FUNCTION_NAME);
4592 for(std::map<std::string, Inventory*>::iterator
4593 i = m_detached_inventories.begin();
4594 i != m_detached_inventories.end(); i++){
4595 const std::string &name = i->first;
4596 //Inventory *inv = i->second;
4597 sendDetachedInventory(name, peer_id);
4605 void Server::DiePlayer(u16 peer_id)
4607 DSTACK(__FUNCTION_NAME);
4609 PlayerSAO *playersao = getPlayerSAO(peer_id);
4612 infostream<<"Server::DiePlayer(): Player "
4613 <<playersao->getPlayer()->getName()
4614 <<" dies"<<std::endl;
4616 playersao->setHP(0);
4618 // Trigger scripted stuff
4619 m_script->on_dieplayer(playersao);
4621 SendPlayerHP(peer_id);
4622 SendDeathscreen(m_con, peer_id, false, v3f(0,0,0));
4625 void Server::RespawnPlayer(u16 peer_id)
4627 DSTACK(__FUNCTION_NAME);
4629 PlayerSAO *playersao = getPlayerSAO(peer_id);
4632 infostream<<"Server::RespawnPlayer(): Player "
4633 <<playersao->getPlayer()->getName()
4634 <<" respawns"<<std::endl;
4636 playersao->setHP(PLAYER_MAX_HP);
4638 bool repositioned = m_script->on_respawnplayer(playersao);
4640 v3f pos = findSpawnPos(m_env->getServerMap());
4641 playersao->setPos(pos);
4645 void Server::DenyAccess(u16 peer_id, const std::wstring &reason)
4647 DSTACK(__FUNCTION_NAME);
4649 SendAccessDenied(m_con, peer_id, reason);
4651 RemoteClient *client = getClientNoEx(peer_id);
4653 client->denied = true;
4655 // If there are way too many clients, get rid of denied new ones immediately
4656 if((int)m_clients.size() > 2 * g_settings->getU16("max_users")){
4657 verbosestream<<"Server: DenyAccess: Too many clients; getting rid of "
4658 <<"peer_id="<<peer_id<<" immediately"<<std::endl;
4659 // Delete peer to stop sending it data
4660 m_con.DeletePeer(peer_id);
4661 // Delete client also to stop block sends and other stuff
4662 DeleteClient(peer_id, CDR_DENY);
4666 void Server::DeleteClient(u16 peer_id, ClientDeletionReason reason)
4668 DSTACK(__FUNCTION_NAME);
4671 std::map<u16, RemoteClient*>::iterator n;
4672 n = m_clients.find(peer_id);
4673 // The client may not exist; clients are immediately removed if their
4674 // access is denied, and this event occurs later then.
4675 if(n == m_clients.end())
4679 Mark objects to be not known by the client
4681 RemoteClient *client = n->second;
4683 for(std::set<u16>::iterator
4684 i = client->m_known_objects.begin();
4685 i != client->m_known_objects.end(); ++i)
4689 ServerActiveObject* obj = m_env->getActiveObject(id);
4691 if(obj && obj->m_known_by_count > 0)
4692 obj->m_known_by_count--;
4696 Clear references to playing sounds
4698 for(std::map<s32, ServerPlayingSound>::iterator
4699 i = m_playing_sounds.begin();
4700 i != m_playing_sounds.end();)
4702 ServerPlayingSound &psound = i->second;
4703 psound.clients.erase(peer_id);
4704 if(psound.clients.size() == 0)
4705 m_playing_sounds.erase(i++);
4710 Player *player = m_env->getPlayer(peer_id);
4712 // Collect information about leaving in chat
4713 std::wstring message;
4715 if(player != NULL && reason != CDR_DENY)
4717 std::wstring name = narrow_to_wide(player->getName());
4720 message += L" left the game.";
4721 if(reason == CDR_TIMEOUT)
4722 message += L" (timed out)";
4726 /* Run scripts and remove from environment */
4730 PlayerSAO *playersao = player->getPlayerSAO();
4733 m_script->on_leaveplayer(playersao);
4735 playersao->disconnected();
4743 if(player != NULL && reason != CDR_DENY)
4745 std::ostringstream os(std::ios_base::binary);
4746 for(std::map<u16, RemoteClient*>::iterator
4747 i = m_clients.begin();
4748 i != m_clients.end(); ++i)
4750 RemoteClient *client = i->second;
4751 assert(client->peer_id == i->first);
4752 if(client->serialization_version == SER_FMT_VER_INVALID)
4755 Player *player = m_env->getPlayer(client->peer_id);
4758 // Get name of player
4759 os<<player->getName()<<" ";
4762 actionstream<<player->getName()<<" "
4763 <<(reason==CDR_TIMEOUT?"times out.":"leaves game.")
4764 <<" List of players: "<<os.str()<<std::endl;
4769 delete m_clients[peer_id];
4770 m_clients.erase(peer_id);
4772 // Send leave chat message to all remaining clients
4773 if(message.length() != 0)
4774 BroadcastChatMessage(message);
4777 void Server::UpdateCrafting(u16 peer_id)
4779 DSTACK(__FUNCTION_NAME);
4781 Player* player = m_env->getPlayer(peer_id);
4784 // Get a preview for crafting
4786 InventoryLocation loc;
4787 loc.setPlayer(player->getName());
4788 getCraftingResult(&player->inventory, preview, false, this);
4789 m_env->getScriptIface()->item_CraftPredict(preview, player->getPlayerSAO(), (&player->inventory)->getList("craft"), loc);
4791 // Put the new preview in
4792 InventoryList *plist = player->inventory.getList("craftpreview");
4794 assert(plist->getSize() >= 1);
4795 plist->changeItem(0, preview);
4798 RemoteClient* Server::getClient(u16 peer_id)
4800 RemoteClient *client = getClientNoEx(peer_id);
4802 throw ClientNotFoundException("Client not found");
4805 RemoteClient* Server::getClientNoEx(u16 peer_id)
4807 std::map<u16, RemoteClient*>::iterator n;
4808 n = m_clients.find(peer_id);
4809 // The client may not exist; clients are immediately removed if their
4810 // access is denied, and this event occurs later then.
4811 if(n == m_clients.end())
4816 std::string Server::getPlayerName(u16 peer_id)
4818 Player *player = m_env->getPlayer(peer_id);
4820 return "[id="+itos(peer_id)+"]";
4821 return player->getName();
4824 PlayerSAO* Server::getPlayerSAO(u16 peer_id)
4826 Player *player = m_env->getPlayer(peer_id);
4829 return player->getPlayerSAO();
4832 std::wstring Server::getStatusString()
4834 std::wostringstream os(std::ios_base::binary);
4837 os<<L"version="<<narrow_to_wide(minetest_version_simple);
4839 os<<L", uptime="<<m_uptime.get();
4841 os<<L", max_lag="<<m_env->getMaxLagEstimate();
4842 // Information about clients
4843 std::map<u16, RemoteClient*>::iterator i;
4846 for(i = m_clients.begin(), first = true;
4847 i != m_clients.end(); ++i)
4849 // Get client and check that it is valid
4850 RemoteClient *client = i->second;
4851 assert(client->peer_id == i->first);
4852 if(client->serialization_version == SER_FMT_VER_INVALID)
4855 Player *player = m_env->getPlayer(client->peer_id);
4856 // Get name of player
4857 std::wstring name = L"unknown";
4859 name = narrow_to_wide(player->getName());
4860 // Add name to information string
4868 if(((ServerMap*)(&m_env->getMap()))->isSavingEnabled() == false)
4869 os<<std::endl<<L"# Server: "<<" WARNING: Map saving is disabled.";
4870 if(g_settings->get("motd") != "")
4871 os<<std::endl<<L"# Server: "<<narrow_to_wide(g_settings->get("motd"));
4875 std::set<std::string> Server::getPlayerEffectivePrivs(const std::string &name)
4877 std::set<std::string> privs;
4878 m_script->getAuth(name, NULL, &privs);
4882 bool Server::checkPriv(const std::string &name, const std::string &priv)
4884 std::set<std::string> privs = getPlayerEffectivePrivs(name);
4885 return (privs.count(priv) != 0);
4888 void Server::reportPrivsModified(const std::string &name)
4891 for(std::map<u16, RemoteClient*>::iterator
4892 i = m_clients.begin();
4893 i != m_clients.end(); ++i){
4894 RemoteClient *client = i->second;
4895 Player *player = m_env->getPlayer(client->peer_id);
4896 reportPrivsModified(player->getName());
4899 Player *player = m_env->getPlayer(name.c_str());
4902 SendPlayerPrivileges(player->peer_id);
4903 PlayerSAO *sao = player->getPlayerSAO();
4906 sao->updatePrivileges(
4907 getPlayerEffectivePrivs(name),
4912 void Server::reportInventoryFormspecModified(const std::string &name)
4914 Player *player = m_env->getPlayer(name.c_str());
4917 SendPlayerInventoryFormspec(player->peer_id);
4920 void Server::setIpBanned(const std::string &ip, const std::string &name)
4922 m_banmanager->add(ip, name);
4925 void Server::unsetIpBanned(const std::string &ip_or_name)
4927 m_banmanager->remove(ip_or_name);
4930 std::string Server::getBanDescription(const std::string &ip_or_name)
4932 return m_banmanager->getBanDescription(ip_or_name);
4935 void Server::notifyPlayer(const char *name, const std::wstring msg, const bool prepend = true)
4937 Player *player = m_env->getPlayer(name);
4941 SendChatMessage(player->peer_id, std::wstring(L"Server -!- ")+msg);
4943 SendChatMessage(player->peer_id, msg);
4946 bool Server::showFormspec(const char *playername, const std::string &formspec, const std::string &formname)
4948 Player *player = m_env->getPlayer(playername);
4952 infostream<<"showFormspec: couldn't find player:"<<playername<<std::endl;
4956 SendShowFormspecMessage(player->peer_id, formspec, formname);
4960 u32 Server::hudAdd(Player *player, HudElement *form) {
4964 u32 id = player->getFreeHudID();
4965 if (id < player->hud.size())
4966 player->hud[id] = form;
4968 player->hud.push_back(form);
4970 SendHUDAdd(player->peer_id, id, form);
4974 bool Server::hudRemove(Player *player, u32 id) {
4975 if (!player || id >= player->hud.size() || !player->hud[id])
4978 delete player->hud[id];
4979 player->hud[id] = NULL;
4981 SendHUDRemove(player->peer_id, id);
4985 bool Server::hudChange(Player *player, u32 id, HudElementStat stat, void *data) {
4989 SendHUDChange(player->peer_id, id, stat, data);
4993 bool Server::hudSetFlags(Player *player, u32 flags, u32 mask) {
4997 SendHUDSetFlags(player->peer_id, flags, mask);
5001 bool Server::hudSetHotbarItemcount(Player *player, s32 hotbar_itemcount) {
5004 if (hotbar_itemcount <= 0 || hotbar_itemcount > HUD_HOTBAR_ITEMCOUNT_MAX)
5007 std::ostringstream os(std::ios::binary);
5008 writeS32(os, hotbar_itemcount);
5009 SendHUDSetParam(player->peer_id, HUD_PARAM_HOTBAR_ITEMCOUNT, os.str());
5013 void Server::hudSetHotbarImage(Player *player, std::string name) {
5017 SendHUDSetParam(player->peer_id, HUD_PARAM_HOTBAR_IMAGE, name);
5020 void Server::hudSetHotbarSelectedImage(Player *player, std::string name) {
5024 SendHUDSetParam(player->peer_id, HUD_PARAM_HOTBAR_SELECTED_IMAGE, name);
5027 void Server::notifyPlayers(const std::wstring msg)
5029 BroadcastChatMessage(msg);
5032 void Server::spawnParticle(const char *playername, v3f pos,
5033 v3f velocity, v3f acceleration,
5034 float expirationtime, float size, bool
5035 collisiondetection, std::string texture)
5037 Player *player = m_env->getPlayer(playername);
5040 SendSpawnParticle(player->peer_id, pos, velocity, acceleration,
5041 expirationtime, size, collisiondetection, texture);
5044 void Server::spawnParticleAll(v3f pos, v3f velocity, v3f acceleration,
5045 float expirationtime, float size,
5046 bool collisiondetection, std::string texture)
5048 SendSpawnParticleAll(pos, velocity, acceleration,
5049 expirationtime, size, collisiondetection, texture);
5052 u32 Server::addParticleSpawner(const char *playername,
5053 u16 amount, float spawntime,
5054 v3f minpos, v3f maxpos,
5055 v3f minvel, v3f maxvel,
5056 v3f minacc, v3f maxacc,
5057 float minexptime, float maxexptime,
5058 float minsize, float maxsize,
5059 bool collisiondetection, std::string texture)
5061 Player *player = m_env->getPlayer(playername);
5066 for(;;) // look for unused particlespawner id
5069 if (std::find(m_particlespawner_ids.begin(),
5070 m_particlespawner_ids.end(), id)
5071 == m_particlespawner_ids.end())
5073 m_particlespawner_ids.push_back(id);
5078 SendAddParticleSpawner(player->peer_id, amount, spawntime,
5079 minpos, maxpos, minvel, maxvel, minacc, maxacc,
5080 minexptime, maxexptime, minsize, maxsize,
5081 collisiondetection, texture, id);
5086 u32 Server::addParticleSpawnerAll(u16 amount, float spawntime,
5087 v3f minpos, v3f maxpos,
5088 v3f minvel, v3f maxvel,
5089 v3f minacc, v3f maxacc,
5090 float minexptime, float maxexptime,
5091 float minsize, float maxsize,
5092 bool collisiondetection, std::string texture)
5095 for(;;) // look for unused particlespawner id
5098 if (std::find(m_particlespawner_ids.begin(),
5099 m_particlespawner_ids.end(), id)
5100 == m_particlespawner_ids.end())
5102 m_particlespawner_ids.push_back(id);
5107 SendAddParticleSpawnerAll(amount, spawntime,
5108 minpos, maxpos, minvel, maxvel, minacc, maxacc,
5109 minexptime, maxexptime, minsize, maxsize,
5110 collisiondetection, texture, id);
5115 void Server::deleteParticleSpawner(const char *playername, u32 id)
5117 Player *player = m_env->getPlayer(playername);
5121 m_particlespawner_ids.erase(
5122 std::remove(m_particlespawner_ids.begin(),
5123 m_particlespawner_ids.end(), id),
5124 m_particlespawner_ids.end());
5125 SendDeleteParticleSpawner(player->peer_id, id);
5128 void Server::deleteParticleSpawnerAll(u32 id)
5130 m_particlespawner_ids.erase(
5131 std::remove(m_particlespawner_ids.begin(),
5132 m_particlespawner_ids.end(), id),
5133 m_particlespawner_ids.end());
5134 SendDeleteParticleSpawnerAll(id);
5137 Inventory* Server::createDetachedInventory(const std::string &name)
5139 if(m_detached_inventories.count(name) > 0){
5140 infostream<<"Server clearing detached inventory \""<<name<<"\""<<std::endl;
5141 delete m_detached_inventories[name];
5143 infostream<<"Server creating detached inventory \""<<name<<"\""<<std::endl;
5145 Inventory *inv = new Inventory(m_itemdef);
5147 m_detached_inventories[name] = inv;
5148 sendDetachedInventoryToAll(name);
5155 BoolScopeSet(bool *dst, bool val):
5158 m_orig_state = *m_dst;
5163 *m_dst = m_orig_state;
5170 // actions: time-reversed list
5171 // Return value: success/failure
5172 bool Server::rollbackRevertActions(const std::list<RollbackAction> &actions,
5173 std::list<std::string> *log)
5175 infostream<<"Server::rollbackRevertActions(len="<<actions.size()<<")"<<std::endl;
5176 ServerMap *map = (ServerMap*)(&m_env->getMap());
5177 // Disable rollback report sink while reverting
5178 BoolScopeSet rollback_scope_disable(&m_rollback_sink_enabled, false);
5180 // Fail if no actions to handle
5181 if(actions.empty()){
5182 log->push_back("Nothing to do.");
5189 for(std::list<RollbackAction>::const_iterator
5190 i = actions.begin();
5191 i != actions.end(); i++)
5193 const RollbackAction &action = *i;
5195 bool success = action.applyRevert(map, this, this);
5198 std::ostringstream os;
5199 os<<"Revert of step ("<<num_tried<<") "<<action.toString()<<" failed";
5200 infostream<<"Map::rollbackRevertActions(): "<<os.str()<<std::endl;
5202 log->push_back(os.str());
5204 std::ostringstream os;
5205 os<<"Successfully reverted step ("<<num_tried<<") "<<action.toString();
5206 infostream<<"Map::rollbackRevertActions(): "<<os.str()<<std::endl;
5208 log->push_back(os.str());
5212 infostream<<"Map::rollbackRevertActions(): "<<num_failed<<"/"<<num_tried
5213 <<" failed"<<std::endl;
5215 // Call it done if less than half failed
5216 return num_failed <= num_tried/2;
5219 // IGameDef interface
5221 IItemDefManager* Server::getItemDefManager()
5225 INodeDefManager* Server::getNodeDefManager()
5229 ICraftDefManager* Server::getCraftDefManager()
5233 ITextureSource* Server::getTextureSource()
5237 IShaderSource* Server::getShaderSource()
5241 u16 Server::allocateUnknownNodeId(const std::string &name)
5243 return m_nodedef->allocateDummy(name);
5245 ISoundManager* Server::getSoundManager()
5247 return &dummySoundManager;
5249 MtEventManager* Server::getEventManager()
5253 IRollbackReportSink* Server::getRollbackReportSink()
5255 if(!m_enable_rollback_recording)
5257 if(!m_rollback_sink_enabled)
5262 IWritableItemDefManager* Server::getWritableItemDefManager()
5266 IWritableNodeDefManager* Server::getWritableNodeDefManager()
5270 IWritableCraftDefManager* Server::getWritableCraftDefManager()
5275 const ModSpec* Server::getModSpec(const std::string &modname)
5277 for(std::vector<ModSpec>::iterator i = m_mods.begin();
5278 i != m_mods.end(); i++){
5279 const ModSpec &mod = *i;
5280 if(mod.name == modname)
5285 void Server::getModNames(std::list<std::string> &modlist)
5287 for(std::vector<ModSpec>::iterator i = m_mods.begin(); i != m_mods.end(); i++)
5289 modlist.push_back(i->name);
5292 std::string Server::getBuiltinLuaPath()
5294 return porting::path_share + DIR_DELIM + "builtin";
5297 v3f findSpawnPos(ServerMap &map)
5299 //return v3f(50,50,50)*BS;
5304 nodepos = v2s16(0,0);
5309 s16 water_level = map.m_mgparams->water_level;
5311 // Try to find a good place a few times
5312 for(s32 i=0; i<1000; i++)
5315 // We're going to try to throw the player to this position
5316 v2s16 nodepos2d = v2s16(
5317 -range + (myrand() % (range * 2)),
5318 -range + (myrand() % (range * 2)));
5320 // Get ground height at point
5321 s16 groundheight = map.findGroundLevel(nodepos2d);
5322 if (groundheight <= water_level) // Don't go underwater
5324 if (groundheight > water_level + 6) // Don't go to high places
5327 nodepos = v3s16(nodepos2d.X, groundheight, nodepos2d.Y);
5328 bool is_good = false;
5330 for (s32 i = 0; i < 10; i++) {
5331 v3s16 blockpos = getNodeBlockPos(nodepos);
5332 map.emergeBlock(blockpos, true);
5333 content_t c = map.getNodeNoEx(nodepos).getContent();
5334 if (c == CONTENT_AIR || c == CONTENT_IGNORE) {
5336 if (air_count >= 2){
5344 // Found a good place
5345 //infostream<<"Searched through "<<i<<" places."<<std::endl;
5351 return intToFloat(nodepos, BS);
5354 PlayerSAO* Server::emergePlayer(const char *name, u16 peer_id)
5356 RemotePlayer *player = NULL;
5357 bool newplayer = false;
5360 Try to get an existing player
5362 player = static_cast<RemotePlayer*>(m_env->getPlayer(name));
5364 // If player is already connected, cancel
5365 if(player != NULL && player->peer_id != 0)
5367 infostream<<"emergePlayer(): Player already connected"<<std::endl;
5372 If player with the wanted peer_id already exists, cancel.
5374 if(m_env->getPlayer(peer_id) != NULL)
5376 infostream<<"emergePlayer(): Player with wrong name but same"
5377 " peer_id already exists"<<std::endl;
5382 Create a new player if it doesn't exist yet
5387 player = new RemotePlayer(this);
5388 player->updateName(name);
5390 /* Set player position */
5391 infostream<<"Server: Finding spawn place for player \""
5392 <<name<<"\""<<std::endl;
5393 v3f pos = findSpawnPos(m_env->getServerMap());
5394 player->setPosition(pos);
5396 /* Add player to environment */
5397 m_env->addPlayer(player);
5401 Create a new player active object
5403 PlayerSAO *playersao = new PlayerSAO(m_env, player, peer_id,
5404 getPlayerEffectivePrivs(player->getName()),
5407 /* Clean up old HUD elements from previous sessions */
5408 player->hud.clear();
5410 /* Add object to environment */
5411 m_env->addActiveObject(playersao);
5415 m_script->on_newplayer(playersao);
5417 m_script->on_joinplayer(playersao);
5422 void Server::handlePeerChange(PeerChange &c)
5424 JMutexAutoLock envlock(m_env_mutex);
5425 JMutexAutoLock conlock(m_con_mutex);
5427 if(c.type == PEER_ADDED)
5434 std::map<u16, RemoteClient*>::iterator n;
5435 n = m_clients.find(c.peer_id);
5436 // The client shouldn't already exist
5437 assert(n == m_clients.end());
5440 RemoteClient *client = new RemoteClient();
5441 client->peer_id = c.peer_id;
5442 m_clients[client->peer_id] = client;
5445 else if(c.type == PEER_REMOVED)
5451 DeleteClient(c.peer_id, c.timeout?CDR_TIMEOUT:CDR_LEAVE);
5460 void Server::handlePeerChanges()
5462 while(m_peer_change_queue.size() > 0)
5464 PeerChange c = m_peer_change_queue.pop_front();
5466 verbosestream<<"Server: Handling peer change: "
5467 <<"id="<<c.peer_id<<", timeout="<<c.timeout
5470 handlePeerChange(c);
5474 void dedicated_server_loop(Server &server, bool &kill)
5476 DSTACK(__FUNCTION_NAME);
5478 verbosestream<<"dedicated_server_loop()"<<std::endl;
5480 IntervalLimiter m_profiler_interval;
5484 float steplen = g_settings->getFloat("dedicated_server_step");
5485 // This is kind of a hack but can be done like this
5486 // because server.step() is very light
5488 ScopeProfiler sp(g_profiler, "dedicated server sleep");
5489 sleep_ms((int)(steplen*1000.0));
5491 server.step(steplen);
5493 if(server.getShutdownRequested() || kill)
5495 infostream<<"Dedicated server quitting"<<std::endl;
5497 if(g_settings->getBool("server_announce") == true)
5498 ServerList::sendAnnounce("delete");
5506 float profiler_print_interval =
5507 g_settings->getFloat("profiler_print_interval");
5508 if(profiler_print_interval != 0)
5510 if(m_profiler_interval.step(steplen, profiler_print_interval))
5512 infostream<<"Profiler:"<<std::endl;
5513 g_profiler->print(infostream);
5514 g_profiler->clear();