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;*/
2292 else if(command == TOSERVER_GOTBLOCKS)
2305 u16 count = data[2];
2306 for(u16 i=0; i<count; i++)
2308 if((s16)datasize < 2+1+(i+1)*6)
2309 throw con::InvalidIncomingDataException
2310 ("GOTBLOCKS length is too short");
2311 v3s16 p = readV3S16(&data[2+1+i*6]);
2312 /*infostream<<"Server: GOTBLOCKS ("
2313 <<p.X<<","<<p.Y<<","<<p.Z<<")"<<std::endl;*/
2314 RemoteClient *client = getClient(peer_id);
2315 client->GotBlock(p);
2318 else if(command == TOSERVER_DELETEDBLOCKS)
2331 u16 count = data[2];
2332 for(u16 i=0; i<count; i++)
2334 if((s16)datasize < 2+1+(i+1)*6)
2335 throw con::InvalidIncomingDataException
2336 ("DELETEDBLOCKS length is too short");
2337 v3s16 p = readV3S16(&data[2+1+i*6]);
2338 /*infostream<<"Server: DELETEDBLOCKS ("
2339 <<p.X<<","<<p.Y<<","<<p.Z<<")"<<std::endl;*/
2340 RemoteClient *client = getClient(peer_id);
2341 client->SetBlockNotSent(p);
2344 else if(command == TOSERVER_CLICK_OBJECT)
2346 infostream<<"Server: CLICK_OBJECT not supported anymore"<<std::endl;
2349 else if(command == TOSERVER_CLICK_ACTIVEOBJECT)
2351 infostream<<"Server: CLICK_ACTIVEOBJECT not supported anymore"<<std::endl;
2354 else if(command == TOSERVER_GROUND_ACTION)
2356 infostream<<"Server: GROUND_ACTION not supported anymore"<<std::endl;
2360 else if(command == TOSERVER_RELEASE)
2362 infostream<<"Server: RELEASE not supported anymore"<<std::endl;
2365 else if(command == TOSERVER_SIGNTEXT)
2367 infostream<<"Server: SIGNTEXT not supported anymore"
2371 else if(command == TOSERVER_SIGNNODETEXT)
2373 infostream<<"Server: SIGNNODETEXT not supported anymore"
2377 else if(command == TOSERVER_INVENTORY_ACTION)
2379 // Strip command and create a stream
2380 std::string datastring((char*)&data[2], datasize-2);
2381 verbosestream<<"TOSERVER_INVENTORY_ACTION: data="<<datastring<<std::endl;
2382 std::istringstream is(datastring, std::ios_base::binary);
2384 InventoryAction *a = InventoryAction::deSerialize(is);
2387 infostream<<"TOSERVER_INVENTORY_ACTION: "
2388 <<"InventoryAction::deSerialize() returned NULL"
2393 // If something goes wrong, this player is to blame
2394 RollbackScopeActor rollback_scope(m_rollback,
2395 std::string("player:")+player->getName());
2398 Note: Always set inventory not sent, to repair cases
2399 where the client made a bad prediction.
2403 Handle restrictions and special cases of the move action
2405 if(a->getType() == IACTION_MOVE)
2407 IMoveAction *ma = (IMoveAction*)a;
2409 ma->from_inv.applyCurrentPlayer(player->getName());
2410 ma->to_inv.applyCurrentPlayer(player->getName());
2412 setInventoryModified(ma->from_inv);
2413 setInventoryModified(ma->to_inv);
2415 bool from_inv_is_current_player =
2416 (ma->from_inv.type == InventoryLocation::PLAYER) &&
2417 (ma->from_inv.name == player->getName());
2419 bool to_inv_is_current_player =
2420 (ma->to_inv.type == InventoryLocation::PLAYER) &&
2421 (ma->to_inv.name == player->getName());
2424 Disable moving items out of craftpreview
2426 if(ma->from_list == "craftpreview")
2428 infostream<<"Ignoring IMoveAction from "
2429 <<(ma->from_inv.dump())<<":"<<ma->from_list
2430 <<" to "<<(ma->to_inv.dump())<<":"<<ma->to_list
2431 <<" because src is "<<ma->from_list<<std::endl;
2437 Disable moving items into craftresult and craftpreview
2439 if(ma->to_list == "craftpreview" || ma->to_list == "craftresult")
2441 infostream<<"Ignoring IMoveAction from "
2442 <<(ma->from_inv.dump())<<":"<<ma->from_list
2443 <<" to "<<(ma->to_inv.dump())<<":"<<ma->to_list
2444 <<" because dst is "<<ma->to_list<<std::endl;
2449 // Disallow moving items in elsewhere than player's inventory
2450 // if not allowed to interact
2451 if(!checkPriv(player->getName(), "interact") &&
2452 (!from_inv_is_current_player ||
2453 !to_inv_is_current_player))
2455 infostream<<"Cannot move outside of player's inventory: "
2456 <<"No interact privilege"<<std::endl;
2462 Handle restrictions and special cases of the drop action
2464 else if(a->getType() == IACTION_DROP)
2466 IDropAction *da = (IDropAction*)a;
2468 da->from_inv.applyCurrentPlayer(player->getName());
2470 setInventoryModified(da->from_inv);
2473 Disable dropping items out of craftpreview
2475 if(da->from_list == "craftpreview")
2477 infostream<<"Ignoring IDropAction from "
2478 <<(da->from_inv.dump())<<":"<<da->from_list
2479 <<" because src is "<<da->from_list<<std::endl;
2484 // Disallow dropping items if not allowed to interact
2485 if(!checkPriv(player->getName(), "interact"))
2492 Handle restrictions and special cases of the craft action
2494 else if(a->getType() == IACTION_CRAFT)
2496 ICraftAction *ca = (ICraftAction*)a;
2498 ca->craft_inv.applyCurrentPlayer(player->getName());
2500 setInventoryModified(ca->craft_inv);
2502 //bool craft_inv_is_current_player =
2503 // (ca->craft_inv.type == InventoryLocation::PLAYER) &&
2504 // (ca->craft_inv.name == player->getName());
2506 // Disallow crafting if not allowed to interact
2507 if(!checkPriv(player->getName(), "interact"))
2509 infostream<<"Cannot craft: "
2510 <<"No interact privilege"<<std::endl;
2517 a->apply(this, playersao, this);
2521 else if(command == TOSERVER_CHAT_MESSAGE)
2529 std::string datastring((char*)&data[2], datasize-2);
2530 std::istringstream is(datastring, std::ios_base::binary);
2533 is.read((char*)buf, 2);
2534 u16 len = readU16(buf);
2536 std::wstring message;
2537 for(u16 i=0; i<len; i++)
2539 is.read((char*)buf, 2);
2540 message += (wchar_t)readU16(buf);
2543 // If something goes wrong, this player is to blame
2544 RollbackScopeActor rollback_scope(m_rollback,
2545 std::string("player:")+player->getName());
2547 // Get player name of this client
2548 std::wstring name = narrow_to_wide(player->getName());
2551 bool ate = m_script->on_chat_message(player->getName(),
2552 wide_to_narrow(message));
2553 // If script ate the message, don't proceed
2557 // Line to send to players
2559 // Whether to send to the player that sent the line
2560 bool send_to_sender = false;
2561 // Whether to send to other players
2562 bool send_to_others = false;
2564 // Commands are implemented in Lua, so only catch invalid
2565 // commands that were not "eaten" and send an error back
2566 if(message[0] == L'/')
2568 message = message.substr(1);
2569 send_to_sender = true;
2570 if(message.length() == 0)
2571 line += L"-!- Empty command";
2573 line += L"-!- Invalid command: " + str_split(message, L' ')[0];
2577 if(checkPriv(player->getName(), "shout")){
2582 send_to_others = true;
2584 line += L"-!- You don't have permission to shout.";
2585 send_to_sender = true;
2592 actionstream<<"CHAT: "<<wide_to_narrow(line)<<std::endl;
2595 Send the message to clients
2597 for(std::map<u16, RemoteClient*>::iterator
2598 i = m_clients.begin();
2599 i != m_clients.end(); ++i)
2601 // Get client and check that it is valid
2602 RemoteClient *client = i->second;
2603 assert(client->peer_id == i->first);
2604 if(client->serialization_version == SER_FMT_VER_INVALID)
2608 bool sender_selected = (peer_id == client->peer_id);
2609 if(sender_selected == true && send_to_sender == false)
2611 if(sender_selected == false && send_to_others == false)
2614 SendChatMessage(client->peer_id, line);
2618 else if(command == TOSERVER_DAMAGE)
2620 std::string datastring((char*)&data[2], datasize-2);
2621 std::istringstream is(datastring, std::ios_base::binary);
2622 u8 damage = readU8(is);
2624 if(g_settings->getBool("enable_damage"))
2626 actionstream<<player->getName()<<" damaged by "
2627 <<(int)damage<<" hp at "<<PP(player->getPosition()/BS)
2630 playersao->setHP(playersao->getHP() - damage);
2632 if(playersao->getHP() == 0 && playersao->m_hp_not_sent)
2635 if(playersao->m_hp_not_sent)
2636 SendPlayerHP(peer_id);
2639 else if(command == TOSERVER_BREATH)
2641 std::string datastring((char*)&data[2], datasize-2);
2642 std::istringstream is(datastring, std::ios_base::binary);
2643 u16 breath = readU16(is);
2644 playersao->setBreath(breath);
2646 else if(command == TOSERVER_PASSWORD)
2649 [0] u16 TOSERVER_PASSWORD
2650 [2] u8[28] old password
2651 [30] u8[28] new password
2654 if(datasize != 2+PASSWORD_SIZE*2)
2656 /*char password[PASSWORD_SIZE];
2657 for(u32 i=0; i<PASSWORD_SIZE-1; i++)
2658 password[i] = data[2+i];
2659 password[PASSWORD_SIZE-1] = 0;*/
2661 for(u32 i=0; i<PASSWORD_SIZE-1; i++)
2669 for(u32 i=0; i<PASSWORD_SIZE-1; i++)
2671 char c = data[2+PASSWORD_SIZE+i];
2677 if(!base64_is_valid(newpwd)){
2678 infostream<<"Server: "<<player->getName()<<" supplied invalid password hash"<<std::endl;
2679 // Wrong old password supplied!!
2680 SendChatMessage(peer_id, L"Invalid new password hash supplied. Password NOT changed.");
2684 infostream<<"Server: Client requests a password change from "
2685 <<"'"<<oldpwd<<"' to '"<<newpwd<<"'"<<std::endl;
2687 std::string playername = player->getName();
2689 std::string checkpwd;
2690 m_script->getAuth(playername, &checkpwd, NULL);
2692 if(oldpwd != checkpwd)
2694 infostream<<"Server: invalid old password"<<std::endl;
2695 // Wrong old password supplied!!
2696 SendChatMessage(peer_id, L"Invalid old password supplied. Password NOT changed.");
2700 bool success = m_script->setPassword(playername, newpwd);
2702 actionstream<<player->getName()<<" changes password"<<std::endl;
2703 SendChatMessage(peer_id, L"Password change successful.");
2705 actionstream<<player->getName()<<" tries to change password but "
2706 <<"it fails"<<std::endl;
2707 SendChatMessage(peer_id, L"Password change failed or inavailable.");
2710 else if(command == TOSERVER_PLAYERITEM)
2715 u16 item = readU16(&data[2]);
2716 playersao->setWieldIndex(item);
2718 else if(command == TOSERVER_RESPAWN)
2720 if(player->hp != 0 || !g_settings->getBool("enable_damage"))
2723 RespawnPlayer(peer_id);
2725 actionstream<<player->getName()<<" respawns at "
2726 <<PP(player->getPosition()/BS)<<std::endl;
2728 // ActiveObject is added to environment in AsyncRunStep after
2729 // the previous addition has been succesfully removed
2731 else if(command == TOSERVER_REQUEST_MEDIA) {
2732 std::string datastring((char*)&data[2], datasize-2);
2733 std::istringstream is(datastring, std::ios_base::binary);
2735 std::list<MediaRequest> tosend;
2736 u16 numfiles = readU16(is);
2738 infostream<<"Sending "<<numfiles<<" files to "
2739 <<getPlayerName(peer_id)<<std::endl;
2740 verbosestream<<"TOSERVER_REQUEST_MEDIA: "<<std::endl;
2742 for(int i = 0; i < numfiles; i++) {
2743 std::string name = deSerializeString(is);
2744 tosend.push_back(MediaRequest(name));
2745 verbosestream<<"TOSERVER_REQUEST_MEDIA: requested file "
2749 sendRequestedMedia(peer_id, tosend);
2751 // Now the client should know about everything
2752 // (definitions and files)
2753 getClient(peer_id)->definitions_sent = true;
2755 else if(command == TOSERVER_RECEIVED_MEDIA) {
2756 getClient(peer_id)->definitions_sent = true;
2758 else if(command == TOSERVER_INTERACT)
2760 std::string datastring((char*)&data[2], datasize-2);
2761 std::istringstream is(datastring, std::ios_base::binary);
2767 [5] u32 length of the next item
2768 [9] serialized PointedThing
2770 0: start digging (from undersurface) or use
2771 1: stop digging (all parameters ignored)
2772 2: digging completed
2773 3: place block or item (to abovesurface)
2776 u8 action = readU8(is);
2777 u16 item_i = readU16(is);
2778 std::istringstream tmp_is(deSerializeLongString(is), std::ios::binary);
2779 PointedThing pointed;
2780 pointed.deSerialize(tmp_is);
2782 verbosestream<<"TOSERVER_INTERACT: action="<<(int)action<<", item="
2783 <<item_i<<", pointed="<<pointed.dump()<<std::endl;
2787 verbosestream<<"TOSERVER_INTERACT: "<<player->getName()
2788 <<" tried to interact, but is dead!"<<std::endl;
2792 v3f player_pos = playersao->getLastGoodPosition();
2794 // Update wielded item
2795 playersao->setWieldIndex(item_i);
2797 // Get pointed to node (undefined if not POINTEDTYPE_NODE)
2798 v3s16 p_under = pointed.node_undersurface;
2799 v3s16 p_above = pointed.node_abovesurface;
2801 // Get pointed to object (NULL if not POINTEDTYPE_OBJECT)
2802 ServerActiveObject *pointed_object = NULL;
2803 if(pointed.type == POINTEDTHING_OBJECT)
2805 pointed_object = m_env->getActiveObject(pointed.object_id);
2806 if(pointed_object == NULL)
2808 verbosestream<<"TOSERVER_INTERACT: "
2809 "pointed object is NULL"<<std::endl;
2815 v3f pointed_pos_under = player_pos;
2816 v3f pointed_pos_above = player_pos;
2817 if(pointed.type == POINTEDTHING_NODE)
2819 pointed_pos_under = intToFloat(p_under, BS);
2820 pointed_pos_above = intToFloat(p_above, BS);
2822 else if(pointed.type == POINTEDTHING_OBJECT)
2824 pointed_pos_under = pointed_object->getBasePosition();
2825 pointed_pos_above = pointed_pos_under;
2829 Check that target is reasonably close
2830 (only when digging or placing things)
2832 if(action == 0 || action == 2 || action == 3)
2834 float d = player_pos.getDistanceFrom(pointed_pos_under);
2835 float max_d = BS * 14; // Just some large enough value
2837 actionstream<<"Player "<<player->getName()
2838 <<" tried to access "<<pointed.dump()
2840 <<"d="<<d<<", max_d="<<max_d
2841 <<". ignoring."<<std::endl;
2842 // Re-send block to revert change on client-side
2843 RemoteClient *client = getClient(peer_id);
2844 v3s16 blockpos = getNodeBlockPos(floatToInt(pointed_pos_under, BS));
2845 client->SetBlockNotSent(blockpos);
2847 m_script->on_cheat(playersao, "interacted_too_far");
2854 Make sure the player is allowed to do it
2856 if(!checkPriv(player->getName(), "interact"))
2858 actionstream<<player->getName()<<" attempted to interact with "
2859 <<pointed.dump()<<" without 'interact' privilege"
2861 // Re-send block to revert change on client-side
2862 RemoteClient *client = getClient(peer_id);
2863 // Digging completed -> under
2865 v3s16 blockpos = getNodeBlockPos(floatToInt(pointed_pos_under, BS));
2866 client->SetBlockNotSent(blockpos);
2868 // Placement -> above
2870 v3s16 blockpos = getNodeBlockPos(floatToInt(pointed_pos_above, BS));
2871 client->SetBlockNotSent(blockpos);
2877 If something goes wrong, this player is to blame
2879 RollbackScopeActor rollback_scope(m_rollback,
2880 std::string("player:")+player->getName());
2883 0: start digging or punch object
2887 if(pointed.type == POINTEDTHING_NODE)
2890 NOTE: This can be used in the future to check if
2891 somebody is cheating, by checking the timing.
2893 MapNode n(CONTENT_IGNORE);
2896 n = m_env->getMap().getNode(p_under);
2898 catch(InvalidPositionException &e)
2900 infostream<<"Server: Not punching: Node not found."
2901 <<" Adding block to emerge queue."
2903 m_emerge->enqueueBlockEmerge(peer_id, getNodeBlockPos(p_above), false);
2905 if(n.getContent() != CONTENT_IGNORE)
2906 m_script->node_on_punch(p_under, n, playersao);
2908 playersao->noCheatDigStart(p_under);
2910 else if(pointed.type == POINTEDTHING_OBJECT)
2912 // Skip if object has been removed
2913 if(pointed_object->m_removed)
2916 actionstream<<player->getName()<<" punches object "
2917 <<pointed.object_id<<": "
2918 <<pointed_object->getDescription()<<std::endl;
2920 ItemStack punchitem = playersao->getWieldedItem();
2921 ToolCapabilities toolcap =
2922 punchitem.getToolCapabilities(m_itemdef);
2923 v3f dir = (pointed_object->getBasePosition() -
2924 (player->getPosition() + player->getEyeOffset())
2926 float time_from_last_punch =
2927 playersao->resetTimeFromLastPunch();
2928 pointed_object->punch(dir, &toolcap, playersao,
2929 time_from_last_punch);
2937 else if(action == 1)
2942 2: Digging completed
2944 else if(action == 2)
2946 // Only digging of nodes
2947 if(pointed.type == POINTEDTHING_NODE)
2949 MapNode n(CONTENT_IGNORE);
2952 n = m_env->getMap().getNode(p_under);
2954 catch(InvalidPositionException &e)
2956 infostream<<"Server: Not finishing digging: Node not found."
2957 <<" Adding block to emerge queue."
2959 m_emerge->enqueueBlockEmerge(peer_id, getNodeBlockPos(p_above), false);
2962 /* Cheat prevention */
2963 bool is_valid_dig = true;
2964 if(!isSingleplayer() && !g_settings->getBool("disable_anticheat"))
2966 v3s16 nocheat_p = playersao->getNoCheatDigPos();
2967 float nocheat_t = playersao->getNoCheatDigTime();
2968 playersao->noCheatDigEnd();
2969 // If player didn't start digging this, ignore dig
2970 if(nocheat_p != p_under){
2971 infostream<<"Server: NoCheat: "<<player->getName()
2972 <<" started digging "
2973 <<PP(nocheat_p)<<" and completed digging "
2974 <<PP(p_under)<<"; not digging."<<std::endl;
2975 is_valid_dig = false;
2977 m_script->on_cheat(playersao, "finished_unknown_dig");
2979 // Get player's wielded item
2980 ItemStack playeritem;
2981 InventoryList *mlist = playersao->getInventory()->getList("main");
2983 playeritem = mlist->getItem(playersao->getWieldIndex());
2984 ToolCapabilities playeritem_toolcap =
2985 playeritem.getToolCapabilities(m_itemdef);
2986 // Get diggability and expected digging time
2987 DigParams params = getDigParams(m_nodedef->get(n).groups,
2988 &playeritem_toolcap);
2989 // If can't dig, try hand
2990 if(!params.diggable){
2991 const ItemDefinition &hand = m_itemdef->get("");
2992 const ToolCapabilities *tp = hand.tool_capabilities;
2994 params = getDigParams(m_nodedef->get(n).groups, tp);
2996 // If can't dig, ignore dig
2997 if(!params.diggable){
2998 infostream<<"Server: NoCheat: "<<player->getName()
2999 <<" completed digging "<<PP(p_under)
3000 <<", which is not diggable with tool. not digging."
3002 is_valid_dig = false;
3004 m_script->on_cheat(playersao, "dug_unbreakable");
3006 // Check digging time
3007 // If already invalidated, we don't have to
3009 // Well not our problem then
3011 // Clean and long dig
3012 else if(params.time > 2.0 && nocheat_t * 1.2 > params.time){
3013 // All is good, but grab time from pool; don't care if
3014 // it's actually available
3015 playersao->getDigPool().grab(params.time);
3017 // Short or laggy dig
3018 // Try getting the time from pool
3019 else if(playersao->getDigPool().grab(params.time)){
3024 infostream<<"Server: NoCheat: "<<player->getName()
3025 <<" completed digging "<<PP(p_under)
3026 <<"too fast; not digging."<<std::endl;
3027 is_valid_dig = false;
3029 m_script->on_cheat(playersao, "dug_too_fast");
3033 /* Actually dig node */
3035 if(is_valid_dig && n.getContent() != CONTENT_IGNORE)
3036 m_script->node_on_dig(p_under, n, playersao);
3038 // Send unusual result (that is, node not being removed)
3039 if(m_env->getMap().getNodeNoEx(p_under).getContent() != CONTENT_AIR)
3041 // Re-send block to revert change on client-side
3042 RemoteClient *client = getClient(peer_id);
3043 v3s16 blockpos = getNodeBlockPos(floatToInt(pointed_pos_under, BS));
3044 client->SetBlockNotSent(blockpos);
3050 3: place block or right-click object
3052 else if(action == 3)
3054 ItemStack item = playersao->getWieldedItem();
3056 // Reset build time counter
3057 if(pointed.type == POINTEDTHING_NODE &&
3058 item.getDefinition(m_itemdef).type == ITEM_NODE)
3059 getClient(peer_id)->m_time_from_building = 0.0;
3061 if(pointed.type == POINTEDTHING_OBJECT)
3063 // Right click object
3065 // Skip if object has been removed
3066 if(pointed_object->m_removed)
3069 actionstream<<player->getName()<<" right-clicks object "
3070 <<pointed.object_id<<": "
3071 <<pointed_object->getDescription()<<std::endl;
3074 pointed_object->rightClick(playersao);
3076 else if(m_script->item_OnPlace(
3077 item, playersao, pointed))
3079 // Placement was handled in lua
3081 // Apply returned ItemStack
3082 playersao->setWieldedItem(item);
3085 // If item has node placement prediction, always send the
3086 // blocks to make sure the client knows what exactly happened
3087 if(item.getDefinition(m_itemdef).node_placement_prediction != ""){
3088 RemoteClient *client = getClient(peer_id);
3089 v3s16 blockpos = getNodeBlockPos(floatToInt(pointed_pos_above, BS));
3090 client->SetBlockNotSent(blockpos);
3091 v3s16 blockpos2 = getNodeBlockPos(floatToInt(pointed_pos_under, BS));
3092 if(blockpos2 != blockpos){
3093 client->SetBlockNotSent(blockpos2);
3101 else if(action == 4)
3103 ItemStack item = playersao->getWieldedItem();
3105 actionstream<<player->getName()<<" uses "<<item.name
3106 <<", pointing at "<<pointed.dump()<<std::endl;
3108 if(m_script->item_OnUse(
3109 item, playersao, pointed))
3111 // Apply returned ItemStack
3112 playersao->setWieldedItem(item);
3119 Catch invalid actions
3123 infostream<<"WARNING: Server: Invalid action "
3124 <<action<<std::endl;
3127 else if(command == TOSERVER_REMOVED_SOUNDS)
3129 std::string datastring((char*)&data[2], datasize-2);
3130 std::istringstream is(datastring, std::ios_base::binary);
3132 int num = readU16(is);
3133 for(int k=0; k<num; k++){
3134 s32 id = readS32(is);
3135 std::map<s32, ServerPlayingSound>::iterator i =
3136 m_playing_sounds.find(id);
3137 if(i == m_playing_sounds.end())
3139 ServerPlayingSound &psound = i->second;
3140 psound.clients.erase(peer_id);
3141 if(psound.clients.size() == 0)
3142 m_playing_sounds.erase(i++);
3145 else if(command == TOSERVER_NODEMETA_FIELDS)
3147 std::string datastring((char*)&data[2], datasize-2);
3148 std::istringstream is(datastring, std::ios_base::binary);
3150 v3s16 p = readV3S16(is);
3151 std::string formname = deSerializeString(is);
3152 int num = readU16(is);
3153 std::map<std::string, std::string> fields;
3154 for(int k=0; k<num; k++){
3155 std::string fieldname = deSerializeString(is);
3156 std::string fieldvalue = deSerializeLongString(is);
3157 fields[fieldname] = fieldvalue;
3160 // If something goes wrong, this player is to blame
3161 RollbackScopeActor rollback_scope(m_rollback,
3162 std::string("player:")+player->getName());
3164 // Check the target node for rollback data; leave others unnoticed
3165 RollbackNode rn_old(&m_env->getMap(), p, this);
3167 m_script->node_on_receive_fields(p, formname, fields,playersao);
3169 // Report rollback data
3170 RollbackNode rn_new(&m_env->getMap(), p, this);
3171 if(rollback() && rn_new != rn_old){
3172 RollbackAction action;
3173 action.setSetNode(p, rn_old, rn_new);
3174 rollback()->reportAction(action);
3177 else if(command == TOSERVER_INVENTORY_FIELDS)
3179 std::string datastring((char*)&data[2], datasize-2);
3180 std::istringstream is(datastring, std::ios_base::binary);
3182 std::string formname = deSerializeString(is);
3183 int num = readU16(is);
3184 std::map<std::string, std::string> fields;
3185 for(int k=0; k<num; k++){
3186 std::string fieldname = deSerializeString(is);
3187 std::string fieldvalue = deSerializeLongString(is);
3188 fields[fieldname] = fieldvalue;
3191 m_script->on_playerReceiveFields(playersao, formname, fields);
3195 infostream<<"Server::ProcessData(): Ignoring "
3196 "unknown command "<<command<<std::endl;
3200 catch(SendFailedException &e)
3202 errorstream<<"Server::ProcessData(): SendFailedException: "
3208 void Server::setTimeOfDay(u32 time)
3210 m_env->setTimeOfDay(time);
3211 m_time_of_day_send_timer = 0;
3214 void Server::onMapEditEvent(MapEditEvent *event)
3216 //infostream<<"Server::onMapEditEvent()"<<std::endl;
3217 if(m_ignore_map_edit_events)
3219 if(m_ignore_map_edit_events_area.contains(event->getArea()))
3221 MapEditEvent *e = event->clone();
3222 m_unsent_map_edit_queue.push_back(e);
3225 Inventory* Server::getInventory(const InventoryLocation &loc)
3228 case InventoryLocation::UNDEFINED:
3231 case InventoryLocation::CURRENT_PLAYER:
3234 case InventoryLocation::PLAYER:
3236 Player *player = m_env->getPlayer(loc.name.c_str());
3239 PlayerSAO *playersao = player->getPlayerSAO();
3242 return playersao->getInventory();
3245 case InventoryLocation::NODEMETA:
3247 NodeMetadata *meta = m_env->getMap().getNodeMetadata(loc.p);
3250 return meta->getInventory();
3253 case InventoryLocation::DETACHED:
3255 if(m_detached_inventories.count(loc.name) == 0)
3257 return m_detached_inventories[loc.name];
3265 void Server::setInventoryModified(const InventoryLocation &loc)
3268 case InventoryLocation::UNDEFINED:
3271 case InventoryLocation::PLAYER:
3273 Player *player = m_env->getPlayer(loc.name.c_str());
3276 PlayerSAO *playersao = player->getPlayerSAO();
3279 playersao->m_inventory_not_sent = true;
3280 playersao->m_wielded_item_not_sent = true;
3283 case InventoryLocation::NODEMETA:
3285 v3s16 blockpos = getNodeBlockPos(loc.p);
3287 MapBlock *block = m_env->getMap().getBlockNoCreateNoEx(blockpos);
3289 block->raiseModified(MOD_STATE_WRITE_NEEDED);
3291 setBlockNotSent(blockpos);
3294 case InventoryLocation::DETACHED:
3296 sendDetachedInventoryToAll(loc.name);
3304 void Server::peerAdded(con::Peer *peer)
3306 DSTACK(__FUNCTION_NAME);
3307 verbosestream<<"Server::peerAdded(): peer->id="
3308 <<peer->id<<std::endl;
3311 c.type = PEER_ADDED;
3312 c.peer_id = peer->id;
3314 m_peer_change_queue.push_back(c);
3317 void Server::deletingPeer(con::Peer *peer, bool timeout)
3319 DSTACK(__FUNCTION_NAME);
3320 verbosestream<<"Server::deletingPeer(): peer->id="
3321 <<peer->id<<", timeout="<<timeout<<std::endl;
3324 c.type = PEER_REMOVED;
3325 c.peer_id = peer->id;
3326 c.timeout = timeout;
3327 m_peer_change_queue.push_back(c);
3334 void Server::SendMovement(con::Connection &con, u16 peer_id)
3336 DSTACK(__FUNCTION_NAME);
3337 std::ostringstream os(std::ios_base::binary);
3339 writeU16(os, TOCLIENT_MOVEMENT);
3340 writeF1000(os, g_settings->getFloat("movement_acceleration_default"));
3341 writeF1000(os, g_settings->getFloat("movement_acceleration_air"));
3342 writeF1000(os, g_settings->getFloat("movement_acceleration_fast"));
3343 writeF1000(os, g_settings->getFloat("movement_speed_walk"));
3344 writeF1000(os, g_settings->getFloat("movement_speed_crouch"));
3345 writeF1000(os, g_settings->getFloat("movement_speed_fast"));
3346 writeF1000(os, g_settings->getFloat("movement_speed_climb"));
3347 writeF1000(os, g_settings->getFloat("movement_speed_jump"));
3348 writeF1000(os, g_settings->getFloat("movement_liquid_fluidity"));
3349 writeF1000(os, g_settings->getFloat("movement_liquid_fluidity_smooth"));
3350 writeF1000(os, g_settings->getFloat("movement_liquid_sink"));
3351 writeF1000(os, g_settings->getFloat("movement_gravity"));
3354 std::string s = os.str();
3355 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3357 con.Send(peer_id, 0, data, true);
3360 void Server::SendHP(con::Connection &con, u16 peer_id, u8 hp)
3362 DSTACK(__FUNCTION_NAME);
3363 std::ostringstream os(std::ios_base::binary);
3365 writeU16(os, TOCLIENT_HP);
3369 std::string s = os.str();
3370 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3372 con.Send(peer_id, 0, data, true);
3375 void Server::SendBreath(con::Connection &con, u16 peer_id, u16 breath)
3377 DSTACK(__FUNCTION_NAME);
3378 std::ostringstream os(std::ios_base::binary);
3380 writeU16(os, TOCLIENT_BREATH);
3381 writeU16(os, breath);
3384 std::string s = os.str();
3385 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3387 con.Send(peer_id, 0, data, true);
3390 void Server::SendAccessDenied(con::Connection &con, u16 peer_id,
3391 const std::wstring &reason)
3393 DSTACK(__FUNCTION_NAME);
3394 std::ostringstream os(std::ios_base::binary);
3396 writeU16(os, TOCLIENT_ACCESS_DENIED);
3397 os<<serializeWideString(reason);
3400 std::string s = os.str();
3401 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3403 con.Send(peer_id, 0, data, true);
3406 void Server::SendDeathscreen(con::Connection &con, u16 peer_id,
3407 bool set_camera_point_target, v3f camera_point_target)
3409 DSTACK(__FUNCTION_NAME);
3410 std::ostringstream os(std::ios_base::binary);
3412 writeU16(os, TOCLIENT_DEATHSCREEN);
3413 writeU8(os, set_camera_point_target);
3414 writeV3F1000(os, camera_point_target);
3417 std::string s = os.str();
3418 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3420 con.Send(peer_id, 0, data, true);
3423 void Server::SendItemDef(con::Connection &con, u16 peer_id,
3424 IItemDefManager *itemdef, u16 protocol_version)
3426 DSTACK(__FUNCTION_NAME);
3427 std::ostringstream os(std::ios_base::binary);
3431 u32 length of the next item
3432 zlib-compressed serialized ItemDefManager
3434 writeU16(os, TOCLIENT_ITEMDEF);
3435 std::ostringstream tmp_os(std::ios::binary);
3436 itemdef->serialize(tmp_os, protocol_version);
3437 std::ostringstream tmp_os2(std::ios::binary);
3438 compressZlib(tmp_os.str(), tmp_os2);
3439 os<<serializeLongString(tmp_os2.str());
3442 std::string s = os.str();
3443 verbosestream<<"Server: Sending item definitions to id("<<peer_id
3444 <<"): size="<<s.size()<<std::endl;
3445 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3447 con.Send(peer_id, 0, data, true);
3450 void Server::SendNodeDef(con::Connection &con, u16 peer_id,
3451 INodeDefManager *nodedef, u16 protocol_version)
3453 DSTACK(__FUNCTION_NAME);
3454 std::ostringstream os(std::ios_base::binary);
3458 u32 length of the next item
3459 zlib-compressed serialized NodeDefManager
3461 writeU16(os, TOCLIENT_NODEDEF);
3462 std::ostringstream tmp_os(std::ios::binary);
3463 nodedef->serialize(tmp_os, protocol_version);
3464 std::ostringstream tmp_os2(std::ios::binary);
3465 compressZlib(tmp_os.str(), tmp_os2);
3466 os<<serializeLongString(tmp_os2.str());
3469 std::string s = os.str();
3470 verbosestream<<"Server: Sending node definitions to id("<<peer_id
3471 <<"): size="<<s.size()<<std::endl;
3472 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3474 con.Send(peer_id, 0, data, true);
3478 Non-static send methods
3481 void Server::SendInventory(u16 peer_id)
3483 DSTACK(__FUNCTION_NAME);
3485 PlayerSAO *playersao = getPlayerSAO(peer_id);
3488 playersao->m_inventory_not_sent = false;
3494 std::ostringstream os;
3495 playersao->getInventory()->serialize(os);
3497 std::string s = os.str();
3499 SharedBuffer<u8> data(s.size()+2);
3500 writeU16(&data[0], TOCLIENT_INVENTORY);
3501 memcpy(&data[2], s.c_str(), s.size());
3504 m_con.Send(peer_id, 0, data, true);
3507 void Server::SendChatMessage(u16 peer_id, const std::wstring &message)
3509 DSTACK(__FUNCTION_NAME);
3511 std::ostringstream os(std::ios_base::binary);
3515 writeU16(buf, TOCLIENT_CHAT_MESSAGE);
3516 os.write((char*)buf, 2);
3519 writeU16(buf, message.size());
3520 os.write((char*)buf, 2);
3523 for(u32 i=0; i<message.size(); i++)
3527 os.write((char*)buf, 2);
3531 std::string s = os.str();
3532 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3534 m_con.Send(peer_id, 0, data, true);
3537 void Server::SendShowFormspecMessage(u16 peer_id, const std::string formspec,
3538 const std::string formname)
3540 DSTACK(__FUNCTION_NAME);
3542 std::ostringstream os(std::ios_base::binary);
3546 writeU16(buf, TOCLIENT_SHOW_FORMSPEC);
3547 os.write((char*)buf, 2);
3548 os<<serializeLongString(formspec);
3549 os<<serializeString(formname);
3552 std::string s = os.str();
3553 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3555 m_con.Send(peer_id, 0, data, true);
3558 // Spawns a particle on peer with peer_id
3559 void Server::SendSpawnParticle(u16 peer_id, v3f pos, v3f velocity, v3f acceleration,
3560 float expirationtime, float size, bool collisiondetection,
3561 std::string texture)
3563 DSTACK(__FUNCTION_NAME);
3565 std::ostringstream os(std::ios_base::binary);
3566 writeU16(os, TOCLIENT_SPAWN_PARTICLE);
3567 writeV3F1000(os, pos);
3568 writeV3F1000(os, velocity);
3569 writeV3F1000(os, acceleration);
3570 writeF1000(os, expirationtime);
3571 writeF1000(os, size);
3572 writeU8(os, collisiondetection);
3573 os<<serializeLongString(texture);
3576 std::string s = os.str();
3577 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3579 m_con.Send(peer_id, 0, data, true);
3582 // Spawns a particle on all peers
3583 void Server::SendSpawnParticleAll(v3f pos, v3f velocity, v3f acceleration,
3584 float expirationtime, float size, bool collisiondetection,
3585 std::string texture)
3587 for(std::map<u16, RemoteClient*>::iterator
3588 i = m_clients.begin();
3589 i != m_clients.end(); i++)
3591 // Get client and check that it is valid
3592 RemoteClient *client = i->second;
3593 assert(client->peer_id == i->first);
3594 if(client->serialization_version == SER_FMT_VER_INVALID)
3597 SendSpawnParticle(client->peer_id, pos, velocity, acceleration,
3598 expirationtime, size, collisiondetection, texture);
3602 // Adds a ParticleSpawner on peer with peer_id
3603 void Server::SendAddParticleSpawner(u16 peer_id, u16 amount, float spawntime, v3f minpos, v3f maxpos,
3604 v3f minvel, v3f maxvel, v3f minacc, v3f maxacc, float minexptime, float maxexptime,
3605 float minsize, float maxsize, bool collisiondetection, std::string texture, u32 id)
3607 DSTACK(__FUNCTION_NAME);
3609 std::ostringstream os(std::ios_base::binary);
3610 writeU16(os, TOCLIENT_ADD_PARTICLESPAWNER);
3612 writeU16(os, amount);
3613 writeF1000(os, spawntime);
3614 writeV3F1000(os, minpos);
3615 writeV3F1000(os, maxpos);
3616 writeV3F1000(os, minvel);
3617 writeV3F1000(os, maxvel);
3618 writeV3F1000(os, minacc);
3619 writeV3F1000(os, maxacc);
3620 writeF1000(os, minexptime);
3621 writeF1000(os, maxexptime);
3622 writeF1000(os, minsize);
3623 writeF1000(os, maxsize);
3624 writeU8(os, collisiondetection);
3625 os<<serializeLongString(texture);
3629 std::string s = os.str();
3630 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3632 m_con.Send(peer_id, 0, data, true);
3635 // Adds a ParticleSpawner on all peers
3636 void Server::SendAddParticleSpawnerAll(u16 amount, float spawntime, v3f minpos, v3f maxpos,
3637 v3f minvel, v3f maxvel, v3f minacc, v3f maxacc, float minexptime, float maxexptime,
3638 float minsize, float maxsize, bool collisiondetection, std::string texture, u32 id)
3640 for(std::map<u16, RemoteClient*>::iterator
3641 i = m_clients.begin();
3642 i != m_clients.end(); i++)
3644 // Get client and check that it is valid
3645 RemoteClient *client = i->second;
3646 assert(client->peer_id == i->first);
3647 if(client->serialization_version == SER_FMT_VER_INVALID)
3650 SendAddParticleSpawner(client->peer_id, amount, spawntime,
3651 minpos, maxpos, minvel, maxvel, minacc, maxacc,
3652 minexptime, maxexptime, minsize, maxsize, collisiondetection, texture, id);
3656 void Server::SendDeleteParticleSpawner(u16 peer_id, u32 id)
3658 DSTACK(__FUNCTION_NAME);
3660 std::ostringstream os(std::ios_base::binary);
3661 writeU16(os, TOCLIENT_DELETE_PARTICLESPAWNER);
3666 std::string s = os.str();
3667 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3669 m_con.Send(peer_id, 0, data, true);
3672 void Server::SendDeleteParticleSpawnerAll(u32 id)
3674 for(std::map<u16, RemoteClient*>::iterator
3675 i = m_clients.begin();
3676 i != m_clients.end(); i++)
3678 // Get client and check that it is valid
3679 RemoteClient *client = i->second;
3680 assert(client->peer_id == i->first);
3681 if(client->serialization_version == SER_FMT_VER_INVALID)
3684 SendDeleteParticleSpawner(client->peer_id, id);
3688 void Server::SendHUDAdd(u16 peer_id, u32 id, HudElement *form)
3690 std::ostringstream os(std::ios_base::binary);
3693 writeU16(os, TOCLIENT_HUDADD);
3695 writeU8(os, (u8)form->type);
3696 writeV2F1000(os, form->pos);
3697 os << serializeString(form->name);
3698 writeV2F1000(os, form->scale);
3699 os << serializeString(form->text);
3700 writeU32(os, form->number);
3701 writeU32(os, form->item);
3702 writeU32(os, form->dir);
3703 writeV2F1000(os, form->align);
3704 writeV2F1000(os, form->offset);
3707 std::string s = os.str();
3708 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3710 m_con.Send(peer_id, 0, data, true);
3713 void Server::SendHUDRemove(u16 peer_id, u32 id)
3715 std::ostringstream os(std::ios_base::binary);
3718 writeU16(os, TOCLIENT_HUDRM);
3722 std::string s = os.str();
3723 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3725 m_con.Send(peer_id, 0, data, true);
3728 void Server::SendHUDChange(u16 peer_id, u32 id, HudElementStat stat, void *value)
3730 std::ostringstream os(std::ios_base::binary);
3733 writeU16(os, TOCLIENT_HUDCHANGE);
3735 writeU8(os, (u8)stat);
3738 case HUD_STAT_SCALE:
3739 case HUD_STAT_ALIGN:
3740 case HUD_STAT_OFFSET:
3741 writeV2F1000(os, *(v2f *)value);
3745 os << serializeString(*(std::string *)value);
3747 case HUD_STAT_NUMBER:
3751 writeU32(os, *(u32 *)value);
3756 std::string s = os.str();
3757 SharedBuffer<u8> data((u8 *)s.c_str(), s.size());
3759 m_con.Send(peer_id, 0, data, true);
3762 void Server::SendHUDSetFlags(u16 peer_id, u32 flags, u32 mask)
3764 std::ostringstream os(std::ios_base::binary);
3767 writeU16(os, TOCLIENT_HUD_SET_FLAGS);
3768 writeU32(os, flags);
3772 std::string s = os.str();
3773 SharedBuffer<u8> data((u8 *)s.c_str(), s.size());
3775 m_con.Send(peer_id, 0, data, true);
3778 void Server::SendHUDSetParam(u16 peer_id, u16 param, const std::string &value)
3780 std::ostringstream os(std::ios_base::binary);
3783 writeU16(os, TOCLIENT_HUD_SET_PARAM);
3784 writeU16(os, param);
3785 os<<serializeString(value);
3788 std::string s = os.str();
3789 SharedBuffer<u8> data((u8 *)s.c_str(), s.size());
3791 m_con.Send(peer_id, 0, data, true);
3794 void Server::BroadcastChatMessage(const std::wstring &message)
3796 for(std::map<u16, RemoteClient*>::iterator
3797 i = m_clients.begin();
3798 i != m_clients.end(); ++i)
3800 // Get client and check that it is valid
3801 RemoteClient *client = i->second;
3802 assert(client->peer_id == i->first);
3803 if(client->serialization_version == SER_FMT_VER_INVALID)
3806 SendChatMessage(client->peer_id, message);
3810 void Server::SendTimeOfDay(u16 peer_id, u16 time, f32 time_speed)
3812 DSTACK(__FUNCTION_NAME);
3815 SharedBuffer<u8> data(2+2+4);
3816 writeU16(&data[0], TOCLIENT_TIME_OF_DAY);
3817 writeU16(&data[2], time);
3818 writeF1000(&data[4], time_speed);
3821 m_con.Send(peer_id, 0, data, true);
3824 void Server::SendPlayerHP(u16 peer_id)
3826 DSTACK(__FUNCTION_NAME);
3827 PlayerSAO *playersao = getPlayerSAO(peer_id);
3829 playersao->m_hp_not_sent = false;
3830 SendHP(m_con, peer_id, playersao->getHP());
3832 // Send to other clients
3833 std::string str = gob_cmd_punched(playersao->readDamage(), playersao->getHP());
3834 ActiveObjectMessage aom(playersao->getId(), true, str);
3835 playersao->m_messages_out.push_back(aom);
3838 void Server::SendPlayerBreath(u16 peer_id)
3840 DSTACK(__FUNCTION_NAME);
3841 PlayerSAO *playersao = getPlayerSAO(peer_id);
3843 playersao->m_breath_not_sent = false;
3844 SendBreath(m_con, peer_id, playersao->getBreath());
3847 void Server::SendMovePlayer(u16 peer_id)
3849 DSTACK(__FUNCTION_NAME);
3850 Player *player = m_env->getPlayer(peer_id);
3853 std::ostringstream os(std::ios_base::binary);
3854 writeU16(os, TOCLIENT_MOVE_PLAYER);
3855 writeV3F1000(os, player->getPosition());
3856 writeF1000(os, player->getPitch());
3857 writeF1000(os, player->getYaw());
3860 v3f pos = player->getPosition();
3861 f32 pitch = player->getPitch();
3862 f32 yaw = player->getYaw();
3863 verbosestream<<"Server: Sending TOCLIENT_MOVE_PLAYER"
3864 <<" pos=("<<pos.X<<","<<pos.Y<<","<<pos.Z<<")"
3871 std::string s = os.str();
3872 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3874 m_con.Send(peer_id, 0, data, true);
3877 void Server::SendPlayerPrivileges(u16 peer_id)
3879 Player *player = m_env->getPlayer(peer_id);
3881 if(player->peer_id == PEER_ID_INEXISTENT)
3884 std::set<std::string> privs;
3885 m_script->getAuth(player->getName(), NULL, &privs);
3887 std::ostringstream os(std::ios_base::binary);
3888 writeU16(os, TOCLIENT_PRIVILEGES);
3889 writeU16(os, privs.size());
3890 for(std::set<std::string>::const_iterator i = privs.begin();
3891 i != privs.end(); i++){
3892 os<<serializeString(*i);
3896 std::string s = os.str();
3897 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3899 m_con.Send(peer_id, 0, data, true);
3902 void Server::SendPlayerInventoryFormspec(u16 peer_id)
3904 Player *player = m_env->getPlayer(peer_id);
3906 if(player->peer_id == PEER_ID_INEXISTENT)
3909 std::ostringstream os(std::ios_base::binary);
3910 writeU16(os, TOCLIENT_INVENTORY_FORMSPEC);
3911 os<<serializeLongString(player->inventory_formspec);
3914 std::string s = os.str();
3915 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3917 m_con.Send(peer_id, 0, data, true);
3920 s32 Server::playSound(const SimpleSoundSpec &spec,
3921 const ServerSoundParams ¶ms)
3923 // Find out initial position of sound
3924 bool pos_exists = false;
3925 v3f pos = params.getPos(m_env, &pos_exists);
3926 // If position is not found while it should be, cancel sound
3927 if(pos_exists != (params.type != ServerSoundParams::SSP_LOCAL))
3929 // Filter destination clients
3930 std::set<RemoteClient*> dst_clients;
3931 if(params.to_player != "")
3933 Player *player = m_env->getPlayer(params.to_player.c_str());
3935 infostream<<"Server::playSound: Player \""<<params.to_player
3936 <<"\" not found"<<std::endl;
3939 if(player->peer_id == PEER_ID_INEXISTENT){
3940 infostream<<"Server::playSound: Player \""<<params.to_player
3941 <<"\" not connected"<<std::endl;
3944 RemoteClient *client = getClient(player->peer_id);
3945 dst_clients.insert(client);
3949 for(std::map<u16, RemoteClient*>::iterator
3950 i = m_clients.begin(); i != m_clients.end(); ++i)
3952 RemoteClient *client = i->second;
3953 Player *player = m_env->getPlayer(client->peer_id);
3957 if(player->getPosition().getDistanceFrom(pos) >
3958 params.max_hear_distance)
3961 dst_clients.insert(client);
3964 if(dst_clients.size() == 0)
3967 s32 id = m_next_sound_id++;
3968 // The sound will exist as a reference in m_playing_sounds
3969 m_playing_sounds[id] = ServerPlayingSound();
3970 ServerPlayingSound &psound = m_playing_sounds[id];
3971 psound.params = params;
3972 for(std::set<RemoteClient*>::iterator i = dst_clients.begin();
3973 i != dst_clients.end(); i++)
3974 psound.clients.insert((*i)->peer_id);
3976 std::ostringstream os(std::ios_base::binary);
3977 writeU16(os, TOCLIENT_PLAY_SOUND);
3979 os<<serializeString(spec.name);
3980 writeF1000(os, spec.gain * params.gain);
3981 writeU8(os, params.type);
3982 writeV3F1000(os, pos);
3983 writeU16(os, params.object);
3984 writeU8(os, params.loop);
3986 std::string s = os.str();
3987 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3989 for(std::set<RemoteClient*>::iterator i = dst_clients.begin();
3990 i != dst_clients.end(); i++){
3992 m_con.Send((*i)->peer_id, 0, data, true);
3996 void Server::stopSound(s32 handle)
3998 // Get sound reference
3999 std::map<s32, ServerPlayingSound>::iterator i =
4000 m_playing_sounds.find(handle);
4001 if(i == m_playing_sounds.end())
4003 ServerPlayingSound &psound = i->second;
4005 std::ostringstream os(std::ios_base::binary);
4006 writeU16(os, TOCLIENT_STOP_SOUND);
4007 writeS32(os, handle);
4009 std::string s = os.str();
4010 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
4012 for(std::set<u16>::iterator i = psound.clients.begin();
4013 i != psound.clients.end(); i++){
4015 m_con.Send(*i, 0, data, true);
4017 // Remove sound reference
4018 m_playing_sounds.erase(i);
4021 void Server::sendRemoveNode(v3s16 p, u16 ignore_id,
4022 std::list<u16> *far_players, float far_d_nodes)
4024 float maxd = far_d_nodes*BS;
4025 v3f p_f = intToFloat(p, BS);
4029 SharedBuffer<u8> reply(replysize);
4030 writeU16(&reply[0], TOCLIENT_REMOVENODE);
4031 writeS16(&reply[2], p.X);
4032 writeS16(&reply[4], p.Y);
4033 writeS16(&reply[6], p.Z);
4035 for(std::map<u16, RemoteClient*>::iterator
4036 i = m_clients.begin();
4037 i != m_clients.end(); ++i)
4039 // Get client and check that it is valid
4040 RemoteClient *client = i->second;
4041 assert(client->peer_id == i->first);
4042 if(client->serialization_version == SER_FMT_VER_INVALID)
4045 // Don't send if it's the same one
4046 if(client->peer_id == ignore_id)
4052 Player *player = m_env->getPlayer(client->peer_id);
4055 // If player is far away, only set modified blocks not sent
4056 v3f player_pos = player->getPosition();
4057 if(player_pos.getDistanceFrom(p_f) > maxd)
4059 far_players->push_back(client->peer_id);
4066 m_con.Send(client->peer_id, 0, reply, true);
4070 void Server::sendAddNode(v3s16 p, MapNode n, u16 ignore_id,
4071 std::list<u16> *far_players, float far_d_nodes,
4072 bool remove_metadata)
4074 float maxd = far_d_nodes*BS;
4075 v3f p_f = intToFloat(p, BS);
4077 for(std::map<u16, RemoteClient*>::iterator
4078 i = m_clients.begin();
4079 i != m_clients.end(); ++i)
4081 // Get client and check that it is valid
4082 RemoteClient *client = i->second;
4083 assert(client->peer_id == i->first);
4084 if(client->serialization_version == SER_FMT_VER_INVALID)
4087 // Don't send if it's the same one
4088 if(client->peer_id == ignore_id)
4094 Player *player = m_env->getPlayer(client->peer_id);
4097 // If player is far away, only set modified blocks not sent
4098 v3f player_pos = player->getPosition();
4099 if(player_pos.getDistanceFrom(p_f) > maxd)
4101 far_players->push_back(client->peer_id);
4108 u32 replysize = 9 + MapNode::serializedLength(client->serialization_version);
4109 SharedBuffer<u8> reply(replysize);
4110 writeU16(&reply[0], TOCLIENT_ADDNODE);
4111 writeS16(&reply[2], p.X);
4112 writeS16(&reply[4], p.Y);
4113 writeS16(&reply[6], p.Z);
4114 n.serialize(&reply[8], client->serialization_version);
4115 u32 index = 8 + MapNode::serializedLength(client->serialization_version);
4116 writeU8(&reply[index], remove_metadata ? 0 : 1);
4118 if (!remove_metadata) {
4119 if (client->net_proto_version <= 21) {
4120 // Old clients always clear metadata; fix it
4121 // by sending the full block again.
4122 client->SetBlockNotSent(p);
4127 m_con.Send(client->peer_id, 0, reply, true);
4131 void Server::setBlockNotSent(v3s16 p)
4133 for(std::map<u16, RemoteClient*>::iterator
4134 i = m_clients.begin();
4135 i != m_clients.end(); ++i)
4137 RemoteClient *client = i->second;
4138 client->SetBlockNotSent(p);
4142 void Server::SendBlockNoLock(u16 peer_id, MapBlock *block, u8 ver, u16 net_proto_version)
4144 DSTACK(__FUNCTION_NAME);
4146 v3s16 p = block->getPos();
4150 bool completely_air = true;
4151 for(s16 z0=0; z0<MAP_BLOCKSIZE; z0++)
4152 for(s16 x0=0; x0<MAP_BLOCKSIZE; x0++)
4153 for(s16 y0=0; y0<MAP_BLOCKSIZE; y0++)
4155 if(block->getNodeNoEx(v3s16(x0,y0,z0)).d != CONTENT_AIR)
4157 completely_air = false;
4158 x0 = y0 = z0 = MAP_BLOCKSIZE; // Break out
4163 infostream<<"Server: Sending block ("<<p.X<<","<<p.Y<<","<<p.Z<<"): ";
4165 infostream<<"[completely air] ";
4166 infostream<<std::endl;
4170 Create a packet with the block in the right format
4173 std::ostringstream os(std::ios_base::binary);
4174 block->serialize(os, ver, false);
4175 block->serializeNetworkSpecific(os, net_proto_version);
4176 std::string s = os.str();
4177 SharedBuffer<u8> blockdata((u8*)s.c_str(), s.size());
4179 u32 replysize = 8 + blockdata.getSize();
4180 SharedBuffer<u8> reply(replysize);
4181 writeU16(&reply[0], TOCLIENT_BLOCKDATA);
4182 writeS16(&reply[2], p.X);
4183 writeS16(&reply[4], p.Y);
4184 writeS16(&reply[6], p.Z);
4185 memcpy(&reply[8], *blockdata, blockdata.getSize());
4187 /*infostream<<"Server: Sending block ("<<p.X<<","<<p.Y<<","<<p.Z<<")"
4188 <<": \tpacket size: "<<replysize<<std::endl;*/
4193 m_con.Send(peer_id, 1, reply, true);
4196 void Server::SendBlocks(float dtime)
4198 DSTACK(__FUNCTION_NAME);
4200 JMutexAutoLock envlock(m_env_mutex);
4201 JMutexAutoLock conlock(m_con_mutex);
4203 ScopeProfiler sp(g_profiler, "Server: sel and send blocks to clients");
4205 std::vector<PrioritySortedBlockTransfer> queue;
4207 s32 total_sending = 0;
4210 ScopeProfiler sp(g_profiler, "Server: selecting blocks for sending");
4212 for(std::map<u16, RemoteClient*>::iterator
4213 i = m_clients.begin();
4214 i != m_clients.end(); ++i)
4216 RemoteClient *client = i->second;
4217 assert(client->peer_id == i->first);
4219 // If definitions and textures have not been sent, don't
4220 // send MapBlocks either
4221 if(!client->definitions_sent)
4224 total_sending += client->SendingCount();
4226 if(client->serialization_version == SER_FMT_VER_INVALID)
4229 client->GetNextBlocks(this, dtime, queue);
4234 // Lowest priority number comes first.
4235 // Lowest is most important.
4236 std::sort(queue.begin(), queue.end());
4238 for(u32 i=0; i<queue.size(); i++)
4240 //TODO: Calculate limit dynamically
4241 if(total_sending >= g_settings->getS32
4242 ("max_simultaneous_block_sends_server_total"))
4245 PrioritySortedBlockTransfer q = queue[i];
4247 MapBlock *block = NULL;
4250 block = m_env->getMap().getBlockNoCreate(q.pos);
4252 catch(InvalidPositionException &e)
4257 RemoteClient *client = getClientNoEx(q.peer_id);
4263 SendBlockNoLock(q.peer_id, block, client->serialization_version, client->net_proto_version);
4265 client->SentBlock(q.pos);
4271 void Server::fillMediaCache()
4273 DSTACK(__FUNCTION_NAME);
4275 infostream<<"Server: Calculating media file checksums"<<std::endl;
4277 // Collect all media file paths
4278 std::list<std::string> paths;
4279 for(std::vector<ModSpec>::iterator i = m_mods.begin();
4280 i != m_mods.end(); i++){
4281 const ModSpec &mod = *i;
4282 paths.push_back(mod.path + DIR_DELIM + "textures");
4283 paths.push_back(mod.path + DIR_DELIM + "sounds");
4284 paths.push_back(mod.path + DIR_DELIM + "media");
4285 paths.push_back(mod.path + DIR_DELIM + "models");
4287 paths.push_back(porting::path_user + DIR_DELIM + "textures" + DIR_DELIM + "server");
4289 // Collect media file information from paths into cache
4290 for(std::list<std::string>::iterator i = paths.begin();
4291 i != paths.end(); i++)
4293 std::string mediapath = *i;
4294 std::vector<fs::DirListNode> dirlist = fs::GetDirListing(mediapath);
4295 for(u32 j=0; j<dirlist.size(); j++){
4296 if(dirlist[j].dir) // Ignode dirs
4298 std::string filename = dirlist[j].name;
4299 // If name contains illegal characters, ignore the file
4300 if(!string_allowed(filename, TEXTURENAME_ALLOWED_CHARS)){
4301 infostream<<"Server: ignoring illegal file name: \""
4302 <<filename<<"\""<<std::endl;
4305 // If name is not in a supported format, ignore it
4306 const char *supported_ext[] = {
4307 ".png", ".jpg", ".bmp", ".tga",
4308 ".pcx", ".ppm", ".psd", ".wal", ".rgb",
4310 ".x", ".b3d", ".md2", ".obj",
4313 if(removeStringEnd(filename, supported_ext) == ""){
4314 infostream<<"Server: ignoring unsupported file extension: \""
4315 <<filename<<"\""<<std::endl;
4318 // Ok, attempt to load the file and add to cache
4319 std::string filepath = mediapath + DIR_DELIM + filename;
4321 std::ifstream fis(filepath.c_str(), std::ios_base::binary);
4322 if(fis.good() == false){
4323 errorstream<<"Server::fillMediaCache(): Could not open \""
4324 <<filename<<"\" for reading"<<std::endl;
4327 std::ostringstream tmp_os(std::ios_base::binary);
4331 fis.read(buf, 1024);
4332 std::streamsize len = fis.gcount();
4333 tmp_os.write(buf, len);
4342 errorstream<<"Server::fillMediaCache(): Failed to read \""
4343 <<filename<<"\""<<std::endl;
4346 if(tmp_os.str().length() == 0){
4347 errorstream<<"Server::fillMediaCache(): Empty file \""
4348 <<filepath<<"\""<<std::endl;
4353 sha1.addBytes(tmp_os.str().c_str(), tmp_os.str().length());
4355 unsigned char *digest = sha1.getDigest();
4356 std::string sha1_base64 = base64_encode(digest, 20);
4357 std::string sha1_hex = hex_encode((char*)digest, 20);
4361 this->m_media[filename] = MediaInfo(filepath, sha1_base64);
4362 verbosestream<<"Server: "<<sha1_hex<<" is "<<filename<<std::endl;
4367 struct SendableMediaAnnouncement
4370 std::string sha1_digest;
4372 SendableMediaAnnouncement(const std::string name_="",
4373 const std::string sha1_digest_=""):
4375 sha1_digest(sha1_digest_)
4379 void Server::sendMediaAnnouncement(u16 peer_id)
4381 DSTACK(__FUNCTION_NAME);
4383 verbosestream<<"Server: Announcing files to id("<<peer_id<<")"
4386 std::list<SendableMediaAnnouncement> file_announcements;
4388 for(std::map<std::string, MediaInfo>::iterator i = m_media.begin();
4389 i != m_media.end(); i++){
4391 file_announcements.push_back(
4392 SendableMediaAnnouncement(i->first, i->second.sha1_digest));
4396 std::ostringstream os(std::ios_base::binary);
4404 u16 length of sha1_digest
4409 writeU16(os, TOCLIENT_ANNOUNCE_MEDIA);
4410 writeU16(os, file_announcements.size());
4412 for(std::list<SendableMediaAnnouncement>::iterator
4413 j = file_announcements.begin();
4414 j != file_announcements.end(); ++j){
4415 os<<serializeString(j->name);
4416 os<<serializeString(j->sha1_digest);
4418 os<<serializeString(g_settings->get("remote_media"));
4421 std::string s = os.str();
4422 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
4425 m_con.Send(peer_id, 0, data, true);
4428 struct SendableMedia
4434 SendableMedia(const std::string &name_="", const std::string path_="",
4435 const std::string &data_=""):
4442 void Server::sendRequestedMedia(u16 peer_id,
4443 const std::list<MediaRequest> &tosend)
4445 DSTACK(__FUNCTION_NAME);
4447 verbosestream<<"Server::sendRequestedMedia(): "
4448 <<"Sending files to client"<<std::endl;
4452 // Put 5kB in one bunch (this is not accurate)
4453 u32 bytes_per_bunch = 5000;
4455 std::vector< std::list<SendableMedia> > file_bunches;
4456 file_bunches.push_back(std::list<SendableMedia>());
4458 u32 file_size_bunch_total = 0;
4460 for(std::list<MediaRequest>::const_iterator i = tosend.begin();
4461 i != tosend.end(); ++i)
4463 if(m_media.find(i->name) == m_media.end()){
4464 errorstream<<"Server::sendRequestedMedia(): Client asked for "
4465 <<"unknown file \""<<(i->name)<<"\""<<std::endl;
4469 //TODO get path + name
4470 std::string tpath = m_media[(*i).name].path;
4473 std::ifstream fis(tpath.c_str(), std::ios_base::binary);
4474 if(fis.good() == false){
4475 errorstream<<"Server::sendRequestedMedia(): Could not open \""
4476 <<tpath<<"\" for reading"<<std::endl;
4479 std::ostringstream tmp_os(std::ios_base::binary);
4483 fis.read(buf, 1024);
4484 std::streamsize len = fis.gcount();
4485 tmp_os.write(buf, len);
4486 file_size_bunch_total += len;
4495 errorstream<<"Server::sendRequestedMedia(): Failed to read \""
4496 <<(*i).name<<"\""<<std::endl;
4499 /*infostream<<"Server::sendRequestedMedia(): Loaded \""
4500 <<tname<<"\""<<std::endl;*/
4502 file_bunches[file_bunches.size()-1].push_back(
4503 SendableMedia((*i).name, tpath, tmp_os.str()));
4505 // Start next bunch if got enough data
4506 if(file_size_bunch_total >= bytes_per_bunch){
4507 file_bunches.push_back(std::list<SendableMedia>());
4508 file_size_bunch_total = 0;
4513 /* Create and send packets */
4515 u32 num_bunches = file_bunches.size();
4516 for(u32 i=0; i<num_bunches; i++)
4518 std::ostringstream os(std::ios_base::binary);
4522 u16 total number of texture bunches
4523 u16 index of this bunch
4524 u32 number of files in this bunch
4533 writeU16(os, TOCLIENT_MEDIA);
4534 writeU16(os, num_bunches);
4536 writeU32(os, file_bunches[i].size());
4538 for(std::list<SendableMedia>::iterator
4539 j = file_bunches[i].begin();
4540 j != file_bunches[i].end(); ++j){
4541 os<<serializeString(j->name);
4542 os<<serializeLongString(j->data);
4546 std::string s = os.str();
4547 verbosestream<<"Server::sendRequestedMedia(): bunch "
4548 <<i<<"/"<<num_bunches
4549 <<" files="<<file_bunches[i].size()
4550 <<" size=" <<s.size()<<std::endl;
4551 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
4553 m_con.Send(peer_id, 0, data, true);
4557 void Server::sendDetachedInventory(const std::string &name, u16 peer_id)
4559 if(m_detached_inventories.count(name) == 0){
4560 errorstream<<__FUNCTION_NAME<<": \""<<name<<"\" not found"<<std::endl;
4563 Inventory *inv = m_detached_inventories[name];
4565 std::ostringstream os(std::ios_base::binary);
4566 writeU16(os, TOCLIENT_DETACHED_INVENTORY);
4567 os<<serializeString(name);
4571 std::string s = os.str();
4572 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
4574 m_con.Send(peer_id, 0, data, true);
4577 void Server::sendDetachedInventoryToAll(const std::string &name)
4579 DSTACK(__FUNCTION_NAME);
4581 for(std::map<u16, RemoteClient*>::iterator
4582 i = m_clients.begin();
4583 i != m_clients.end(); ++i){
4584 RemoteClient *client = i->second;
4585 sendDetachedInventory(name, client->peer_id);
4589 void Server::sendDetachedInventories(u16 peer_id)
4591 DSTACK(__FUNCTION_NAME);
4593 for(std::map<std::string, Inventory*>::iterator
4594 i = m_detached_inventories.begin();
4595 i != m_detached_inventories.end(); i++){
4596 const std::string &name = i->first;
4597 //Inventory *inv = i->second;
4598 sendDetachedInventory(name, peer_id);
4606 void Server::DiePlayer(u16 peer_id)
4608 DSTACK(__FUNCTION_NAME);
4610 PlayerSAO *playersao = getPlayerSAO(peer_id);
4613 infostream<<"Server::DiePlayer(): Player "
4614 <<playersao->getPlayer()->getName()
4615 <<" dies"<<std::endl;
4617 playersao->setHP(0);
4619 // Trigger scripted stuff
4620 m_script->on_dieplayer(playersao);
4622 SendPlayerHP(peer_id);
4623 SendDeathscreen(m_con, peer_id, false, v3f(0,0,0));
4626 void Server::RespawnPlayer(u16 peer_id)
4628 DSTACK(__FUNCTION_NAME);
4630 PlayerSAO *playersao = getPlayerSAO(peer_id);
4633 infostream<<"Server::RespawnPlayer(): Player "
4634 <<playersao->getPlayer()->getName()
4635 <<" respawns"<<std::endl;
4637 playersao->setHP(PLAYER_MAX_HP);
4639 bool repositioned = m_script->on_respawnplayer(playersao);
4641 v3f pos = findSpawnPos(m_env->getServerMap());
4642 playersao->setPos(pos);
4646 void Server::DenyAccess(u16 peer_id, const std::wstring &reason)
4648 DSTACK(__FUNCTION_NAME);
4650 SendAccessDenied(m_con, peer_id, reason);
4652 RemoteClient *client = getClientNoEx(peer_id);
4654 client->denied = true;
4656 // If there are way too many clients, get rid of denied new ones immediately
4657 if((int)m_clients.size() > 2 * g_settings->getU16("max_users")){
4658 verbosestream<<"Server: DenyAccess: Too many clients; getting rid of "
4659 <<"peer_id="<<peer_id<<" immediately"<<std::endl;
4660 // Delete peer to stop sending it data
4661 m_con.DeletePeer(peer_id);
4662 // Delete client also to stop block sends and other stuff
4663 DeleteClient(peer_id, CDR_DENY);
4667 void Server::DeleteClient(u16 peer_id, ClientDeletionReason reason)
4669 DSTACK(__FUNCTION_NAME);
4672 std::map<u16, RemoteClient*>::iterator n;
4673 n = m_clients.find(peer_id);
4674 // The client may not exist; clients are immediately removed if their
4675 // access is denied, and this event occurs later then.
4676 if(n == m_clients.end())
4680 Mark objects to be not known by the client
4682 RemoteClient *client = n->second;
4684 for(std::set<u16>::iterator
4685 i = client->m_known_objects.begin();
4686 i != client->m_known_objects.end(); ++i)
4690 ServerActiveObject* obj = m_env->getActiveObject(id);
4692 if(obj && obj->m_known_by_count > 0)
4693 obj->m_known_by_count--;
4697 Clear references to playing sounds
4699 for(std::map<s32, ServerPlayingSound>::iterator
4700 i = m_playing_sounds.begin();
4701 i != m_playing_sounds.end();)
4703 ServerPlayingSound &psound = i->second;
4704 psound.clients.erase(peer_id);
4705 if(psound.clients.size() == 0)
4706 m_playing_sounds.erase(i++);
4711 Player *player = m_env->getPlayer(peer_id);
4713 // Collect information about leaving in chat
4714 std::wstring message;
4716 if(player != NULL && reason != CDR_DENY)
4718 std::wstring name = narrow_to_wide(player->getName());
4721 message += L" left the game.";
4722 if(reason == CDR_TIMEOUT)
4723 message += L" (timed out)";
4727 /* Run scripts and remove from environment */
4731 PlayerSAO *playersao = player->getPlayerSAO();
4734 m_script->on_leaveplayer(playersao);
4736 playersao->disconnected();
4744 if(player != NULL && reason != CDR_DENY)
4746 std::ostringstream os(std::ios_base::binary);
4747 for(std::map<u16, RemoteClient*>::iterator
4748 i = m_clients.begin();
4749 i != m_clients.end(); ++i)
4751 RemoteClient *client = i->second;
4752 assert(client->peer_id == i->first);
4753 if(client->serialization_version == SER_FMT_VER_INVALID)
4756 Player *player = m_env->getPlayer(client->peer_id);
4759 // Get name of player
4760 os<<player->getName()<<" ";
4763 actionstream<<player->getName()<<" "
4764 <<(reason==CDR_TIMEOUT?"times out.":"leaves game.")
4765 <<" List of players: "<<os.str()<<std::endl;
4770 delete m_clients[peer_id];
4771 m_clients.erase(peer_id);
4773 // Send leave chat message to all remaining clients
4774 if(message.length() != 0)
4775 BroadcastChatMessage(message);
4778 void Server::UpdateCrafting(u16 peer_id)
4780 DSTACK(__FUNCTION_NAME);
4782 Player* player = m_env->getPlayer(peer_id);
4785 // Get a preview for crafting
4787 InventoryLocation loc;
4788 loc.setPlayer(player->getName());
4789 getCraftingResult(&player->inventory, preview, false, this);
4790 m_env->getScriptIface()->item_CraftPredict(preview, player->getPlayerSAO(), (&player->inventory)->getList("craft"), loc);
4792 // Put the new preview in
4793 InventoryList *plist = player->inventory.getList("craftpreview");
4795 assert(plist->getSize() >= 1);
4796 plist->changeItem(0, preview);
4799 RemoteClient* Server::getClient(u16 peer_id)
4801 RemoteClient *client = getClientNoEx(peer_id);
4803 throw ClientNotFoundException("Client not found");
4806 RemoteClient* Server::getClientNoEx(u16 peer_id)
4808 std::map<u16, RemoteClient*>::iterator n;
4809 n = m_clients.find(peer_id);
4810 // The client may not exist; clients are immediately removed if their
4811 // access is denied, and this event occurs later then.
4812 if(n == m_clients.end())
4817 std::string Server::getPlayerName(u16 peer_id)
4819 Player *player = m_env->getPlayer(peer_id);
4821 return "[id="+itos(peer_id)+"]";
4822 return player->getName();
4825 PlayerSAO* Server::getPlayerSAO(u16 peer_id)
4827 Player *player = m_env->getPlayer(peer_id);
4830 return player->getPlayerSAO();
4833 std::wstring Server::getStatusString()
4835 std::wostringstream os(std::ios_base::binary);
4838 os<<L"version="<<narrow_to_wide(minetest_version_simple);
4840 os<<L", uptime="<<m_uptime.get();
4842 os<<L", max_lag="<<m_env->getMaxLagEstimate();
4843 // Information about clients
4844 std::map<u16, RemoteClient*>::iterator i;
4847 for(i = m_clients.begin(), first = true;
4848 i != m_clients.end(); ++i)
4850 // Get client and check that it is valid
4851 RemoteClient *client = i->second;
4852 assert(client->peer_id == i->first);
4853 if(client->serialization_version == SER_FMT_VER_INVALID)
4856 Player *player = m_env->getPlayer(client->peer_id);
4857 // Get name of player
4858 std::wstring name = L"unknown";
4860 name = narrow_to_wide(player->getName());
4861 // Add name to information string
4869 if(((ServerMap*)(&m_env->getMap()))->isSavingEnabled() == false)
4870 os<<std::endl<<L"# Server: "<<" WARNING: Map saving is disabled.";
4871 if(g_settings->get("motd") != "")
4872 os<<std::endl<<L"# Server: "<<narrow_to_wide(g_settings->get("motd"));
4876 std::set<std::string> Server::getPlayerEffectivePrivs(const std::string &name)
4878 std::set<std::string> privs;
4879 m_script->getAuth(name, NULL, &privs);
4883 bool Server::checkPriv(const std::string &name, const std::string &priv)
4885 std::set<std::string> privs = getPlayerEffectivePrivs(name);
4886 return (privs.count(priv) != 0);
4889 void Server::reportPrivsModified(const std::string &name)
4892 for(std::map<u16, RemoteClient*>::iterator
4893 i = m_clients.begin();
4894 i != m_clients.end(); ++i){
4895 RemoteClient *client = i->second;
4896 Player *player = m_env->getPlayer(client->peer_id);
4897 reportPrivsModified(player->getName());
4900 Player *player = m_env->getPlayer(name.c_str());
4903 SendPlayerPrivileges(player->peer_id);
4904 PlayerSAO *sao = player->getPlayerSAO();
4907 sao->updatePrivileges(
4908 getPlayerEffectivePrivs(name),
4913 void Server::reportInventoryFormspecModified(const std::string &name)
4915 Player *player = m_env->getPlayer(name.c_str());
4918 SendPlayerInventoryFormspec(player->peer_id);
4921 void Server::setIpBanned(const std::string &ip, const std::string &name)
4923 m_banmanager->add(ip, name);
4926 void Server::unsetIpBanned(const std::string &ip_or_name)
4928 m_banmanager->remove(ip_or_name);
4931 std::string Server::getBanDescription(const std::string &ip_or_name)
4933 return m_banmanager->getBanDescription(ip_or_name);
4936 void Server::notifyPlayer(const char *name, const std::wstring msg, const bool prepend = true)
4938 Player *player = m_env->getPlayer(name);
4942 SendChatMessage(player->peer_id, std::wstring(L"Server -!- ")+msg);
4944 SendChatMessage(player->peer_id, msg);
4947 bool Server::showFormspec(const char *playername, const std::string &formspec, const std::string &formname)
4949 Player *player = m_env->getPlayer(playername);
4953 infostream<<"showFormspec: couldn't find player:"<<playername<<std::endl;
4957 SendShowFormspecMessage(player->peer_id, formspec, formname);
4961 u32 Server::hudAdd(Player *player, HudElement *form) {
4965 u32 id = player->getFreeHudID();
4966 if (id < player->hud.size())
4967 player->hud[id] = form;
4969 player->hud.push_back(form);
4971 SendHUDAdd(player->peer_id, id, form);
4975 bool Server::hudRemove(Player *player, u32 id) {
4976 if (!player || id >= player->hud.size() || !player->hud[id])
4979 delete player->hud[id];
4980 player->hud[id] = NULL;
4982 SendHUDRemove(player->peer_id, id);
4986 bool Server::hudChange(Player *player, u32 id, HudElementStat stat, void *data) {
4990 SendHUDChange(player->peer_id, id, stat, data);
4994 bool Server::hudSetFlags(Player *player, u32 flags, u32 mask) {
4998 SendHUDSetFlags(player->peer_id, flags, mask);
5002 bool Server::hudSetHotbarItemcount(Player *player, s32 hotbar_itemcount) {
5005 if (hotbar_itemcount <= 0 || hotbar_itemcount > HUD_HOTBAR_ITEMCOUNT_MAX)
5008 std::ostringstream os(std::ios::binary);
5009 writeS32(os, hotbar_itemcount);
5010 SendHUDSetParam(player->peer_id, HUD_PARAM_HOTBAR_ITEMCOUNT, os.str());
5014 void Server::hudSetHotbarImage(Player *player, std::string name) {
5018 SendHUDSetParam(player->peer_id, HUD_PARAM_HOTBAR_IMAGE, name);
5021 void Server::hudSetHotbarSelectedImage(Player *player, std::string name) {
5025 SendHUDSetParam(player->peer_id, HUD_PARAM_HOTBAR_SELECTED_IMAGE, name);
5028 void Server::notifyPlayers(const std::wstring msg)
5030 BroadcastChatMessage(msg);
5033 void Server::spawnParticle(const char *playername, v3f pos,
5034 v3f velocity, v3f acceleration,
5035 float expirationtime, float size, bool
5036 collisiondetection, std::string texture)
5038 Player *player = m_env->getPlayer(playername);
5041 SendSpawnParticle(player->peer_id, pos, velocity, acceleration,
5042 expirationtime, size, collisiondetection, texture);
5045 void Server::spawnParticleAll(v3f pos, v3f velocity, v3f acceleration,
5046 float expirationtime, float size,
5047 bool collisiondetection, std::string texture)
5049 SendSpawnParticleAll(pos, velocity, acceleration,
5050 expirationtime, size, collisiondetection, texture);
5053 u32 Server::addParticleSpawner(const char *playername,
5054 u16 amount, float spawntime,
5055 v3f minpos, v3f maxpos,
5056 v3f minvel, v3f maxvel,
5057 v3f minacc, v3f maxacc,
5058 float minexptime, float maxexptime,
5059 float minsize, float maxsize,
5060 bool collisiondetection, std::string texture)
5062 Player *player = m_env->getPlayer(playername);
5067 for(;;) // look for unused particlespawner id
5070 if (std::find(m_particlespawner_ids.begin(),
5071 m_particlespawner_ids.end(), id)
5072 == m_particlespawner_ids.end())
5074 m_particlespawner_ids.push_back(id);
5079 SendAddParticleSpawner(player->peer_id, amount, spawntime,
5080 minpos, maxpos, minvel, maxvel, minacc, maxacc,
5081 minexptime, maxexptime, minsize, maxsize,
5082 collisiondetection, texture, id);
5087 u32 Server::addParticleSpawnerAll(u16 amount, float spawntime,
5088 v3f minpos, v3f maxpos,
5089 v3f minvel, v3f maxvel,
5090 v3f minacc, v3f maxacc,
5091 float minexptime, float maxexptime,
5092 float minsize, float maxsize,
5093 bool collisiondetection, std::string texture)
5096 for(;;) // look for unused particlespawner id
5099 if (std::find(m_particlespawner_ids.begin(),
5100 m_particlespawner_ids.end(), id)
5101 == m_particlespawner_ids.end())
5103 m_particlespawner_ids.push_back(id);
5108 SendAddParticleSpawnerAll(amount, spawntime,
5109 minpos, maxpos, minvel, maxvel, minacc, maxacc,
5110 minexptime, maxexptime, minsize, maxsize,
5111 collisiondetection, texture, id);
5116 void Server::deleteParticleSpawner(const char *playername, u32 id)
5118 Player *player = m_env->getPlayer(playername);
5122 m_particlespawner_ids.erase(
5123 std::remove(m_particlespawner_ids.begin(),
5124 m_particlespawner_ids.end(), id),
5125 m_particlespawner_ids.end());
5126 SendDeleteParticleSpawner(player->peer_id, id);
5129 void Server::deleteParticleSpawnerAll(u32 id)
5131 m_particlespawner_ids.erase(
5132 std::remove(m_particlespawner_ids.begin(),
5133 m_particlespawner_ids.end(), id),
5134 m_particlespawner_ids.end());
5135 SendDeleteParticleSpawnerAll(id);
5138 Inventory* Server::createDetachedInventory(const std::string &name)
5140 if(m_detached_inventories.count(name) > 0){
5141 infostream<<"Server clearing detached inventory \""<<name<<"\""<<std::endl;
5142 delete m_detached_inventories[name];
5144 infostream<<"Server creating detached inventory \""<<name<<"\""<<std::endl;
5146 Inventory *inv = new Inventory(m_itemdef);
5148 m_detached_inventories[name] = inv;
5149 sendDetachedInventoryToAll(name);
5156 BoolScopeSet(bool *dst, bool val):
5159 m_orig_state = *m_dst;
5164 *m_dst = m_orig_state;
5171 // actions: time-reversed list
5172 // Return value: success/failure
5173 bool Server::rollbackRevertActions(const std::list<RollbackAction> &actions,
5174 std::list<std::string> *log)
5176 infostream<<"Server::rollbackRevertActions(len="<<actions.size()<<")"<<std::endl;
5177 ServerMap *map = (ServerMap*)(&m_env->getMap());
5178 // Disable rollback report sink while reverting
5179 BoolScopeSet rollback_scope_disable(&m_rollback_sink_enabled, false);
5181 // Fail if no actions to handle
5182 if(actions.empty()){
5183 log->push_back("Nothing to do.");
5190 for(std::list<RollbackAction>::const_iterator
5191 i = actions.begin();
5192 i != actions.end(); i++)
5194 const RollbackAction &action = *i;
5196 bool success = action.applyRevert(map, this, this);
5199 std::ostringstream os;
5200 os<<"Revert of step ("<<num_tried<<") "<<action.toString()<<" failed";
5201 infostream<<"Map::rollbackRevertActions(): "<<os.str()<<std::endl;
5203 log->push_back(os.str());
5205 std::ostringstream os;
5206 os<<"Successfully reverted step ("<<num_tried<<") "<<action.toString();
5207 infostream<<"Map::rollbackRevertActions(): "<<os.str()<<std::endl;
5209 log->push_back(os.str());
5213 infostream<<"Map::rollbackRevertActions(): "<<num_failed<<"/"<<num_tried
5214 <<" failed"<<std::endl;
5216 // Call it done if less than half failed
5217 return num_failed <= num_tried/2;
5220 // IGameDef interface
5222 IItemDefManager* Server::getItemDefManager()
5226 INodeDefManager* Server::getNodeDefManager()
5230 ICraftDefManager* Server::getCraftDefManager()
5234 ITextureSource* Server::getTextureSource()
5238 IShaderSource* Server::getShaderSource()
5242 u16 Server::allocateUnknownNodeId(const std::string &name)
5244 return m_nodedef->allocateDummy(name);
5246 ISoundManager* Server::getSoundManager()
5248 return &dummySoundManager;
5250 MtEventManager* Server::getEventManager()
5254 IRollbackReportSink* Server::getRollbackReportSink()
5256 if(!m_enable_rollback_recording)
5258 if(!m_rollback_sink_enabled)
5263 IWritableItemDefManager* Server::getWritableItemDefManager()
5267 IWritableNodeDefManager* Server::getWritableNodeDefManager()
5271 IWritableCraftDefManager* Server::getWritableCraftDefManager()
5276 const ModSpec* Server::getModSpec(const std::string &modname)
5278 for(std::vector<ModSpec>::iterator i = m_mods.begin();
5279 i != m_mods.end(); i++){
5280 const ModSpec &mod = *i;
5281 if(mod.name == modname)
5286 void Server::getModNames(std::list<std::string> &modlist)
5288 for(std::vector<ModSpec>::iterator i = m_mods.begin(); i != m_mods.end(); i++)
5290 modlist.push_back(i->name);
5293 std::string Server::getBuiltinLuaPath()
5295 return porting::path_share + DIR_DELIM + "builtin";
5298 v3f findSpawnPos(ServerMap &map)
5300 //return v3f(50,50,50)*BS;
5305 nodepos = v2s16(0,0);
5310 s16 water_level = map.m_mgparams->water_level;
5312 // Try to find a good place a few times
5313 for(s32 i=0; i<1000; i++)
5316 // We're going to try to throw the player to this position
5317 v2s16 nodepos2d = v2s16(
5318 -range + (myrand() % (range * 2)),
5319 -range + (myrand() % (range * 2)));
5321 // Get ground height at point
5322 s16 groundheight = map.findGroundLevel(nodepos2d, g_settings->getBool("cache_block_before_spawn"));
5323 if (groundheight <= water_level) // Don't go underwater
5325 if (groundheight > water_level + g_settings->getS16("max_spawn_height")) // Don't go to high places
5328 nodepos = v3s16(nodepos2d.X, groundheight, nodepos2d.Y);
5329 bool is_good = false;
5331 for (s32 i = 0; i < 10; i++) {
5332 v3s16 blockpos = getNodeBlockPos(nodepos);
5333 map.emergeBlock(blockpos, true);
5334 content_t c = map.getNodeNoEx(nodepos).getContent();
5335 if (c == CONTENT_AIR || c == CONTENT_IGNORE) {
5337 if (air_count >= 2){
5345 // Found a good place
5346 //infostream<<"Searched through "<<i<<" places."<<std::endl;
5352 return intToFloat(nodepos, BS);
5355 PlayerSAO* Server::emergePlayer(const char *name, u16 peer_id)
5357 RemotePlayer *player = NULL;
5358 bool newplayer = false;
5361 Try to get an existing player
5363 player = static_cast<RemotePlayer*>(m_env->getPlayer(name));
5365 // If player is already connected, cancel
5366 if(player != NULL && player->peer_id != 0)
5368 infostream<<"emergePlayer(): Player already connected"<<std::endl;
5373 If player with the wanted peer_id already exists, cancel.
5375 if(m_env->getPlayer(peer_id) != NULL)
5377 infostream<<"emergePlayer(): Player with wrong name but same"
5378 " peer_id already exists"<<std::endl;
5383 Create a new player if it doesn't exist yet
5388 player = new RemotePlayer(this);
5389 player->updateName(name);
5391 /* Set player position */
5392 infostream<<"Server: Finding spawn place for player \""
5393 <<name<<"\""<<std::endl;
5394 v3f pos = findSpawnPos(m_env->getServerMap());
5395 player->setPosition(pos);
5397 /* Add player to environment */
5398 m_env->addPlayer(player);
5402 Create a new player active object
5404 PlayerSAO *playersao = new PlayerSAO(m_env, player, peer_id,
5405 getPlayerEffectivePrivs(player->getName()),
5408 /* Clean up old HUD elements from previous sessions */
5409 player->hud.clear();
5411 /* Add object to environment */
5412 m_env->addActiveObject(playersao);
5416 m_script->on_newplayer(playersao);
5418 m_script->on_joinplayer(playersao);
5423 void Server::handlePeerChange(PeerChange &c)
5425 JMutexAutoLock envlock(m_env_mutex);
5426 JMutexAutoLock conlock(m_con_mutex);
5428 if(c.type == PEER_ADDED)
5435 std::map<u16, RemoteClient*>::iterator n;
5436 n = m_clients.find(c.peer_id);
5437 // The client shouldn't already exist
5438 assert(n == m_clients.end());
5441 RemoteClient *client = new RemoteClient();
5442 client->peer_id = c.peer_id;
5443 m_clients[client->peer_id] = client;
5446 else if(c.type == PEER_REMOVED)
5452 DeleteClient(c.peer_id, c.timeout?CDR_TIMEOUT:CDR_LEAVE);
5461 void Server::handlePeerChanges()
5463 while(m_peer_change_queue.size() > 0)
5465 PeerChange c = m_peer_change_queue.pop_front();
5467 verbosestream<<"Server: Handling peer change: "
5468 <<"id="<<c.peer_id<<", timeout="<<c.timeout
5471 handlePeerChange(c);
5475 void dedicated_server_loop(Server &server, bool &kill)
5477 DSTACK(__FUNCTION_NAME);
5479 verbosestream<<"dedicated_server_loop()"<<std::endl;
5481 IntervalLimiter m_profiler_interval;
5485 float steplen = g_settings->getFloat("dedicated_server_step");
5486 // This is kind of a hack but can be done like this
5487 // because server.step() is very light
5489 ScopeProfiler sp(g_profiler, "dedicated server sleep");
5490 sleep_ms((int)(steplen*1000.0));
5492 server.step(steplen);
5494 if(server.getShutdownRequested() || kill)
5496 infostream<<"Dedicated server quitting"<<std::endl;
5498 if(g_settings->getBool("server_announce") == true)
5499 ServerList::sendAnnounce("delete");
5507 float profiler_print_interval =
5508 g_settings->getFloat("profiler_print_interval");
5509 if(profiler_print_interval != 0)
5511 if(m_profiler_interval.step(steplen, profiler_print_interval))
5513 infostream<<"Profiler:"<<std::endl;
5514 g_profiler->print(infostream);
5515 g_profiler->clear();