3 Copyright (C) 2010-2013 celeron55, Perttu Ahola <celeron55@gmail.com>
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU Lesser General Public License as published by
7 the Free Software Foundation; either version 2.1 of the License, or
8 (at your option) any later version.
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU Lesser General Public License for more details.
15 You should have received a copy of the GNU Lesser General Public License along
16 with this program; if not, write to the Free Software Foundation, Inc.,
17 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
24 #include "clientserver.h"
26 #include "environment.h"
28 #include "jthread/jmutexautolock.h"
30 #include "constants.h"
36 #include "serverobject.h"
37 #include "genericobject.h"
41 #include "scripting_game.h"
48 #include "content_mapnode.h"
49 #include "content_nodemeta.h"
50 #include "content_abm.h"
51 #include "content_sao.h"
56 #include "sound.h" // dummySoundManager
57 #include "event_manager.h"
59 #include "serverlist.h"
60 #include "util/string.h"
61 #include "util/pointedthing.h"
62 #include "util/mathconstants.h"
64 #include "util/serialize.h"
65 #include "util/thread.h"
66 #include "defaultsettings.h"
68 class ClientNotFoundException : public BaseException
71 ClientNotFoundException(const char *s):
76 class ServerThread : public JThread
82 ServerThread(Server *server):
91 void * ServerThread::Thread()
95 log_register_thread("ServerThread");
97 DSTACK(__FUNCTION_NAME);
99 BEGIN_DEBUG_EXCEPTION_HANDLER
101 while(!StopRequested())
104 //TimeTaker timer("AsyncRunStep() + Receive()");
107 //TimeTaker timer("AsyncRunStep()");
108 m_server->AsyncRunStep();
111 //infostream<<"Running m_server->Receive()"<<std::endl;
114 catch(con::NoIncomingDataException &e)
117 catch(con::PeerNotFoundException &e)
119 infostream<<"Server: PeerNotFoundException"<<std::endl;
121 catch(ClientNotFoundException &e)
124 catch(con::ConnectionBindFailed &e)
126 m_server->setAsyncFatalError(e.what());
130 m_server->setAsyncFatalError(e.what());
134 END_DEBUG_EXCEPTION_HANDLER(errorstream)
139 v3f ServerSoundParams::getPos(ServerEnvironment *env, bool *pos_exists) const
141 if(pos_exists) *pos_exists = false;
146 if(pos_exists) *pos_exists = true;
151 ServerActiveObject *sao = env->getActiveObject(object);
154 if(pos_exists) *pos_exists = true;
155 return sao->getBasePosition(); }
160 void RemoteClient::GetNextBlocks(Server *server, float dtime,
161 std::vector<PrioritySortedBlockTransfer> &dest)
163 DSTACK(__FUNCTION_NAME);
166 TimeTaker timer("RemoteClient::GetNextBlocks", &timer_result);*/
169 m_nothing_to_send_pause_timer -= dtime;
170 m_nearest_unsent_reset_timer += dtime;
172 if(m_nothing_to_send_pause_timer >= 0)
175 Player *player = server->m_env->getPlayer(peer_id);
176 // This can happen sometimes; clients and players are not in perfect sync.
180 // Won't send anything if already sending
181 if(m_blocks_sending.size() >= g_settings->getU16
182 ("max_simultaneous_block_sends_per_client"))
184 //infostream<<"Not sending any blocks, Queue full."<<std::endl;
188 //TimeTaker timer("RemoteClient::GetNextBlocks");
190 v3f playerpos = player->getPosition();
191 v3f playerspeed = player->getSpeed();
192 v3f playerspeeddir(0,0,0);
193 if(playerspeed.getLength() > 1.0*BS)
194 playerspeeddir = playerspeed / playerspeed.getLength();
195 // Predict to next block
196 v3f playerpos_predicted = playerpos + playerspeeddir*MAP_BLOCKSIZE*BS;
198 v3s16 center_nodepos = floatToInt(playerpos_predicted, BS);
200 v3s16 center = getNodeBlockPos(center_nodepos);
202 // Camera position and direction
203 v3f camera_pos = player->getEyePosition();
204 v3f camera_dir = v3f(0,0,1);
205 camera_dir.rotateYZBy(player->getPitch());
206 camera_dir.rotateXZBy(player->getYaw());
208 /*infostream<<"camera_dir=("<<camera_dir.X<<","<<camera_dir.Y<<","
209 <<camera_dir.Z<<")"<<std::endl;*/
212 Get the starting value of the block finder radius.
215 if(m_last_center != center)
217 m_nearest_unsent_d = 0;
218 m_last_center = center;
221 /*infostream<<"m_nearest_unsent_reset_timer="
222 <<m_nearest_unsent_reset_timer<<std::endl;*/
224 // Reset periodically to workaround for some bugs or stuff
225 if(m_nearest_unsent_reset_timer > 20.0)
227 m_nearest_unsent_reset_timer = 0;
228 m_nearest_unsent_d = 0;
229 //infostream<<"Resetting m_nearest_unsent_d for "
230 // <<server->getPlayerName(peer_id)<<std::endl;
233 //s16 last_nearest_unsent_d = m_nearest_unsent_d;
234 s16 d_start = m_nearest_unsent_d;
236 //infostream<<"d_start="<<d_start<<std::endl;
238 u16 max_simul_sends_setting = g_settings->getU16
239 ("max_simultaneous_block_sends_per_client");
240 u16 max_simul_sends_usually = max_simul_sends_setting;
243 Check the time from last addNode/removeNode.
245 Decrease send rate if player is building stuff.
247 m_time_from_building += dtime;
248 if(m_time_from_building < g_settings->getFloat(
249 "full_block_send_enable_min_time_from_building"))
251 max_simul_sends_usually
252 = LIMITED_MAX_SIMULTANEOUS_BLOCK_SENDS;
256 Number of blocks sending + number of blocks selected for sending
258 u32 num_blocks_selected = m_blocks_sending.size();
261 next time d will be continued from the d from which the nearest
262 unsent block was found this time.
264 This is because not necessarily any of the blocks found this
265 time are actually sent.
267 s32 new_nearest_unsent_d = -1;
269 s16 d_max = g_settings->getS16("max_block_send_distance");
270 s16 d_max_gen = g_settings->getS16("max_block_generate_distance");
272 // Don't loop very much at a time
273 s16 max_d_increment_at_time = 2;
274 if(d_max > d_start + max_d_increment_at_time)
275 d_max = d_start + max_d_increment_at_time;
276 /*if(d_max_gen > d_start+2)
277 d_max_gen = d_start+2;*/
279 //infostream<<"Starting from "<<d_start<<std::endl;
281 s32 nearest_emerged_d = -1;
282 s32 nearest_emergefull_d = -1;
283 s32 nearest_sent_d = -1;
284 bool queue_is_full = false;
287 for(d = d_start; d <= d_max; d++)
289 /*errorstream<<"checking d="<<d<<" for "
290 <<server->getPlayerName(peer_id)<<std::endl;*/
291 //infostream<<"RemoteClient::SendBlocks(): d="<<d<<std::endl;
294 If m_nearest_unsent_d was changed by the EmergeThread
295 (it can change it to 0 through SetBlockNotSent),
297 Else update m_nearest_unsent_d
299 /*if(m_nearest_unsent_d != last_nearest_unsent_d)
301 d = m_nearest_unsent_d;
302 last_nearest_unsent_d = m_nearest_unsent_d;
306 Get the border/face dot coordinates of a "d-radiused"
309 std::list<v3s16> list;
310 getFacePositions(list, d);
312 std::list<v3s16>::iterator li;
313 for(li=list.begin(); li!=list.end(); ++li)
315 v3s16 p = *li + center;
319 - Don't allow too many simultaneous transfers
320 - EXCEPT when the blocks are very close
322 Also, don't send blocks that are already flying.
325 // Start with the usual maximum
326 u16 max_simul_dynamic = max_simul_sends_usually;
328 // If block is very close, allow full maximum
329 if(d <= BLOCK_SEND_DISABLE_LIMITS_MAX_D)
330 max_simul_dynamic = max_simul_sends_setting;
332 // Don't select too many blocks for sending
333 if(num_blocks_selected >= max_simul_dynamic)
335 queue_is_full = true;
336 goto queue_full_break;
339 // Don't send blocks that are currently being transferred
340 if(m_blocks_sending.find(p) != m_blocks_sending.end())
346 if(p.X < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
347 || p.X > MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
348 || p.Y < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
349 || p.Y > MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
350 || p.Z < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
351 || p.Z > MAP_GENERATION_LIMIT / MAP_BLOCKSIZE)
354 // If this is true, inexistent block will be made from scratch
355 bool generate = d <= d_max_gen;
358 /*// Limit the generating area vertically to 2/3
359 if(abs(p.Y - center.Y) > d_max_gen - d_max_gen / 3)
362 // Limit the send area vertically to 1/2
363 if(abs(p.Y - center.Y) > d_max / 2)
369 If block is far away, don't generate it unless it is
375 // Block center y in nodes
376 f32 y = (f32)(p.Y * MAP_BLOCKSIZE + MAP_BLOCKSIZE/2);
377 // Don't generate if it's very high or very low
378 if(y < -64 || y > 64)
382 v2s16 p2d_nodes_center(
386 // Get ground height in nodes
387 s16 gh = server->m_env->getServerMap().findGroundLevel(
390 // If differs a lot, don't generate
391 if(fabs(gh - y) > MAP_BLOCKSIZE*2)
393 // Actually, don't even send it
399 //infostream<<"d="<<d<<std::endl;
402 Don't generate or send if not in sight
403 FIXME This only works if the client uses a small enough
404 FOV setting. The default of 72 degrees is fine.
407 float camera_fov = (72.0*M_PI/180) * 4./3.;
408 if(isBlockInSight(p, camera_pos, camera_dir, camera_fov, 10000*BS) == false)
414 Don't send already sent blocks
417 if(m_blocks_sent.find(p) != m_blocks_sent.end())
424 Check if map has this block
426 MapBlock *block = server->m_env->getMap().getBlockNoCreateNoEx(p);
428 bool surely_not_found_on_disk = false;
429 bool block_is_invalid = false;
432 // Reset usage timer, this block will be of use in the future.
433 block->resetUsageTimer();
435 // Block is dummy if data doesn't exist.
436 // It means it has been not found from disk and not generated
439 surely_not_found_on_disk = true;
442 // Block is valid if lighting is up-to-date and data exists
443 if(block->isValid() == false)
445 block_is_invalid = true;
448 /*if(block->isFullyGenerated() == false)
450 block_is_invalid = true;
455 ServerMap *map = (ServerMap*)(&server->m_env->getMap());
456 v2s16 chunkpos = map->sector_to_chunk(p2d);
457 if(map->chunkNonVolatile(chunkpos) == false)
458 block_is_invalid = true;
460 if(block->isGenerated() == false)
461 block_is_invalid = true;
464 If block is not close, don't send it unless it is near
467 Block is near ground level if night-time mesh
468 differs from day-time mesh.
472 if(block->getDayNightDiff() == false)
479 If block has been marked to not exist on disk (dummy)
480 and generating new ones is not wanted, skip block.
482 if(generate == false && surely_not_found_on_disk == true)
489 Add inexistent block to emerge queue.
491 if(block == NULL || surely_not_found_on_disk || block_is_invalid)
493 /* //TODO: Get value from somewhere
494 // Allow only one block in emerge queue
495 //if(server->m_emerge_queue.peerItemCount(peer_id) < 1)
496 // Allow two blocks in queue per client
497 //if(server->m_emerge_queue.peerItemCount(peer_id) < 2)
499 // Make it more responsive when needing to generate stuff
500 if(surely_not_found_on_disk)
502 if(server->m_emerge_queue.peerItemCount(peer_id) < max_emerge)
504 //infostream<<"Adding block to emerge queue"<<std::endl;
506 // Add it to the emerge queue and trigger the thread
509 if(generate == false)
510 flags |= BLOCK_EMERGE_FLAG_FROMDISK;
512 server->m_emerge_queue.addBlock(peer_id, p, flags);
513 server->m_emergethread.trigger();
515 if(nearest_emerged_d == -1)
516 nearest_emerged_d = d;
518 if(nearest_emergefull_d == -1)
519 nearest_emergefull_d = d;
520 goto queue_full_break;
524 if (server->m_emerge->enqueueBlockEmerge(peer_id, p, generate)) {
525 if (nearest_emerged_d == -1)
526 nearest_emerged_d = d;
528 if (nearest_emergefull_d == -1)
529 nearest_emergefull_d = d;
530 goto queue_full_break;
537 if(nearest_sent_d == -1)
541 Add block to send queue
544 /*errorstream<<"sending from d="<<d<<" to "
545 <<server->getPlayerName(peer_id)<<std::endl;*/
547 PrioritySortedBlockTransfer q((float)d, p, peer_id);
551 num_blocks_selected += 1;
556 //infostream<<"Stopped at "<<d<<std::endl;
558 // If nothing was found for sending and nothing was queued for
559 // emerging, continue next time browsing from here
560 if(nearest_emerged_d != -1){
561 new_nearest_unsent_d = nearest_emerged_d;
562 } else if(nearest_emergefull_d != -1){
563 new_nearest_unsent_d = nearest_emergefull_d;
565 if(d > g_settings->getS16("max_block_send_distance")){
566 new_nearest_unsent_d = 0;
567 m_nothing_to_send_pause_timer = 2.0;
568 /*infostream<<"GetNextBlocks(): d wrapped around for "
569 <<server->getPlayerName(peer_id)
570 <<"; setting to 0 and pausing"<<std::endl;*/
572 if(nearest_sent_d != -1)
573 new_nearest_unsent_d = nearest_sent_d;
575 new_nearest_unsent_d = d;
579 if(new_nearest_unsent_d != -1)
580 m_nearest_unsent_d = new_nearest_unsent_d;
582 /*timer_result = timer.stop(true);
583 if(timer_result != 0)
584 infostream<<"GetNextBlocks timeout: "<<timer_result<<" (!=0)"<<std::endl;*/
587 void RemoteClient::GotBlock(v3s16 p)
589 if(m_blocks_sending.find(p) != m_blocks_sending.end())
590 m_blocks_sending.erase(p);
593 /*infostream<<"RemoteClient::GotBlock(): Didn't find in"
594 " m_blocks_sending"<<std::endl;*/
595 m_excess_gotblocks++;
597 m_blocks_sent.insert(p);
600 void RemoteClient::SentBlock(v3s16 p)
602 if(m_blocks_sending.find(p) == m_blocks_sending.end())
603 m_blocks_sending[p] = 0.0;
605 infostream<<"RemoteClient::SentBlock(): Sent block"
606 " already in m_blocks_sending"<<std::endl;
609 void RemoteClient::SetBlockNotSent(v3s16 p)
611 m_nearest_unsent_d = 0;
613 if(m_blocks_sending.find(p) != m_blocks_sending.end())
614 m_blocks_sending.erase(p);
615 if(m_blocks_sent.find(p) != m_blocks_sent.end())
616 m_blocks_sent.erase(p);
619 void RemoteClient::SetBlocksNotSent(std::map<v3s16, MapBlock*> &blocks)
621 m_nearest_unsent_d = 0;
623 for(std::map<v3s16, MapBlock*>::iterator
625 i != blocks.end(); ++i)
629 if(m_blocks_sending.find(p) != m_blocks_sending.end())
630 m_blocks_sending.erase(p);
631 if(m_blocks_sent.find(p) != m_blocks_sent.end())
632 m_blocks_sent.erase(p);
641 const std::string &path_world,
642 const SubgameSpec &gamespec,
643 bool simple_singleplayer_mode
645 m_path_world(path_world),
646 m_gamespec(gamespec),
647 m_simple_singleplayer_mode(simple_singleplayer_mode),
648 m_async_fatal_error(""),
650 m_con(PROTOCOL_ID, 512, CONNECTION_TIMEOUT,
651 g_settings->getBool("enable_ipv6") && g_settings->getBool("ipv6_server"), this),
654 m_rollback_sink_enabled(true),
655 m_enable_rollback_recording(false),
658 m_itemdef(createItemDefManager()),
659 m_nodedef(createNodeDefManager()),
660 m_craftdef(createCraftDefManager()),
661 m_event(new EventManager()),
663 m_time_of_day_send_timer(0),
665 m_shutdown_requested(false),
666 m_ignore_map_edit_events(false),
667 m_ignore_map_edit_events_peer_id(0)
669 m_liquid_transform_timer = 0.0;
670 m_liquid_transform_every = 1.0;
671 m_print_info_timer = 0.0;
672 m_masterserver_timer = 0.0;
673 m_objectdata_timer = 0.0;
674 m_emergethread_trigger_timer = 0.0;
675 m_savemap_timer = 0.0;
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 world if it doesn't exist
707 if(!initializeWorld(m_path_world, m_gamespec.id))
708 throw ServerError("Failed to initialize world");
710 // Create ban manager
711 std::string ban_path = m_path_world+DIR_DELIM+"ipban.txt";
712 m_banmanager = new BanManager(ban_path);
714 // Create rollback manager
715 std::string rollback_path = m_path_world+DIR_DELIM+"rollback.txt";
716 m_rollback = createRollbackManager(rollback_path, this);
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);
826 servermap->setMapgenParams(m_emerge->params);
828 // Give environment reference to scripting api
829 m_script->initializeEnvironment(m_env);
831 // Register us to receive map edit events
832 servermap->addEventReceiver(this);
834 // If file exists, load environment metadata
835 if(fs::PathExists(m_path_world+DIR_DELIM+"env_meta.txt"))
837 infostream<<"Server: Loading environment metadata"<<std::endl;
838 m_env->loadMeta(m_path_world);
842 infostream<<"Server: Loading players"<<std::endl;
843 m_env->deSerializePlayers(m_path_world);
846 Add some test ActiveBlockModifiers to environment
848 add_legacy_abms(m_env, m_nodedef);
850 m_liquid_transform_every = g_settings->getFloat("liquid_update");
855 infostream<<"Server destructing"<<std::endl;
858 Send shutdown message
861 JMutexAutoLock conlock(m_con_mutex);
863 std::wstring line = L"*** Server shutting down";
866 Send the message to clients
868 for(std::map<u16, RemoteClient*>::iterator
869 i = m_clients.begin();
870 i != m_clients.end(); ++i)
872 // Get client and check that it is valid
873 RemoteClient *client = i->second;
874 assert(client->peer_id == i->first);
875 if(client->serialization_version == SER_FMT_VER_INVALID)
879 SendChatMessage(client->peer_id, line);
881 catch(con::PeerNotFoundException &e)
887 JMutexAutoLock envlock(m_env_mutex);
888 JMutexAutoLock conlock(m_con_mutex);
891 Execute script shutdown hooks
893 m_script->on_shutdown();
897 JMutexAutoLock envlock(m_env_mutex);
902 infostream<<"Server: Saving players"<<std::endl;
903 m_env->serializePlayers(m_path_world);
906 Save environment metadata
908 infostream<<"Server: Saving environment metadata"<<std::endl;
909 m_env->saveMeta(m_path_world);
918 //shutdown all emerge threads first!
925 JMutexAutoLock clientslock(m_con_mutex);
927 for(std::map<u16, RemoteClient*>::iterator
928 i = m_clients.begin();
929 i != m_clients.end(); ++i)
937 // Delete things in the reverse order of creation
946 // Deinitialize scripting
947 infostream<<"Server: Deinitializing scripting"<<std::endl;
950 // Delete detached inventories
952 for(std::map<std::string, Inventory*>::iterator
953 i = m_detached_inventories.begin();
954 i != m_detached_inventories.end(); i++){
960 void Server::start(unsigned short port)
962 DSTACK(__FUNCTION_NAME);
963 infostream<<"Starting server on port "<<port<<"..."<<std::endl;
965 // Stop thread if already running
968 // Initialize connection
969 m_con.SetTimeoutMs(30);
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)
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->startAllThreads();
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");
1975 if(m_script->on_prejoinplayer(playername, addr_s, reason))
1977 actionstream<<"Server: Player with the name \""<<playername<<"\" "
1978 <<"tried to connect from "<<addr_s<<" "
1979 <<"but it was disallowed for the following reason: "
1980 <<reason<<std::endl;
1981 DenyAccess(peer_id, narrow_to_wide(reason.c_str()));
1986 infostream<<"Server: New connection: \""<<playername<<"\" from "
1987 <<addr_s<<" (peer_id="<<peer_id<<")"<<std::endl;
1990 char given_password[PASSWORD_SIZE];
1991 if(datasize < 2+1+PLAYERNAME_SIZE+PASSWORD_SIZE)
1993 // old version - assume blank password
1994 given_password[0] = 0;
1998 for(u32 i=0; i<PASSWORD_SIZE-1; i++)
2000 given_password[i] = data[23+i];
2002 given_password[PASSWORD_SIZE-1] = 0;
2005 if(!base64_is_valid(given_password)){
2006 actionstream<<"Server: "<<playername
2007 <<" supplied invalid password hash"<<std::endl;
2008 DenyAccess(peer_id, L"Invalid password hash");
2012 // Enforce user limit.
2013 // Don't enforce for users that have some admin right
2014 if(m_clients.size() >= g_settings->getU16("max_users") &&
2015 !checkPriv(playername, "server") &&
2016 !checkPriv(playername, "ban") &&
2017 !checkPriv(playername, "privs") &&
2018 !checkPriv(playername, "password") &&
2019 playername != g_settings->get("name"))
2021 actionstream<<"Server: "<<playername<<" tried to join, but there"
2022 <<" are already max_users="
2023 <<g_settings->getU16("max_users")<<" players."<<std::endl;
2024 DenyAccess(peer_id, L"Too many users.");
2028 std::string checkpwd; // Password hash to check against
2029 bool has_auth = m_script->getAuth(playername, &checkpwd, NULL);
2031 // If no authentication info exists for user, create it
2033 if(!isSingleplayer() &&
2034 g_settings->getBool("disallow_empty_password") &&
2035 std::string(given_password) == ""){
2036 actionstream<<"Server: "<<playername
2037 <<" supplied empty password"<<std::endl;
2038 DenyAccess(peer_id, L"Empty passwords are "
2039 L"disallowed. Set a password and try again.");
2042 std::wstring raw_default_password =
2043 narrow_to_wide(g_settings->get("default_password"));
2044 std::string initial_password =
2045 translatePassword(playername, raw_default_password);
2047 // If default_password is empty, allow any initial password
2048 if (raw_default_password.length() == 0)
2049 initial_password = given_password;
2051 m_script->createAuth(playername, initial_password);
2054 has_auth = m_script->getAuth(playername, &checkpwd, NULL);
2057 actionstream<<"Server: "<<playername<<" cannot be authenticated"
2058 <<" (auth handler does not work?)"<<std::endl;
2059 DenyAccess(peer_id, L"Not allowed to login");
2063 if(given_password != checkpwd){
2064 actionstream<<"Server: "<<playername<<" supplied wrong password"
2066 DenyAccess(peer_id, L"Wrong password");
2071 PlayerSAO *playersao = emergePlayer(playername, peer_id);
2073 // If failed, cancel
2074 if(playersao == NULL)
2076 RemotePlayer *player =
2077 static_cast<RemotePlayer*>(m_env->getPlayer(playername));
2078 if(player && player->peer_id != 0){
2079 errorstream<<"Server: "<<playername<<": Failed to emerge player"
2080 <<" (player allocated to an another client)"<<std::endl;
2081 DenyAccess(peer_id, L"Another client is connected with this "
2082 L"name. If your client closed unexpectedly, try again in "
2085 errorstream<<"Server: "<<playername<<": Failed to emerge player"
2087 DenyAccess(peer_id, L"Could not allocate player.");
2093 Answer with a TOCLIENT_INIT
2096 SharedBuffer<u8> reply(2+1+6+8+4);
2097 writeU16(&reply[0], TOCLIENT_INIT);
2098 writeU8(&reply[2], deployed);
2099 writeV3S16(&reply[2+1], floatToInt(playersao->getPlayer()->getPosition()+v3f(0,BS/2,0), BS));
2100 writeU64(&reply[2+1+6], m_env->getServerMap().getSeed());
2101 writeF1000(&reply[2+1+6+8], g_settings->getFloat("dedicated_server_step"));
2104 m_con.Send(peer_id, 0, reply, true);
2108 Send complete position information
2110 SendMovePlayer(peer_id);
2115 if(command == TOSERVER_INIT2)
2117 verbosestream<<"Server: Got TOSERVER_INIT2 from "
2118 <<peer_id<<std::endl;
2120 Player *player = m_env->getPlayer(peer_id);
2122 verbosestream<<"Server: TOSERVER_INIT2: "
2123 <<"Player not found; ignoring."<<std::endl;
2127 RemoteClient *client = getClient(peer_id);
2128 client->serialization_version =
2129 getClient(peer_id)->pending_serialization_version;
2132 Send some initialization data
2135 infostream<<"Server: Sending content to "
2136 <<getPlayerName(peer_id)<<std::endl;
2138 // Send player movement settings
2139 SendMovement(m_con, peer_id);
2141 // Send item definitions
2142 SendItemDef(m_con, peer_id, m_itemdef, client->net_proto_version);
2144 // Send node definitions
2145 SendNodeDef(m_con, peer_id, m_nodedef, client->net_proto_version);
2147 // Send media announcement
2148 sendMediaAnnouncement(peer_id);
2151 SendPlayerPrivileges(peer_id);
2153 // Send inventory formspec
2154 SendPlayerInventoryFormspec(peer_id);
2157 UpdateCrafting(peer_id);
2158 SendInventory(peer_id);
2161 if(g_settings->getBool("enable_damage"))
2162 SendPlayerHP(peer_id);
2165 SendPlayerBreath(peer_id);
2167 // Send detached inventories
2168 sendDetachedInventories(peer_id);
2170 // Show death screen if necessary
2172 SendDeathscreen(m_con, peer_id, false, v3f(0,0,0));
2176 u16 time = m_env->getTimeOfDay();
2177 float time_speed = g_settings->getFloat("time_speed");
2178 SendTimeOfDay(peer_id, time, time_speed);
2181 // Note things in chat if not in simple singleplayer mode
2182 if(!m_simple_singleplayer_mode)
2184 // Send information about server to player in chat
2185 SendChatMessage(peer_id, getStatusString());
2187 // Send information about joining in chat
2189 std::wstring name = L"unknown";
2190 Player *player = m_env->getPlayer(peer_id);
2192 name = narrow_to_wide(player->getName());
2194 std::wstring message;
2197 message += L" joined the game.";
2198 BroadcastChatMessage(message);
2202 // Warnings about protocol version can be issued here
2203 if(getClient(peer_id)->net_proto_version < LATEST_PROTOCOL_VERSION)
2205 SendChatMessage(peer_id, L"# Server: WARNING: YOUR CLIENT'S "
2206 L"VERSION MAY NOT BE FULLY COMPATIBLE WITH THIS SERVER!");
2213 std::ostringstream os(std::ios_base::binary);
2214 for(std::map<u16, RemoteClient*>::iterator
2215 i = m_clients.begin();
2216 i != m_clients.end(); ++i)
2218 RemoteClient *client = i->second;
2219 assert(client->peer_id == i->first);
2220 if(client->serialization_version == SER_FMT_VER_INVALID)
2223 Player *player = m_env->getPlayer(client->peer_id);
2226 // Get name of player
2227 os<<player->getName()<<" ";
2230 actionstream<<player->getName()<<" ["<<addr_s<<"] "<<"joins game. List of players: "
2231 <<os.str()<<std::endl;
2237 if(peer_ser_ver == SER_FMT_VER_INVALID)
2239 infostream<<"Server::ProcessData(): Cancelling: Peer"
2240 " serialization format invalid or not initialized."
2241 " Skipping incoming command="<<command<<std::endl;
2245 Player *player = m_env->getPlayer(peer_id);
2247 infostream<<"Server::ProcessData(): Cancelling: "
2248 "No player for peer_id="<<peer_id
2253 PlayerSAO *playersao = player->getPlayerSAO();
2254 if(playersao == NULL){
2255 infostream<<"Server::ProcessData(): Cancelling: "
2256 "No player object for peer_id="<<peer_id
2261 if(command == TOSERVER_PLAYERPOS)
2263 if(datasize < 2+12+12+4+4)
2267 v3s32 ps = readV3S32(&data[start+2]);
2268 v3s32 ss = readV3S32(&data[start+2+12]);
2269 f32 pitch = (f32)readS32(&data[2+12+12]) / 100.0;
2270 f32 yaw = (f32)readS32(&data[2+12+12+4]) / 100.0;
2272 if(datasize >= 2+12+12+4+4+4)
2273 keyPressed = (u32)readU32(&data[2+12+12+4+4]);
2274 v3f position((f32)ps.X/100., (f32)ps.Y/100., (f32)ps.Z/100.);
2275 v3f speed((f32)ss.X/100., (f32)ss.Y/100., (f32)ss.Z/100.);
2276 pitch = wrapDegrees(pitch);
2277 yaw = wrapDegrees(yaw);
2279 player->setPosition(position);
2280 player->setSpeed(speed);
2281 player->setPitch(pitch);
2282 player->setYaw(yaw);
2283 player->keyPressed=keyPressed;
2284 player->control.up = (bool)(keyPressed&1);
2285 player->control.down = (bool)(keyPressed&2);
2286 player->control.left = (bool)(keyPressed&4);
2287 player->control.right = (bool)(keyPressed&8);
2288 player->control.jump = (bool)(keyPressed&16);
2289 player->control.aux1 = (bool)(keyPressed&32);
2290 player->control.sneak = (bool)(keyPressed&64);
2291 player->control.LMB = (bool)(keyPressed&128);
2292 player->control.RMB = (bool)(keyPressed&256);
2294 bool cheated = playersao->checkMovementCheat();
2297 m_script->on_cheat(playersao, "moved_too_fast");
2300 /*infostream<<"Server::ProcessData(): Moved player "<<peer_id<<" to "
2301 <<"("<<position.X<<","<<position.Y<<","<<position.Z<<")"
2302 <<" pitch="<<pitch<<" yaw="<<yaw<<std::endl;*/
2305 else if(command == TOSERVER_GOTBLOCKS)
2318 u16 count = data[2];
2319 for(u16 i=0; i<count; i++)
2321 if((s16)datasize < 2+1+(i+1)*6)
2322 throw con::InvalidIncomingDataException
2323 ("GOTBLOCKS length is too short");
2324 v3s16 p = readV3S16(&data[2+1+i*6]);
2325 /*infostream<<"Server: GOTBLOCKS ("
2326 <<p.X<<","<<p.Y<<","<<p.Z<<")"<<std::endl;*/
2327 RemoteClient *client = getClient(peer_id);
2328 client->GotBlock(p);
2331 else if(command == TOSERVER_DELETEDBLOCKS)
2344 u16 count = data[2];
2345 for(u16 i=0; i<count; i++)
2347 if((s16)datasize < 2+1+(i+1)*6)
2348 throw con::InvalidIncomingDataException
2349 ("DELETEDBLOCKS length is too short");
2350 v3s16 p = readV3S16(&data[2+1+i*6]);
2351 /*infostream<<"Server: DELETEDBLOCKS ("
2352 <<p.X<<","<<p.Y<<","<<p.Z<<")"<<std::endl;*/
2353 RemoteClient *client = getClient(peer_id);
2354 client->SetBlockNotSent(p);
2357 else if(command == TOSERVER_CLICK_OBJECT)
2359 infostream<<"Server: CLICK_OBJECT not supported anymore"<<std::endl;
2362 else if(command == TOSERVER_CLICK_ACTIVEOBJECT)
2364 infostream<<"Server: CLICK_ACTIVEOBJECT not supported anymore"<<std::endl;
2367 else if(command == TOSERVER_GROUND_ACTION)
2369 infostream<<"Server: GROUND_ACTION not supported anymore"<<std::endl;
2373 else if(command == TOSERVER_RELEASE)
2375 infostream<<"Server: RELEASE not supported anymore"<<std::endl;
2378 else if(command == TOSERVER_SIGNTEXT)
2380 infostream<<"Server: SIGNTEXT not supported anymore"
2384 else if(command == TOSERVER_SIGNNODETEXT)
2386 infostream<<"Server: SIGNNODETEXT not supported anymore"
2390 else if(command == TOSERVER_INVENTORY_ACTION)
2392 // Strip command and create a stream
2393 std::string datastring((char*)&data[2], datasize-2);
2394 verbosestream<<"TOSERVER_INVENTORY_ACTION: data="<<datastring<<std::endl;
2395 std::istringstream is(datastring, std::ios_base::binary);
2397 InventoryAction *a = InventoryAction::deSerialize(is);
2400 infostream<<"TOSERVER_INVENTORY_ACTION: "
2401 <<"InventoryAction::deSerialize() returned NULL"
2406 // If something goes wrong, this player is to blame
2407 RollbackScopeActor rollback_scope(m_rollback,
2408 std::string("player:")+player->getName());
2411 Note: Always set inventory not sent, to repair cases
2412 where the client made a bad prediction.
2416 Handle restrictions and special cases of the move action
2418 if(a->getType() == IACTION_MOVE)
2420 IMoveAction *ma = (IMoveAction*)a;
2422 ma->from_inv.applyCurrentPlayer(player->getName());
2423 ma->to_inv.applyCurrentPlayer(player->getName());
2425 setInventoryModified(ma->from_inv);
2426 setInventoryModified(ma->to_inv);
2428 bool from_inv_is_current_player =
2429 (ma->from_inv.type == InventoryLocation::PLAYER) &&
2430 (ma->from_inv.name == player->getName());
2432 bool to_inv_is_current_player =
2433 (ma->to_inv.type == InventoryLocation::PLAYER) &&
2434 (ma->to_inv.name == player->getName());
2437 Disable moving items out of craftpreview
2439 if(ma->from_list == "craftpreview")
2441 infostream<<"Ignoring IMoveAction from "
2442 <<(ma->from_inv.dump())<<":"<<ma->from_list
2443 <<" to "<<(ma->to_inv.dump())<<":"<<ma->to_list
2444 <<" because src is "<<ma->from_list<<std::endl;
2450 Disable moving items into craftresult and craftpreview
2452 if(ma->to_list == "craftpreview" || ma->to_list == "craftresult")
2454 infostream<<"Ignoring IMoveAction from "
2455 <<(ma->from_inv.dump())<<":"<<ma->from_list
2456 <<" to "<<(ma->to_inv.dump())<<":"<<ma->to_list
2457 <<" because dst is "<<ma->to_list<<std::endl;
2462 // Disallow moving items in elsewhere than player's inventory
2463 // if not allowed to interact
2464 if(!checkPriv(player->getName(), "interact") &&
2465 (!from_inv_is_current_player ||
2466 !to_inv_is_current_player))
2468 infostream<<"Cannot move outside of player's inventory: "
2469 <<"No interact privilege"<<std::endl;
2475 Handle restrictions and special cases of the drop action
2477 else if(a->getType() == IACTION_DROP)
2479 IDropAction *da = (IDropAction*)a;
2481 da->from_inv.applyCurrentPlayer(player->getName());
2483 setInventoryModified(da->from_inv);
2486 Disable dropping items out of craftpreview
2488 if(da->from_list == "craftpreview")
2490 infostream<<"Ignoring IDropAction from "
2491 <<(da->from_inv.dump())<<":"<<da->from_list
2492 <<" because src is "<<da->from_list<<std::endl;
2497 // Disallow dropping items if not allowed to interact
2498 if(!checkPriv(player->getName(), "interact"))
2505 Handle restrictions and special cases of the craft action
2507 else if(a->getType() == IACTION_CRAFT)
2509 ICraftAction *ca = (ICraftAction*)a;
2511 ca->craft_inv.applyCurrentPlayer(player->getName());
2513 setInventoryModified(ca->craft_inv);
2515 //bool craft_inv_is_current_player =
2516 // (ca->craft_inv.type == InventoryLocation::PLAYER) &&
2517 // (ca->craft_inv.name == player->getName());
2519 // Disallow crafting if not allowed to interact
2520 if(!checkPriv(player->getName(), "interact"))
2522 infostream<<"Cannot craft: "
2523 <<"No interact privilege"<<std::endl;
2530 a->apply(this, playersao, this);
2534 else if(command == TOSERVER_CHAT_MESSAGE)
2542 std::string datastring((char*)&data[2], datasize-2);
2543 std::istringstream is(datastring, std::ios_base::binary);
2546 is.read((char*)buf, 2);
2547 u16 len = readU16(buf);
2549 std::wstring message;
2550 for(u16 i=0; i<len; i++)
2552 is.read((char*)buf, 2);
2553 message += (wchar_t)readU16(buf);
2556 // If something goes wrong, this player is to blame
2557 RollbackScopeActor rollback_scope(m_rollback,
2558 std::string("player:")+player->getName());
2560 // Get player name of this client
2561 std::wstring name = narrow_to_wide(player->getName());
2564 bool ate = m_script->on_chat_message(player->getName(),
2565 wide_to_narrow(message));
2566 // If script ate the message, don't proceed
2570 // Line to send to players
2572 // Whether to send to the player that sent the line
2573 bool send_to_sender = false;
2574 // Whether to send to other players
2575 bool send_to_others = false;
2577 // Commands are implemented in Lua, so only catch invalid
2578 // commands that were not "eaten" and send an error back
2579 if(message[0] == L'/')
2581 message = message.substr(1);
2582 send_to_sender = true;
2583 if(message.length() == 0)
2584 line += L"-!- Empty command";
2586 line += L"-!- Invalid command: " + str_split(message, L' ')[0];
2590 if(checkPriv(player->getName(), "shout")){
2595 send_to_others = true;
2597 line += L"-!- You don't have permission to shout.";
2598 send_to_sender = true;
2605 actionstream<<"CHAT: "<<wide_to_narrow(line)<<std::endl;
2608 Send the message to clients
2610 for(std::map<u16, RemoteClient*>::iterator
2611 i = m_clients.begin();
2612 i != m_clients.end(); ++i)
2614 // Get client and check that it is valid
2615 RemoteClient *client = i->second;
2616 assert(client->peer_id == i->first);
2617 if(client->serialization_version == SER_FMT_VER_INVALID)
2621 bool sender_selected = (peer_id == client->peer_id);
2622 if(sender_selected == true && send_to_sender == false)
2624 if(sender_selected == false && send_to_others == false)
2627 SendChatMessage(client->peer_id, line);
2631 else if(command == TOSERVER_DAMAGE)
2633 std::string datastring((char*)&data[2], datasize-2);
2634 std::istringstream is(datastring, std::ios_base::binary);
2635 u8 damage = readU8(is);
2637 if(g_settings->getBool("enable_damage"))
2639 actionstream<<player->getName()<<" damaged by "
2640 <<(int)damage<<" hp at "<<PP(player->getPosition()/BS)
2643 playersao->setHP(playersao->getHP() - damage);
2645 if(playersao->getHP() == 0 && playersao->m_hp_not_sent)
2648 if(playersao->m_hp_not_sent)
2649 SendPlayerHP(peer_id);
2652 else if(command == TOSERVER_BREATH)
2654 std::string datastring((char*)&data[2], datasize-2);
2655 std::istringstream is(datastring, std::ios_base::binary);
2656 u16 breath = readU16(is);
2657 playersao->setBreath(breath);
2659 else if(command == TOSERVER_PASSWORD)
2662 [0] u16 TOSERVER_PASSWORD
2663 [2] u8[28] old password
2664 [30] u8[28] new password
2667 if(datasize != 2+PASSWORD_SIZE*2)
2669 /*char password[PASSWORD_SIZE];
2670 for(u32 i=0; i<PASSWORD_SIZE-1; i++)
2671 password[i] = data[2+i];
2672 password[PASSWORD_SIZE-1] = 0;*/
2674 for(u32 i=0; i<PASSWORD_SIZE-1; i++)
2682 for(u32 i=0; i<PASSWORD_SIZE-1; i++)
2684 char c = data[2+PASSWORD_SIZE+i];
2690 if(!base64_is_valid(newpwd)){
2691 infostream<<"Server: "<<player->getName()<<" supplied invalid password hash"<<std::endl;
2692 // Wrong old password supplied!!
2693 SendChatMessage(peer_id, L"Invalid new password hash supplied. Password NOT changed.");
2697 infostream<<"Server: Client requests a password change from "
2698 <<"'"<<oldpwd<<"' to '"<<newpwd<<"'"<<std::endl;
2700 std::string playername = player->getName();
2702 std::string checkpwd;
2703 m_script->getAuth(playername, &checkpwd, NULL);
2705 if(oldpwd != checkpwd)
2707 infostream<<"Server: invalid old password"<<std::endl;
2708 // Wrong old password supplied!!
2709 SendChatMessage(peer_id, L"Invalid old password supplied. Password NOT changed.");
2713 bool success = m_script->setPassword(playername, newpwd);
2715 actionstream<<player->getName()<<" changes password"<<std::endl;
2716 SendChatMessage(peer_id, L"Password change successful.");
2718 actionstream<<player->getName()<<" tries to change password but "
2719 <<"it fails"<<std::endl;
2720 SendChatMessage(peer_id, L"Password change failed or inavailable.");
2723 else if(command == TOSERVER_PLAYERITEM)
2728 u16 item = readU16(&data[2]);
2729 playersao->setWieldIndex(item);
2731 else if(command == TOSERVER_RESPAWN)
2733 if(player->hp != 0 || !g_settings->getBool("enable_damage"))
2736 RespawnPlayer(peer_id);
2738 actionstream<<player->getName()<<" respawns at "
2739 <<PP(player->getPosition()/BS)<<std::endl;
2741 // ActiveObject is added to environment in AsyncRunStep after
2742 // the previous addition has been succesfully removed
2744 else if(command == TOSERVER_REQUEST_MEDIA) {
2745 std::string datastring((char*)&data[2], datasize-2);
2746 std::istringstream is(datastring, std::ios_base::binary);
2748 std::list<std::string> tosend;
2749 u16 numfiles = readU16(is);
2751 infostream<<"Sending "<<numfiles<<" files to "
2752 <<getPlayerName(peer_id)<<std::endl;
2753 verbosestream<<"TOSERVER_REQUEST_MEDIA: "<<std::endl;
2755 for(int i = 0; i < numfiles; i++) {
2756 std::string name = deSerializeString(is);
2757 tosend.push_back(name);
2758 verbosestream<<"TOSERVER_REQUEST_MEDIA: requested file "
2762 sendRequestedMedia(peer_id, tosend);
2764 // Now the client should know about everything
2765 // (definitions and files)
2766 getClient(peer_id)->definitions_sent = true;
2768 else if(command == TOSERVER_RECEIVED_MEDIA) {
2769 getClient(peer_id)->definitions_sent = true;
2771 else if(command == TOSERVER_INTERACT)
2773 std::string datastring((char*)&data[2], datasize-2);
2774 std::istringstream is(datastring, std::ios_base::binary);
2780 [5] u32 length of the next item
2781 [9] serialized PointedThing
2783 0: start digging (from undersurface) or use
2784 1: stop digging (all parameters ignored)
2785 2: digging completed
2786 3: place block or item (to abovesurface)
2789 u8 action = readU8(is);
2790 u16 item_i = readU16(is);
2791 std::istringstream tmp_is(deSerializeLongString(is), std::ios::binary);
2792 PointedThing pointed;
2793 pointed.deSerialize(tmp_is);
2795 verbosestream<<"TOSERVER_INTERACT: action="<<(int)action<<", item="
2796 <<item_i<<", pointed="<<pointed.dump()<<std::endl;
2800 verbosestream<<"TOSERVER_INTERACT: "<<player->getName()
2801 <<" tried to interact, but is dead!"<<std::endl;
2805 v3f player_pos = playersao->getLastGoodPosition();
2807 // Update wielded item
2808 playersao->setWieldIndex(item_i);
2810 // Get pointed to node (undefined if not POINTEDTYPE_NODE)
2811 v3s16 p_under = pointed.node_undersurface;
2812 v3s16 p_above = pointed.node_abovesurface;
2814 // Get pointed to object (NULL if not POINTEDTYPE_OBJECT)
2815 ServerActiveObject *pointed_object = NULL;
2816 if(pointed.type == POINTEDTHING_OBJECT)
2818 pointed_object = m_env->getActiveObject(pointed.object_id);
2819 if(pointed_object == NULL)
2821 verbosestream<<"TOSERVER_INTERACT: "
2822 "pointed object is NULL"<<std::endl;
2828 v3f pointed_pos_under = player_pos;
2829 v3f pointed_pos_above = player_pos;
2830 if(pointed.type == POINTEDTHING_NODE)
2832 pointed_pos_under = intToFloat(p_under, BS);
2833 pointed_pos_above = intToFloat(p_above, BS);
2835 else if(pointed.type == POINTEDTHING_OBJECT)
2837 pointed_pos_under = pointed_object->getBasePosition();
2838 pointed_pos_above = pointed_pos_under;
2842 Check that target is reasonably close
2843 (only when digging or placing things)
2845 if(action == 0 || action == 2 || action == 3)
2847 float d = player_pos.getDistanceFrom(pointed_pos_under);
2848 float max_d = BS * 14; // Just some large enough value
2850 actionstream<<"Player "<<player->getName()
2851 <<" tried to access "<<pointed.dump()
2853 <<"d="<<d<<", max_d="<<max_d
2854 <<". ignoring."<<std::endl;
2855 // Re-send block to revert change on client-side
2856 RemoteClient *client = getClient(peer_id);
2857 v3s16 blockpos = getNodeBlockPos(floatToInt(pointed_pos_under, BS));
2858 client->SetBlockNotSent(blockpos);
2860 m_script->on_cheat(playersao, "interacted_too_far");
2867 Make sure the player is allowed to do it
2869 if(!checkPriv(player->getName(), "interact"))
2871 actionstream<<player->getName()<<" attempted to interact with "
2872 <<pointed.dump()<<" without 'interact' privilege"
2874 // Re-send block to revert change on client-side
2875 RemoteClient *client = getClient(peer_id);
2876 // Digging completed -> under
2878 v3s16 blockpos = getNodeBlockPos(floatToInt(pointed_pos_under, BS));
2879 client->SetBlockNotSent(blockpos);
2881 // Placement -> above
2883 v3s16 blockpos = getNodeBlockPos(floatToInt(pointed_pos_above, BS));
2884 client->SetBlockNotSent(blockpos);
2890 If something goes wrong, this player is to blame
2892 RollbackScopeActor rollback_scope(m_rollback,
2893 std::string("player:")+player->getName());
2896 0: start digging or punch object
2900 if(pointed.type == POINTEDTHING_NODE)
2903 NOTE: This can be used in the future to check if
2904 somebody is cheating, by checking the timing.
2906 MapNode n(CONTENT_IGNORE);
2909 n = m_env->getMap().getNode(p_under);
2911 catch(InvalidPositionException &e)
2913 infostream<<"Server: Not punching: Node not found."
2914 <<" Adding block to emerge queue."
2916 m_emerge->enqueueBlockEmerge(peer_id, getNodeBlockPos(p_above), false);
2918 if(n.getContent() != CONTENT_IGNORE)
2919 m_script->node_on_punch(p_under, n, playersao);
2921 playersao->noCheatDigStart(p_under);
2923 else if(pointed.type == POINTEDTHING_OBJECT)
2925 // Skip if object has been removed
2926 if(pointed_object->m_removed)
2929 actionstream<<player->getName()<<" punches object "
2930 <<pointed.object_id<<": "
2931 <<pointed_object->getDescription()<<std::endl;
2933 ItemStack punchitem = playersao->getWieldedItem();
2934 ToolCapabilities toolcap =
2935 punchitem.getToolCapabilities(m_itemdef);
2936 v3f dir = (pointed_object->getBasePosition() -
2937 (player->getPosition() + player->getEyeOffset())
2939 float time_from_last_punch =
2940 playersao->resetTimeFromLastPunch();
2941 pointed_object->punch(dir, &toolcap, playersao,
2942 time_from_last_punch);
2950 else if(action == 1)
2955 2: Digging completed
2957 else if(action == 2)
2959 // Only digging of nodes
2960 if(pointed.type == POINTEDTHING_NODE)
2962 MapNode n(CONTENT_IGNORE);
2965 n = m_env->getMap().getNode(p_under);
2967 catch(InvalidPositionException &e)
2969 infostream<<"Server: Not finishing digging: Node not found."
2970 <<" Adding block to emerge queue."
2972 m_emerge->enqueueBlockEmerge(peer_id, getNodeBlockPos(p_above), false);
2975 /* Cheat prevention */
2976 bool is_valid_dig = true;
2977 if(!isSingleplayer() && !g_settings->getBool("disable_anticheat"))
2979 v3s16 nocheat_p = playersao->getNoCheatDigPos();
2980 float nocheat_t = playersao->getNoCheatDigTime();
2981 playersao->noCheatDigEnd();
2982 // If player didn't start digging this, ignore dig
2983 if(nocheat_p != p_under){
2984 infostream<<"Server: NoCheat: "<<player->getName()
2985 <<" started digging "
2986 <<PP(nocheat_p)<<" and completed digging "
2987 <<PP(p_under)<<"; not digging."<<std::endl;
2988 is_valid_dig = false;
2990 m_script->on_cheat(playersao, "finished_unknown_dig");
2992 // Get player's wielded item
2993 ItemStack playeritem;
2994 InventoryList *mlist = playersao->getInventory()->getList("main");
2996 playeritem = mlist->getItem(playersao->getWieldIndex());
2997 ToolCapabilities playeritem_toolcap =
2998 playeritem.getToolCapabilities(m_itemdef);
2999 // Get diggability and expected digging time
3000 DigParams params = getDigParams(m_nodedef->get(n).groups,
3001 &playeritem_toolcap);
3002 // If can't dig, try hand
3003 if(!params.diggable){
3004 const ItemDefinition &hand = m_itemdef->get("");
3005 const ToolCapabilities *tp = hand.tool_capabilities;
3007 params = getDigParams(m_nodedef->get(n).groups, tp);
3009 // If can't dig, ignore dig
3010 if(!params.diggable){
3011 infostream<<"Server: NoCheat: "<<player->getName()
3012 <<" completed digging "<<PP(p_under)
3013 <<", which is not diggable with tool. not digging."
3015 is_valid_dig = false;
3017 m_script->on_cheat(playersao, "dug_unbreakable");
3019 // Check digging time
3020 // If already invalidated, we don't have to
3022 // Well not our problem then
3024 // Clean and long dig
3025 else if(params.time > 2.0 && nocheat_t * 1.2 > params.time){
3026 // All is good, but grab time from pool; don't care if
3027 // it's actually available
3028 playersao->getDigPool().grab(params.time);
3030 // Short or laggy dig
3031 // Try getting the time from pool
3032 else if(playersao->getDigPool().grab(params.time)){
3037 infostream<<"Server: NoCheat: "<<player->getName()
3038 <<" completed digging "<<PP(p_under)
3039 <<"too fast; not digging."<<std::endl;
3040 is_valid_dig = false;
3042 m_script->on_cheat(playersao, "dug_too_fast");
3046 /* Actually dig node */
3048 if(is_valid_dig && n.getContent() != CONTENT_IGNORE)
3049 m_script->node_on_dig(p_under, n, playersao);
3051 // Send unusual result (that is, node not being removed)
3052 if(m_env->getMap().getNodeNoEx(p_under).getContent() != CONTENT_AIR)
3054 // Re-send block to revert change on client-side
3055 RemoteClient *client = getClient(peer_id);
3056 v3s16 blockpos = getNodeBlockPos(floatToInt(pointed_pos_under, BS));
3057 client->SetBlockNotSent(blockpos);
3063 3: place block or right-click object
3065 else if(action == 3)
3067 ItemStack item = playersao->getWieldedItem();
3069 // Reset build time counter
3070 if(pointed.type == POINTEDTHING_NODE &&
3071 item.getDefinition(m_itemdef).type == ITEM_NODE)
3072 getClient(peer_id)->m_time_from_building = 0.0;
3074 if(pointed.type == POINTEDTHING_OBJECT)
3076 // Right click object
3078 // Skip if object has been removed
3079 if(pointed_object->m_removed)
3082 actionstream<<player->getName()<<" right-clicks object "
3083 <<pointed.object_id<<": "
3084 <<pointed_object->getDescription()<<std::endl;
3087 pointed_object->rightClick(playersao);
3089 else if(m_script->item_OnPlace(
3090 item, playersao, pointed))
3092 // Placement was handled in lua
3094 // Apply returned ItemStack
3095 playersao->setWieldedItem(item);
3098 // If item has node placement prediction, always send the
3099 // blocks to make sure the client knows what exactly happened
3100 if(item.getDefinition(m_itemdef).node_placement_prediction != ""){
3101 RemoteClient *client = getClient(peer_id);
3102 v3s16 blockpos = getNodeBlockPos(floatToInt(pointed_pos_above, BS));
3103 client->SetBlockNotSent(blockpos);
3104 v3s16 blockpos2 = getNodeBlockPos(floatToInt(pointed_pos_under, BS));
3105 if(blockpos2 != blockpos){
3106 client->SetBlockNotSent(blockpos2);
3114 else if(action == 4)
3116 ItemStack item = playersao->getWieldedItem();
3118 actionstream<<player->getName()<<" uses "<<item.name
3119 <<", pointing at "<<pointed.dump()<<std::endl;
3121 if(m_script->item_OnUse(
3122 item, playersao, pointed))
3124 // Apply returned ItemStack
3125 playersao->setWieldedItem(item);
3132 Catch invalid actions
3136 infostream<<"WARNING: Server: Invalid action "
3137 <<action<<std::endl;
3140 else if(command == TOSERVER_REMOVED_SOUNDS)
3142 std::string datastring((char*)&data[2], datasize-2);
3143 std::istringstream is(datastring, std::ios_base::binary);
3145 int num = readU16(is);
3146 for(int k=0; k<num; k++){
3147 s32 id = readS32(is);
3148 std::map<s32, ServerPlayingSound>::iterator i =
3149 m_playing_sounds.find(id);
3150 if(i == m_playing_sounds.end())
3152 ServerPlayingSound &psound = i->second;
3153 psound.clients.erase(peer_id);
3154 if(psound.clients.size() == 0)
3155 m_playing_sounds.erase(i++);
3158 else if(command == TOSERVER_NODEMETA_FIELDS)
3160 std::string datastring((char*)&data[2], datasize-2);
3161 std::istringstream is(datastring, std::ios_base::binary);
3163 v3s16 p = readV3S16(is);
3164 std::string formname = deSerializeString(is);
3165 int num = readU16(is);
3166 std::map<std::string, std::string> fields;
3167 for(int k=0; k<num; k++){
3168 std::string fieldname = deSerializeString(is);
3169 std::string fieldvalue = deSerializeLongString(is);
3170 fields[fieldname] = fieldvalue;
3173 // If something goes wrong, this player is to blame
3174 RollbackScopeActor rollback_scope(m_rollback,
3175 std::string("player:")+player->getName());
3177 // Check the target node for rollback data; leave others unnoticed
3178 RollbackNode rn_old(&m_env->getMap(), p, this);
3180 m_script->node_on_receive_fields(p, formname, fields,playersao);
3182 // Report rollback data
3183 RollbackNode rn_new(&m_env->getMap(), p, this);
3184 if(rollback() && rn_new != rn_old){
3185 RollbackAction action;
3186 action.setSetNode(p, rn_old, rn_new);
3187 rollback()->reportAction(action);
3190 else if(command == TOSERVER_INVENTORY_FIELDS)
3192 std::string datastring((char*)&data[2], datasize-2);
3193 std::istringstream is(datastring, std::ios_base::binary);
3195 std::string formname = deSerializeString(is);
3196 int num = readU16(is);
3197 std::map<std::string, std::string> fields;
3198 for(int k=0; k<num; k++){
3199 std::string fieldname = deSerializeString(is);
3200 std::string fieldvalue = deSerializeLongString(is);
3201 fields[fieldname] = fieldvalue;
3204 m_script->on_playerReceiveFields(playersao, formname, fields);
3208 infostream<<"Server::ProcessData(): Ignoring "
3209 "unknown command "<<command<<std::endl;
3213 catch(SendFailedException &e)
3215 errorstream<<"Server::ProcessData(): SendFailedException: "
3221 void Server::setTimeOfDay(u32 time)
3223 m_env->setTimeOfDay(time);
3224 m_time_of_day_send_timer = 0;
3227 void Server::onMapEditEvent(MapEditEvent *event)
3229 //infostream<<"Server::onMapEditEvent()"<<std::endl;
3230 if(m_ignore_map_edit_events)
3232 if(m_ignore_map_edit_events_area.contains(event->getArea()))
3234 MapEditEvent *e = event->clone();
3235 m_unsent_map_edit_queue.push_back(e);
3238 Inventory* Server::getInventory(const InventoryLocation &loc)
3241 case InventoryLocation::UNDEFINED:
3244 case InventoryLocation::CURRENT_PLAYER:
3247 case InventoryLocation::PLAYER:
3249 Player *player = m_env->getPlayer(loc.name.c_str());
3252 PlayerSAO *playersao = player->getPlayerSAO();
3255 return playersao->getInventory();
3258 case InventoryLocation::NODEMETA:
3260 NodeMetadata *meta = m_env->getMap().getNodeMetadata(loc.p);
3263 return meta->getInventory();
3266 case InventoryLocation::DETACHED:
3268 if(m_detached_inventories.count(loc.name) == 0)
3270 return m_detached_inventories[loc.name];
3278 void Server::setInventoryModified(const InventoryLocation &loc)
3281 case InventoryLocation::UNDEFINED:
3284 case InventoryLocation::PLAYER:
3286 Player *player = m_env->getPlayer(loc.name.c_str());
3289 PlayerSAO *playersao = player->getPlayerSAO();
3292 playersao->m_inventory_not_sent = true;
3293 playersao->m_wielded_item_not_sent = true;
3296 case InventoryLocation::NODEMETA:
3298 v3s16 blockpos = getNodeBlockPos(loc.p);
3300 MapBlock *block = m_env->getMap().getBlockNoCreateNoEx(blockpos);
3302 block->raiseModified(MOD_STATE_WRITE_NEEDED);
3304 setBlockNotSent(blockpos);
3307 case InventoryLocation::DETACHED:
3309 sendDetachedInventoryToAll(loc.name);
3317 void Server::peerAdded(con::Peer *peer)
3319 DSTACK(__FUNCTION_NAME);
3320 verbosestream<<"Server::peerAdded(): peer->id="
3321 <<peer->id<<std::endl;
3324 c.type = PEER_ADDED;
3325 c.peer_id = peer->id;
3327 m_peer_change_queue.push_back(c);
3330 void Server::deletingPeer(con::Peer *peer, bool timeout)
3332 DSTACK(__FUNCTION_NAME);
3333 verbosestream<<"Server::deletingPeer(): peer->id="
3334 <<peer->id<<", timeout="<<timeout<<std::endl;
3337 c.type = PEER_REMOVED;
3338 c.peer_id = peer->id;
3339 c.timeout = timeout;
3340 m_peer_change_queue.push_back(c);
3347 void Server::SendMovement(con::Connection &con, u16 peer_id)
3349 DSTACK(__FUNCTION_NAME);
3350 std::ostringstream os(std::ios_base::binary);
3352 writeU16(os, TOCLIENT_MOVEMENT);
3353 writeF1000(os, g_settings->getFloat("movement_acceleration_default"));
3354 writeF1000(os, g_settings->getFloat("movement_acceleration_air"));
3355 writeF1000(os, g_settings->getFloat("movement_acceleration_fast"));
3356 writeF1000(os, g_settings->getFloat("movement_speed_walk"));
3357 writeF1000(os, g_settings->getFloat("movement_speed_crouch"));
3358 writeF1000(os, g_settings->getFloat("movement_speed_fast"));
3359 writeF1000(os, g_settings->getFloat("movement_speed_climb"));
3360 writeF1000(os, g_settings->getFloat("movement_speed_jump"));
3361 writeF1000(os, g_settings->getFloat("movement_liquid_fluidity"));
3362 writeF1000(os, g_settings->getFloat("movement_liquid_fluidity_smooth"));
3363 writeF1000(os, g_settings->getFloat("movement_liquid_sink"));
3364 writeF1000(os, g_settings->getFloat("movement_gravity"));
3367 std::string s = os.str();
3368 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3370 con.Send(peer_id, 0, data, true);
3373 void Server::SendHP(con::Connection &con, u16 peer_id, u8 hp)
3375 DSTACK(__FUNCTION_NAME);
3376 std::ostringstream os(std::ios_base::binary);
3378 writeU16(os, TOCLIENT_HP);
3382 std::string s = os.str();
3383 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3385 con.Send(peer_id, 0, data, true);
3388 void Server::SendBreath(con::Connection &con, u16 peer_id, u16 breath)
3390 DSTACK(__FUNCTION_NAME);
3391 std::ostringstream os(std::ios_base::binary);
3393 writeU16(os, TOCLIENT_BREATH);
3394 writeU16(os, breath);
3397 std::string s = os.str();
3398 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3400 con.Send(peer_id, 0, data, true);
3403 void Server::SendAccessDenied(con::Connection &con, u16 peer_id,
3404 const std::wstring &reason)
3406 DSTACK(__FUNCTION_NAME);
3407 std::ostringstream os(std::ios_base::binary);
3409 writeU16(os, TOCLIENT_ACCESS_DENIED);
3410 os<<serializeWideString(reason);
3413 std::string s = os.str();
3414 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3416 con.Send(peer_id, 0, data, true);
3419 void Server::SendDeathscreen(con::Connection &con, u16 peer_id,
3420 bool set_camera_point_target, v3f camera_point_target)
3422 DSTACK(__FUNCTION_NAME);
3423 std::ostringstream os(std::ios_base::binary);
3425 writeU16(os, TOCLIENT_DEATHSCREEN);
3426 writeU8(os, set_camera_point_target);
3427 writeV3F1000(os, camera_point_target);
3430 std::string s = os.str();
3431 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3433 con.Send(peer_id, 0, data, true);
3436 void Server::SendItemDef(con::Connection &con, u16 peer_id,
3437 IItemDefManager *itemdef, u16 protocol_version)
3439 DSTACK(__FUNCTION_NAME);
3440 std::ostringstream os(std::ios_base::binary);
3444 u32 length of the next item
3445 zlib-compressed serialized ItemDefManager
3447 writeU16(os, TOCLIENT_ITEMDEF);
3448 std::ostringstream tmp_os(std::ios::binary);
3449 itemdef->serialize(tmp_os, protocol_version);
3450 std::ostringstream tmp_os2(std::ios::binary);
3451 compressZlib(tmp_os.str(), tmp_os2);
3452 os<<serializeLongString(tmp_os2.str());
3455 std::string s = os.str();
3456 verbosestream<<"Server: Sending item definitions to id("<<peer_id
3457 <<"): size="<<s.size()<<std::endl;
3458 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3460 con.Send(peer_id, 0, data, true);
3463 void Server::SendNodeDef(con::Connection &con, u16 peer_id,
3464 INodeDefManager *nodedef, u16 protocol_version)
3466 DSTACK(__FUNCTION_NAME);
3467 std::ostringstream os(std::ios_base::binary);
3471 u32 length of the next item
3472 zlib-compressed serialized NodeDefManager
3474 writeU16(os, TOCLIENT_NODEDEF);
3475 std::ostringstream tmp_os(std::ios::binary);
3476 nodedef->serialize(tmp_os, protocol_version);
3477 std::ostringstream tmp_os2(std::ios::binary);
3478 compressZlib(tmp_os.str(), tmp_os2);
3479 os<<serializeLongString(tmp_os2.str());
3482 std::string s = os.str();
3483 verbosestream<<"Server: Sending node definitions to id("<<peer_id
3484 <<"): size="<<s.size()<<std::endl;
3485 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3487 con.Send(peer_id, 0, data, true);
3491 Non-static send methods
3494 void Server::SendInventory(u16 peer_id)
3496 DSTACK(__FUNCTION_NAME);
3498 PlayerSAO *playersao = getPlayerSAO(peer_id);
3501 playersao->m_inventory_not_sent = false;
3507 std::ostringstream os;
3508 playersao->getInventory()->serialize(os);
3510 std::string s = os.str();
3512 SharedBuffer<u8> data(s.size()+2);
3513 writeU16(&data[0], TOCLIENT_INVENTORY);
3514 memcpy(&data[2], s.c_str(), s.size());
3517 m_con.Send(peer_id, 0, data, true);
3520 void Server::SendChatMessage(u16 peer_id, const std::wstring &message)
3522 DSTACK(__FUNCTION_NAME);
3524 std::ostringstream os(std::ios_base::binary);
3528 writeU16(buf, TOCLIENT_CHAT_MESSAGE);
3529 os.write((char*)buf, 2);
3532 writeU16(buf, message.size());
3533 os.write((char*)buf, 2);
3536 for(u32 i=0; i<message.size(); i++)
3540 os.write((char*)buf, 2);
3544 std::string s = os.str();
3545 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3547 m_con.Send(peer_id, 0, data, true);
3550 void Server::SendShowFormspecMessage(u16 peer_id, const std::string formspec,
3551 const std::string formname)
3553 DSTACK(__FUNCTION_NAME);
3555 std::ostringstream os(std::ios_base::binary);
3559 writeU16(buf, TOCLIENT_SHOW_FORMSPEC);
3560 os.write((char*)buf, 2);
3561 os<<serializeLongString(formspec);
3562 os<<serializeString(formname);
3565 std::string s = os.str();
3566 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3568 m_con.Send(peer_id, 0, data, true);
3571 // Spawns a particle on peer with peer_id
3572 void Server::SendSpawnParticle(u16 peer_id, v3f pos, v3f velocity, v3f acceleration,
3573 float expirationtime, float size, bool collisiondetection,
3574 std::string texture)
3576 DSTACK(__FUNCTION_NAME);
3578 std::ostringstream os(std::ios_base::binary);
3579 writeU16(os, TOCLIENT_SPAWN_PARTICLE);
3580 writeV3F1000(os, pos);
3581 writeV3F1000(os, velocity);
3582 writeV3F1000(os, acceleration);
3583 writeF1000(os, expirationtime);
3584 writeF1000(os, size);
3585 writeU8(os, collisiondetection);
3586 os<<serializeLongString(texture);
3589 std::string s = os.str();
3590 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3592 m_con.Send(peer_id, 0, data, true);
3595 // Spawns a particle on all peers
3596 void Server::SendSpawnParticleAll(v3f pos, v3f velocity, v3f acceleration,
3597 float expirationtime, float size, bool collisiondetection,
3598 std::string texture)
3600 for(std::map<u16, RemoteClient*>::iterator
3601 i = m_clients.begin();
3602 i != m_clients.end(); i++)
3604 // Get client and check that it is valid
3605 RemoteClient *client = i->second;
3606 assert(client->peer_id == i->first);
3607 if(client->serialization_version == SER_FMT_VER_INVALID)
3610 SendSpawnParticle(client->peer_id, pos, velocity, acceleration,
3611 expirationtime, size, collisiondetection, texture);
3615 // Adds a ParticleSpawner on peer with peer_id
3616 void Server::SendAddParticleSpawner(u16 peer_id, u16 amount, float spawntime, v3f minpos, v3f maxpos,
3617 v3f minvel, v3f maxvel, v3f minacc, v3f maxacc, float minexptime, float maxexptime,
3618 float minsize, float maxsize, bool collisiondetection, std::string texture, u32 id)
3620 DSTACK(__FUNCTION_NAME);
3622 std::ostringstream os(std::ios_base::binary);
3623 writeU16(os, TOCLIENT_ADD_PARTICLESPAWNER);
3625 writeU16(os, amount);
3626 writeF1000(os, spawntime);
3627 writeV3F1000(os, minpos);
3628 writeV3F1000(os, maxpos);
3629 writeV3F1000(os, minvel);
3630 writeV3F1000(os, maxvel);
3631 writeV3F1000(os, minacc);
3632 writeV3F1000(os, maxacc);
3633 writeF1000(os, minexptime);
3634 writeF1000(os, maxexptime);
3635 writeF1000(os, minsize);
3636 writeF1000(os, maxsize);
3637 writeU8(os, collisiondetection);
3638 os<<serializeLongString(texture);
3642 std::string s = os.str();
3643 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3645 m_con.Send(peer_id, 0, data, true);
3648 // Adds a ParticleSpawner on all peers
3649 void Server::SendAddParticleSpawnerAll(u16 amount, float spawntime, v3f minpos, v3f maxpos,
3650 v3f minvel, v3f maxvel, v3f minacc, v3f maxacc, float minexptime, float maxexptime,
3651 float minsize, float maxsize, bool collisiondetection, std::string texture, u32 id)
3653 for(std::map<u16, RemoteClient*>::iterator
3654 i = m_clients.begin();
3655 i != m_clients.end(); i++)
3657 // Get client and check that it is valid
3658 RemoteClient *client = i->second;
3659 assert(client->peer_id == i->first);
3660 if(client->serialization_version == SER_FMT_VER_INVALID)
3663 SendAddParticleSpawner(client->peer_id, amount, spawntime,
3664 minpos, maxpos, minvel, maxvel, minacc, maxacc,
3665 minexptime, maxexptime, minsize, maxsize, collisiondetection, texture, id);
3669 void Server::SendDeleteParticleSpawner(u16 peer_id, u32 id)
3671 DSTACK(__FUNCTION_NAME);
3673 std::ostringstream os(std::ios_base::binary);
3674 writeU16(os, TOCLIENT_DELETE_PARTICLESPAWNER);
3679 std::string s = os.str();
3680 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3682 m_con.Send(peer_id, 0, data, true);
3685 void Server::SendDeleteParticleSpawnerAll(u32 id)
3687 for(std::map<u16, RemoteClient*>::iterator
3688 i = m_clients.begin();
3689 i != m_clients.end(); i++)
3691 // Get client and check that it is valid
3692 RemoteClient *client = i->second;
3693 assert(client->peer_id == i->first);
3694 if(client->serialization_version == SER_FMT_VER_INVALID)
3697 SendDeleteParticleSpawner(client->peer_id, id);
3701 void Server::SendHUDAdd(u16 peer_id, u32 id, HudElement *form)
3703 std::ostringstream os(std::ios_base::binary);
3706 writeU16(os, TOCLIENT_HUDADD);
3708 writeU8(os, (u8)form->type);
3709 writeV2F1000(os, form->pos);
3710 os << serializeString(form->name);
3711 writeV2F1000(os, form->scale);
3712 os << serializeString(form->text);
3713 writeU32(os, form->number);
3714 writeU32(os, form->item);
3715 writeU32(os, form->dir);
3716 writeV2F1000(os, form->align);
3717 writeV2F1000(os, form->offset);
3720 std::string s = os.str();
3721 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3723 m_con.Send(peer_id, 0, data, true);
3726 void Server::SendHUDRemove(u16 peer_id, u32 id)
3728 std::ostringstream os(std::ios_base::binary);
3731 writeU16(os, TOCLIENT_HUDRM);
3735 std::string s = os.str();
3736 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3738 m_con.Send(peer_id, 0, data, true);
3741 void Server::SendHUDChange(u16 peer_id, u32 id, HudElementStat stat, void *value)
3743 std::ostringstream os(std::ios_base::binary);
3746 writeU16(os, TOCLIENT_HUDCHANGE);
3748 writeU8(os, (u8)stat);
3751 case HUD_STAT_SCALE:
3752 case HUD_STAT_ALIGN:
3753 case HUD_STAT_OFFSET:
3754 writeV2F1000(os, *(v2f *)value);
3758 os << serializeString(*(std::string *)value);
3760 case HUD_STAT_NUMBER:
3764 writeU32(os, *(u32 *)value);
3769 std::string s = os.str();
3770 SharedBuffer<u8> data((u8 *)s.c_str(), s.size());
3772 m_con.Send(peer_id, 0, data, true);
3775 void Server::SendHUDSetFlags(u16 peer_id, u32 flags, u32 mask)
3777 std::ostringstream os(std::ios_base::binary);
3780 writeU16(os, TOCLIENT_HUD_SET_FLAGS);
3781 writeU32(os, flags);
3785 std::string s = os.str();
3786 SharedBuffer<u8> data((u8 *)s.c_str(), s.size());
3788 m_con.Send(peer_id, 0, data, true);
3791 void Server::SendHUDSetParam(u16 peer_id, u16 param, const std::string &value)
3793 std::ostringstream os(std::ios_base::binary);
3796 writeU16(os, TOCLIENT_HUD_SET_PARAM);
3797 writeU16(os, param);
3798 os<<serializeString(value);
3801 std::string s = os.str();
3802 SharedBuffer<u8> data((u8 *)s.c_str(), s.size());
3804 m_con.Send(peer_id, 0, data, true);
3807 void Server::BroadcastChatMessage(const std::wstring &message)
3809 for(std::map<u16, RemoteClient*>::iterator
3810 i = m_clients.begin();
3811 i != m_clients.end(); ++i)
3813 // Get client and check that it is valid
3814 RemoteClient *client = i->second;
3815 assert(client->peer_id == i->first);
3816 if(client->serialization_version == SER_FMT_VER_INVALID)
3819 SendChatMessage(client->peer_id, message);
3823 void Server::SendTimeOfDay(u16 peer_id, u16 time, f32 time_speed)
3825 DSTACK(__FUNCTION_NAME);
3828 SharedBuffer<u8> data(2+2+4);
3829 writeU16(&data[0], TOCLIENT_TIME_OF_DAY);
3830 writeU16(&data[2], time);
3831 writeF1000(&data[4], time_speed);
3834 m_con.Send(peer_id, 0, data, true);
3837 void Server::SendPlayerHP(u16 peer_id)
3839 DSTACK(__FUNCTION_NAME);
3840 PlayerSAO *playersao = getPlayerSAO(peer_id);
3842 playersao->m_hp_not_sent = false;
3843 SendHP(m_con, peer_id, playersao->getHP());
3845 // Send to other clients
3846 std::string str = gob_cmd_punched(playersao->readDamage(), playersao->getHP());
3847 ActiveObjectMessage aom(playersao->getId(), true, str);
3848 playersao->m_messages_out.push_back(aom);
3851 void Server::SendPlayerBreath(u16 peer_id)
3853 DSTACK(__FUNCTION_NAME);
3854 PlayerSAO *playersao = getPlayerSAO(peer_id);
3856 playersao->m_breath_not_sent = false;
3857 SendBreath(m_con, peer_id, playersao->getBreath());
3860 void Server::SendMovePlayer(u16 peer_id)
3862 DSTACK(__FUNCTION_NAME);
3863 Player *player = m_env->getPlayer(peer_id);
3866 std::ostringstream os(std::ios_base::binary);
3867 writeU16(os, TOCLIENT_MOVE_PLAYER);
3868 writeV3F1000(os, player->getPosition());
3869 writeF1000(os, player->getPitch());
3870 writeF1000(os, player->getYaw());
3873 v3f pos = player->getPosition();
3874 f32 pitch = player->getPitch();
3875 f32 yaw = player->getYaw();
3876 verbosestream<<"Server: Sending TOCLIENT_MOVE_PLAYER"
3877 <<" pos=("<<pos.X<<","<<pos.Y<<","<<pos.Z<<")"
3884 std::string s = os.str();
3885 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3887 m_con.Send(peer_id, 0, data, true);
3890 void Server::SendPlayerPrivileges(u16 peer_id)
3892 Player *player = m_env->getPlayer(peer_id);
3894 if(player->peer_id == PEER_ID_INEXISTENT)
3897 std::set<std::string> privs;
3898 m_script->getAuth(player->getName(), NULL, &privs);
3900 std::ostringstream os(std::ios_base::binary);
3901 writeU16(os, TOCLIENT_PRIVILEGES);
3902 writeU16(os, privs.size());
3903 for(std::set<std::string>::const_iterator i = privs.begin();
3904 i != privs.end(); i++){
3905 os<<serializeString(*i);
3909 std::string s = os.str();
3910 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3912 m_con.Send(peer_id, 0, data, true);
3915 void Server::SendPlayerInventoryFormspec(u16 peer_id)
3917 Player *player = m_env->getPlayer(peer_id);
3919 if(player->peer_id == PEER_ID_INEXISTENT)
3922 std::ostringstream os(std::ios_base::binary);
3923 writeU16(os, TOCLIENT_INVENTORY_FORMSPEC);
3924 os<<serializeLongString(player->inventory_formspec);
3927 std::string s = os.str();
3928 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3930 m_con.Send(peer_id, 0, data, true);
3933 s32 Server::playSound(const SimpleSoundSpec &spec,
3934 const ServerSoundParams ¶ms)
3936 // Find out initial position of sound
3937 bool pos_exists = false;
3938 v3f pos = params.getPos(m_env, &pos_exists);
3939 // If position is not found while it should be, cancel sound
3940 if(pos_exists != (params.type != ServerSoundParams::SSP_LOCAL))
3942 // Filter destination clients
3943 std::set<RemoteClient*> dst_clients;
3944 if(params.to_player != "")
3946 Player *player = m_env->getPlayer(params.to_player.c_str());
3948 infostream<<"Server::playSound: Player \""<<params.to_player
3949 <<"\" not found"<<std::endl;
3952 if(player->peer_id == PEER_ID_INEXISTENT){
3953 infostream<<"Server::playSound: Player \""<<params.to_player
3954 <<"\" not connected"<<std::endl;
3957 RemoteClient *client = getClient(player->peer_id);
3958 dst_clients.insert(client);
3962 for(std::map<u16, RemoteClient*>::iterator
3963 i = m_clients.begin(); i != m_clients.end(); ++i)
3965 RemoteClient *client = i->second;
3966 Player *player = m_env->getPlayer(client->peer_id);
3970 if(player->getPosition().getDistanceFrom(pos) >
3971 params.max_hear_distance)
3974 dst_clients.insert(client);
3977 if(dst_clients.size() == 0)
3980 s32 id = m_next_sound_id++;
3981 // The sound will exist as a reference in m_playing_sounds
3982 m_playing_sounds[id] = ServerPlayingSound();
3983 ServerPlayingSound &psound = m_playing_sounds[id];
3984 psound.params = params;
3985 for(std::set<RemoteClient*>::iterator i = dst_clients.begin();
3986 i != dst_clients.end(); i++)
3987 psound.clients.insert((*i)->peer_id);
3989 std::ostringstream os(std::ios_base::binary);
3990 writeU16(os, TOCLIENT_PLAY_SOUND);
3992 os<<serializeString(spec.name);
3993 writeF1000(os, spec.gain * params.gain);
3994 writeU8(os, params.type);
3995 writeV3F1000(os, pos);
3996 writeU16(os, params.object);
3997 writeU8(os, params.loop);
3999 std::string s = os.str();
4000 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
4002 for(std::set<RemoteClient*>::iterator i = dst_clients.begin();
4003 i != dst_clients.end(); i++){
4005 m_con.Send((*i)->peer_id, 0, data, true);
4009 void Server::stopSound(s32 handle)
4011 // Get sound reference
4012 std::map<s32, ServerPlayingSound>::iterator i =
4013 m_playing_sounds.find(handle);
4014 if(i == m_playing_sounds.end())
4016 ServerPlayingSound &psound = i->second;
4018 std::ostringstream os(std::ios_base::binary);
4019 writeU16(os, TOCLIENT_STOP_SOUND);
4020 writeS32(os, handle);
4022 std::string s = os.str();
4023 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
4025 for(std::set<u16>::iterator i = psound.clients.begin();
4026 i != psound.clients.end(); i++){
4028 m_con.Send(*i, 0, data, true);
4030 // Remove sound reference
4031 m_playing_sounds.erase(i);
4034 void Server::sendRemoveNode(v3s16 p, u16 ignore_id,
4035 std::list<u16> *far_players, float far_d_nodes)
4037 float maxd = far_d_nodes*BS;
4038 v3f p_f = intToFloat(p, BS);
4042 SharedBuffer<u8> reply(replysize);
4043 writeU16(&reply[0], TOCLIENT_REMOVENODE);
4044 writeS16(&reply[2], p.X);
4045 writeS16(&reply[4], p.Y);
4046 writeS16(&reply[6], p.Z);
4048 for(std::map<u16, RemoteClient*>::iterator
4049 i = m_clients.begin();
4050 i != m_clients.end(); ++i)
4052 // Get client and check that it is valid
4053 RemoteClient *client = i->second;
4054 assert(client->peer_id == i->first);
4055 if(client->serialization_version == SER_FMT_VER_INVALID)
4058 // Don't send if it's the same one
4059 if(client->peer_id == ignore_id)
4065 Player *player = m_env->getPlayer(client->peer_id);
4068 // If player is far away, only set modified blocks not sent
4069 v3f player_pos = player->getPosition();
4070 if(player_pos.getDistanceFrom(p_f) > maxd)
4072 far_players->push_back(client->peer_id);
4079 m_con.Send(client->peer_id, 0, reply, true);
4083 void Server::sendAddNode(v3s16 p, MapNode n, u16 ignore_id,
4084 std::list<u16> *far_players, float far_d_nodes,
4085 bool remove_metadata)
4087 float maxd = far_d_nodes*BS;
4088 v3f p_f = intToFloat(p, BS);
4090 for(std::map<u16, RemoteClient*>::iterator
4091 i = m_clients.begin();
4092 i != m_clients.end(); ++i)
4094 // Get client and check that it is valid
4095 RemoteClient *client = i->second;
4096 assert(client->peer_id == i->first);
4097 if(client->serialization_version == SER_FMT_VER_INVALID)
4100 // Don't send if it's the same one
4101 if(client->peer_id == ignore_id)
4107 Player *player = m_env->getPlayer(client->peer_id);
4110 // If player is far away, only set modified blocks not sent
4111 v3f player_pos = player->getPosition();
4112 if(player_pos.getDistanceFrom(p_f) > maxd)
4114 far_players->push_back(client->peer_id);
4121 u32 replysize = 9 + MapNode::serializedLength(client->serialization_version);
4122 SharedBuffer<u8> reply(replysize);
4123 writeU16(&reply[0], TOCLIENT_ADDNODE);
4124 writeS16(&reply[2], p.X);
4125 writeS16(&reply[4], p.Y);
4126 writeS16(&reply[6], p.Z);
4127 n.serialize(&reply[8], client->serialization_version);
4128 u32 index = 8 + MapNode::serializedLength(client->serialization_version);
4129 writeU8(&reply[index], remove_metadata ? 0 : 1);
4131 if (!remove_metadata) {
4132 if (client->net_proto_version <= 21) {
4133 // Old clients always clear metadata; fix it
4134 // by sending the full block again.
4135 client->SetBlockNotSent(p);
4140 m_con.Send(client->peer_id, 0, reply, true);
4144 void Server::setBlockNotSent(v3s16 p)
4146 for(std::map<u16, RemoteClient*>::iterator
4147 i = m_clients.begin();
4148 i != m_clients.end(); ++i)
4150 RemoteClient *client = i->second;
4151 client->SetBlockNotSent(p);
4155 void Server::SendBlockNoLock(u16 peer_id, MapBlock *block, u8 ver, u16 net_proto_version)
4157 DSTACK(__FUNCTION_NAME);
4159 v3s16 p = block->getPos();
4163 bool completely_air = true;
4164 for(s16 z0=0; z0<MAP_BLOCKSIZE; z0++)
4165 for(s16 x0=0; x0<MAP_BLOCKSIZE; x0++)
4166 for(s16 y0=0; y0<MAP_BLOCKSIZE; y0++)
4168 if(block->getNodeNoEx(v3s16(x0,y0,z0)).d != CONTENT_AIR)
4170 completely_air = false;
4171 x0 = y0 = z0 = MAP_BLOCKSIZE; // Break out
4176 infostream<<"Server: Sending block ("<<p.X<<","<<p.Y<<","<<p.Z<<"): ";
4178 infostream<<"[completely air] ";
4179 infostream<<std::endl;
4183 Create a packet with the block in the right format
4186 std::ostringstream os(std::ios_base::binary);
4187 block->serialize(os, ver, false);
4188 block->serializeNetworkSpecific(os, net_proto_version);
4189 std::string s = os.str();
4190 SharedBuffer<u8> blockdata((u8*)s.c_str(), s.size());
4192 u32 replysize = 8 + blockdata.getSize();
4193 SharedBuffer<u8> reply(replysize);
4194 writeU16(&reply[0], TOCLIENT_BLOCKDATA);
4195 writeS16(&reply[2], p.X);
4196 writeS16(&reply[4], p.Y);
4197 writeS16(&reply[6], p.Z);
4198 memcpy(&reply[8], *blockdata, blockdata.getSize());
4200 /*infostream<<"Server: Sending block ("<<p.X<<","<<p.Y<<","<<p.Z<<")"
4201 <<": \tpacket size: "<<replysize<<std::endl;*/
4206 m_con.Send(peer_id, 1, reply, true);
4209 void Server::SendBlocks(float dtime)
4211 DSTACK(__FUNCTION_NAME);
4213 JMutexAutoLock envlock(m_env_mutex);
4214 JMutexAutoLock conlock(m_con_mutex);
4216 ScopeProfiler sp(g_profiler, "Server: sel and send blocks to clients");
4218 std::vector<PrioritySortedBlockTransfer> queue;
4220 s32 total_sending = 0;
4223 ScopeProfiler sp(g_profiler, "Server: selecting blocks for sending");
4225 for(std::map<u16, RemoteClient*>::iterator
4226 i = m_clients.begin();
4227 i != m_clients.end(); ++i)
4229 RemoteClient *client = i->second;
4230 assert(client->peer_id == i->first);
4232 // If definitions and textures have not been sent, don't
4233 // send MapBlocks either
4234 if(!client->definitions_sent)
4237 total_sending += client->SendingCount();
4239 if(client->serialization_version == SER_FMT_VER_INVALID)
4242 client->GetNextBlocks(this, dtime, queue);
4247 // Lowest priority number comes first.
4248 // Lowest is most important.
4249 std::sort(queue.begin(), queue.end());
4251 for(u32 i=0; i<queue.size(); i++)
4253 //TODO: Calculate limit dynamically
4254 if(total_sending >= g_settings->getS32
4255 ("max_simultaneous_block_sends_server_total"))
4258 PrioritySortedBlockTransfer q = queue[i];
4260 MapBlock *block = NULL;
4263 block = m_env->getMap().getBlockNoCreate(q.pos);
4265 catch(InvalidPositionException &e)
4270 RemoteClient *client = getClientNoEx(q.peer_id);
4276 SendBlockNoLock(q.peer_id, block, client->serialization_version, client->net_proto_version);
4278 client->SentBlock(q.pos);
4284 void Server::fillMediaCache()
4286 DSTACK(__FUNCTION_NAME);
4288 infostream<<"Server: Calculating media file checksums"<<std::endl;
4290 // Collect all media file paths
4291 std::list<std::string> paths;
4292 for(std::vector<ModSpec>::iterator i = m_mods.begin();
4293 i != m_mods.end(); i++){
4294 const ModSpec &mod = *i;
4295 paths.push_back(mod.path + DIR_DELIM + "textures");
4296 paths.push_back(mod.path + DIR_DELIM + "sounds");
4297 paths.push_back(mod.path + DIR_DELIM + "media");
4298 paths.push_back(mod.path + DIR_DELIM + "models");
4300 paths.push_back(porting::path_user + DIR_DELIM + "textures" + DIR_DELIM + "server");
4302 // Collect media file information from paths into cache
4303 for(std::list<std::string>::iterator i = paths.begin();
4304 i != paths.end(); i++)
4306 std::string mediapath = *i;
4307 std::vector<fs::DirListNode> dirlist = fs::GetDirListing(mediapath);
4308 for(u32 j=0; j<dirlist.size(); j++){
4309 if(dirlist[j].dir) // Ignode dirs
4311 std::string filename = dirlist[j].name;
4312 // If name contains illegal characters, ignore the file
4313 if(!string_allowed(filename, TEXTURENAME_ALLOWED_CHARS)){
4314 infostream<<"Server: ignoring illegal file name: \""
4315 <<filename<<"\""<<std::endl;
4318 // If name is not in a supported format, ignore it
4319 const char *supported_ext[] = {
4320 ".png", ".jpg", ".bmp", ".tga",
4321 ".pcx", ".ppm", ".psd", ".wal", ".rgb",
4323 ".x", ".b3d", ".md2", ".obj",
4326 if(removeStringEnd(filename, supported_ext) == ""){
4327 infostream<<"Server: ignoring unsupported file extension: \""
4328 <<filename<<"\""<<std::endl;
4331 // Ok, attempt to load the file and add to cache
4332 std::string filepath = mediapath + DIR_DELIM + filename;
4334 std::ifstream fis(filepath.c_str(), std::ios_base::binary);
4335 if(fis.good() == false){
4336 errorstream<<"Server::fillMediaCache(): Could not open \""
4337 <<filename<<"\" for reading"<<std::endl;
4340 std::ostringstream tmp_os(std::ios_base::binary);
4344 fis.read(buf, 1024);
4345 std::streamsize len = fis.gcount();
4346 tmp_os.write(buf, len);
4355 errorstream<<"Server::fillMediaCache(): Failed to read \""
4356 <<filename<<"\""<<std::endl;
4359 if(tmp_os.str().length() == 0){
4360 errorstream<<"Server::fillMediaCache(): Empty file \""
4361 <<filepath<<"\""<<std::endl;
4366 sha1.addBytes(tmp_os.str().c_str(), tmp_os.str().length());
4368 unsigned char *digest = sha1.getDigest();
4369 std::string sha1_base64 = base64_encode(digest, 20);
4370 std::string sha1_hex = hex_encode((char*)digest, 20);
4374 this->m_media[filename] = MediaInfo(filepath, sha1_base64);
4375 verbosestream<<"Server: "<<sha1_hex<<" is "<<filename<<std::endl;
4380 struct SendableMediaAnnouncement
4383 std::string sha1_digest;
4385 SendableMediaAnnouncement(const std::string name_="",
4386 const std::string sha1_digest_=""):
4388 sha1_digest(sha1_digest_)
4392 void Server::sendMediaAnnouncement(u16 peer_id)
4394 DSTACK(__FUNCTION_NAME);
4396 verbosestream<<"Server: Announcing files to id("<<peer_id<<")"
4399 std::list<SendableMediaAnnouncement> file_announcements;
4401 for(std::map<std::string, MediaInfo>::iterator i = m_media.begin();
4402 i != m_media.end(); i++){
4404 file_announcements.push_back(
4405 SendableMediaAnnouncement(i->first, i->second.sha1_digest));
4409 std::ostringstream os(std::ios_base::binary);
4417 u16 length of sha1_digest
4422 writeU16(os, TOCLIENT_ANNOUNCE_MEDIA);
4423 writeU16(os, file_announcements.size());
4425 for(std::list<SendableMediaAnnouncement>::iterator
4426 j = file_announcements.begin();
4427 j != file_announcements.end(); ++j){
4428 os<<serializeString(j->name);
4429 os<<serializeString(j->sha1_digest);
4431 os<<serializeString(g_settings->get("remote_media"));
4434 std::string s = os.str();
4435 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
4438 m_con.Send(peer_id, 0, data, true);
4441 struct SendableMedia
4447 SendableMedia(const std::string &name_="", const std::string path_="",
4448 const std::string &data_=""):
4455 void Server::sendRequestedMedia(u16 peer_id,
4456 const std::list<std::string> &tosend)
4458 DSTACK(__FUNCTION_NAME);
4460 verbosestream<<"Server::sendRequestedMedia(): "
4461 <<"Sending files to client"<<std::endl;
4465 // Put 5kB in one bunch (this is not accurate)
4466 u32 bytes_per_bunch = 5000;
4468 std::vector< std::list<SendableMedia> > file_bunches;
4469 file_bunches.push_back(std::list<SendableMedia>());
4471 u32 file_size_bunch_total = 0;
4473 for(std::list<std::string>::const_iterator i = tosend.begin();
4474 i != tosend.end(); ++i)
4476 const std::string &name = *i;
4478 if(m_media.find(name) == m_media.end()){
4479 errorstream<<"Server::sendRequestedMedia(): Client asked for "
4480 <<"unknown file \""<<(name)<<"\""<<std::endl;
4484 //TODO get path + name
4485 std::string tpath = m_media[name].path;
4488 std::ifstream fis(tpath.c_str(), std::ios_base::binary);
4489 if(fis.good() == false){
4490 errorstream<<"Server::sendRequestedMedia(): Could not open \""
4491 <<tpath<<"\" for reading"<<std::endl;
4494 std::ostringstream tmp_os(std::ios_base::binary);
4498 fis.read(buf, 1024);
4499 std::streamsize len = fis.gcount();
4500 tmp_os.write(buf, len);
4501 file_size_bunch_total += len;
4510 errorstream<<"Server::sendRequestedMedia(): Failed to read \""
4511 <<name<<"\""<<std::endl;
4514 /*infostream<<"Server::sendRequestedMedia(): Loaded \""
4515 <<tname<<"\""<<std::endl;*/
4517 file_bunches[file_bunches.size()-1].push_back(
4518 SendableMedia(name, tpath, tmp_os.str()));
4520 // Start next bunch if got enough data
4521 if(file_size_bunch_total >= bytes_per_bunch){
4522 file_bunches.push_back(std::list<SendableMedia>());
4523 file_size_bunch_total = 0;
4528 /* Create and send packets */
4530 u32 num_bunches = file_bunches.size();
4531 for(u32 i=0; i<num_bunches; i++)
4533 std::ostringstream os(std::ios_base::binary);
4537 u16 total number of texture bunches
4538 u16 index of this bunch
4539 u32 number of files in this bunch
4548 writeU16(os, TOCLIENT_MEDIA);
4549 writeU16(os, num_bunches);
4551 writeU32(os, file_bunches[i].size());
4553 for(std::list<SendableMedia>::iterator
4554 j = file_bunches[i].begin();
4555 j != file_bunches[i].end(); ++j){
4556 os<<serializeString(j->name);
4557 os<<serializeLongString(j->data);
4561 std::string s = os.str();
4562 verbosestream<<"Server::sendRequestedMedia(): bunch "
4563 <<i<<"/"<<num_bunches
4564 <<" files="<<file_bunches[i].size()
4565 <<" size=" <<s.size()<<std::endl;
4566 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
4568 m_con.Send(peer_id, 0, data, true);
4572 void Server::sendDetachedInventory(const std::string &name, u16 peer_id)
4574 if(m_detached_inventories.count(name) == 0){
4575 errorstream<<__FUNCTION_NAME<<": \""<<name<<"\" not found"<<std::endl;
4578 Inventory *inv = m_detached_inventories[name];
4580 std::ostringstream os(std::ios_base::binary);
4581 writeU16(os, TOCLIENT_DETACHED_INVENTORY);
4582 os<<serializeString(name);
4586 std::string s = os.str();
4587 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
4589 m_con.Send(peer_id, 0, data, true);
4592 void Server::sendDetachedInventoryToAll(const std::string &name)
4594 DSTACK(__FUNCTION_NAME);
4596 for(std::map<u16, RemoteClient*>::iterator
4597 i = m_clients.begin();
4598 i != m_clients.end(); ++i){
4599 RemoteClient *client = i->second;
4600 sendDetachedInventory(name, client->peer_id);
4604 void Server::sendDetachedInventories(u16 peer_id)
4606 DSTACK(__FUNCTION_NAME);
4608 for(std::map<std::string, Inventory*>::iterator
4609 i = m_detached_inventories.begin();
4610 i != m_detached_inventories.end(); i++){
4611 const std::string &name = i->first;
4612 //Inventory *inv = i->second;
4613 sendDetachedInventory(name, peer_id);
4621 void Server::DiePlayer(u16 peer_id)
4623 DSTACK(__FUNCTION_NAME);
4625 PlayerSAO *playersao = getPlayerSAO(peer_id);
4628 infostream<<"Server::DiePlayer(): Player "
4629 <<playersao->getPlayer()->getName()
4630 <<" dies"<<std::endl;
4632 playersao->setHP(0);
4634 // Trigger scripted stuff
4635 m_script->on_dieplayer(playersao);
4637 SendPlayerHP(peer_id);
4638 SendDeathscreen(m_con, peer_id, false, v3f(0,0,0));
4641 void Server::RespawnPlayer(u16 peer_id)
4643 DSTACK(__FUNCTION_NAME);
4645 PlayerSAO *playersao = getPlayerSAO(peer_id);
4648 infostream<<"Server::RespawnPlayer(): Player "
4649 <<playersao->getPlayer()->getName()
4650 <<" respawns"<<std::endl;
4652 playersao->setHP(PLAYER_MAX_HP);
4654 bool repositioned = m_script->on_respawnplayer(playersao);
4656 v3f pos = findSpawnPos(m_env->getServerMap());
4657 playersao->setPos(pos);
4661 void Server::DenyAccess(u16 peer_id, const std::wstring &reason)
4663 DSTACK(__FUNCTION_NAME);
4665 SendAccessDenied(m_con, peer_id, reason);
4667 RemoteClient *client = getClientNoEx(peer_id);
4669 client->denied = true;
4671 // If there are way too many clients, get rid of denied new ones immediately
4672 if((int)m_clients.size() > 2 * g_settings->getU16("max_users")){
4673 verbosestream<<"Server: DenyAccess: Too many clients; getting rid of "
4674 <<"peer_id="<<peer_id<<" immediately"<<std::endl;
4675 // Delete peer to stop sending it data
4676 m_con.DeletePeer(peer_id);
4677 // Delete client also to stop block sends and other stuff
4678 DeleteClient(peer_id, CDR_DENY);
4682 void Server::DeleteClient(u16 peer_id, ClientDeletionReason reason)
4684 DSTACK(__FUNCTION_NAME);
4687 std::map<u16, RemoteClient*>::iterator n;
4688 n = m_clients.find(peer_id);
4689 // The client may not exist; clients are immediately removed if their
4690 // access is denied, and this event occurs later then.
4691 if(n == m_clients.end())
4695 Mark objects to be not known by the client
4697 RemoteClient *client = n->second;
4699 for(std::set<u16>::iterator
4700 i = client->m_known_objects.begin();
4701 i != client->m_known_objects.end(); ++i)
4705 ServerActiveObject* obj = m_env->getActiveObject(id);
4707 if(obj && obj->m_known_by_count > 0)
4708 obj->m_known_by_count--;
4712 Clear references to playing sounds
4714 for(std::map<s32, ServerPlayingSound>::iterator
4715 i = m_playing_sounds.begin();
4716 i != m_playing_sounds.end();)
4718 ServerPlayingSound &psound = i->second;
4719 psound.clients.erase(peer_id);
4720 if(psound.clients.size() == 0)
4721 m_playing_sounds.erase(i++);
4726 Player *player = m_env->getPlayer(peer_id);
4728 // Collect information about leaving in chat
4729 std::wstring message;
4731 if(player != NULL && reason != CDR_DENY)
4733 std::wstring name = narrow_to_wide(player->getName());
4736 message += L" left the game.";
4737 if(reason == CDR_TIMEOUT)
4738 message += L" (timed out)";
4742 /* Run scripts and remove from environment */
4746 PlayerSAO *playersao = player->getPlayerSAO();
4749 m_script->on_leaveplayer(playersao);
4751 playersao->disconnected();
4759 if(player != NULL && reason != CDR_DENY)
4761 std::ostringstream os(std::ios_base::binary);
4762 for(std::map<u16, RemoteClient*>::iterator
4763 i = m_clients.begin();
4764 i != m_clients.end(); ++i)
4766 RemoteClient *client = i->second;
4767 assert(client->peer_id == i->first);
4768 if(client->serialization_version == SER_FMT_VER_INVALID)
4771 Player *player = m_env->getPlayer(client->peer_id);
4774 // Get name of player
4775 os<<player->getName()<<" ";
4778 actionstream<<player->getName()<<" "
4779 <<(reason==CDR_TIMEOUT?"times out.":"leaves game.")
4780 <<" List of players: "<<os.str()<<std::endl;
4785 delete m_clients[peer_id];
4786 m_clients.erase(peer_id);
4788 // Send leave chat message to all remaining clients
4789 if(message.length() != 0)
4790 BroadcastChatMessage(message);
4793 void Server::UpdateCrafting(u16 peer_id)
4795 DSTACK(__FUNCTION_NAME);
4797 Player* player = m_env->getPlayer(peer_id);
4800 // Get a preview for crafting
4802 InventoryLocation loc;
4803 loc.setPlayer(player->getName());
4804 getCraftingResult(&player->inventory, preview, false, this);
4805 m_env->getScriptIface()->item_CraftPredict(preview, player->getPlayerSAO(), (&player->inventory)->getList("craft"), loc);
4807 // Put the new preview in
4808 InventoryList *plist = player->inventory.getList("craftpreview");
4810 assert(plist->getSize() >= 1);
4811 plist->changeItem(0, preview);
4814 RemoteClient* Server::getClient(u16 peer_id)
4816 RemoteClient *client = getClientNoEx(peer_id);
4818 throw ClientNotFoundException("Client not found");
4821 RemoteClient* Server::getClientNoEx(u16 peer_id)
4823 std::map<u16, RemoteClient*>::iterator n;
4824 n = m_clients.find(peer_id);
4825 // The client may not exist; clients are immediately removed if their
4826 // access is denied, and this event occurs later then.
4827 if(n == m_clients.end())
4832 std::string Server::getPlayerName(u16 peer_id)
4834 Player *player = m_env->getPlayer(peer_id);
4836 return "[id="+itos(peer_id)+"]";
4837 return player->getName();
4840 PlayerSAO* Server::getPlayerSAO(u16 peer_id)
4842 Player *player = m_env->getPlayer(peer_id);
4845 return player->getPlayerSAO();
4848 std::wstring Server::getStatusString()
4850 std::wostringstream os(std::ios_base::binary);
4853 os<<L"version="<<narrow_to_wide(minetest_version_simple);
4855 os<<L", uptime="<<m_uptime.get();
4857 os<<L", max_lag="<<m_env->getMaxLagEstimate();
4858 // Information about clients
4859 std::map<u16, RemoteClient*>::iterator i;
4862 for(i = m_clients.begin(), first = true;
4863 i != m_clients.end(); ++i)
4865 // Get client and check that it is valid
4866 RemoteClient *client = i->second;
4867 assert(client->peer_id == i->first);
4868 if(client->serialization_version == SER_FMT_VER_INVALID)
4871 Player *player = m_env->getPlayer(client->peer_id);
4872 // Get name of player
4873 std::wstring name = L"unknown";
4875 name = narrow_to_wide(player->getName());
4876 // Add name to information string
4884 if(((ServerMap*)(&m_env->getMap()))->isSavingEnabled() == false)
4885 os<<std::endl<<L"# Server: "<<" WARNING: Map saving is disabled.";
4886 if(g_settings->get("motd") != "")
4887 os<<std::endl<<L"# Server: "<<narrow_to_wide(g_settings->get("motd"));
4891 std::set<std::string> Server::getPlayerEffectivePrivs(const std::string &name)
4893 std::set<std::string> privs;
4894 m_script->getAuth(name, NULL, &privs);
4898 bool Server::checkPriv(const std::string &name, const std::string &priv)
4900 std::set<std::string> privs = getPlayerEffectivePrivs(name);
4901 return (privs.count(priv) != 0);
4904 void Server::reportPrivsModified(const std::string &name)
4907 for(std::map<u16, RemoteClient*>::iterator
4908 i = m_clients.begin();
4909 i != m_clients.end(); ++i){
4910 RemoteClient *client = i->second;
4911 Player *player = m_env->getPlayer(client->peer_id);
4912 reportPrivsModified(player->getName());
4915 Player *player = m_env->getPlayer(name.c_str());
4918 SendPlayerPrivileges(player->peer_id);
4919 PlayerSAO *sao = player->getPlayerSAO();
4922 sao->updatePrivileges(
4923 getPlayerEffectivePrivs(name),
4928 void Server::reportInventoryFormspecModified(const std::string &name)
4930 Player *player = m_env->getPlayer(name.c_str());
4933 SendPlayerInventoryFormspec(player->peer_id);
4936 void Server::setIpBanned(const std::string &ip, const std::string &name)
4938 m_banmanager->add(ip, name);
4941 void Server::unsetIpBanned(const std::string &ip_or_name)
4943 m_banmanager->remove(ip_or_name);
4946 std::string Server::getBanDescription(const std::string &ip_or_name)
4948 return m_banmanager->getBanDescription(ip_or_name);
4951 void Server::notifyPlayer(const char *name, const std::wstring msg, const bool prepend = true)
4953 Player *player = m_env->getPlayer(name);
4957 SendChatMessage(player->peer_id, std::wstring(L"Server -!- ")+msg);
4959 SendChatMessage(player->peer_id, msg);
4962 bool Server::showFormspec(const char *playername, const std::string &formspec, const std::string &formname)
4964 Player *player = m_env->getPlayer(playername);
4968 infostream<<"showFormspec: couldn't find player:"<<playername<<std::endl;
4972 SendShowFormspecMessage(player->peer_id, formspec, formname);
4976 u32 Server::hudAdd(Player *player, HudElement *form) {
4980 u32 id = player->getFreeHudID();
4981 if (id < player->hud.size())
4982 player->hud[id] = form;
4984 player->hud.push_back(form);
4986 SendHUDAdd(player->peer_id, id, form);
4990 bool Server::hudRemove(Player *player, u32 id) {
4991 if (!player || id >= player->hud.size() || !player->hud[id])
4994 delete player->hud[id];
4995 player->hud[id] = NULL;
4997 SendHUDRemove(player->peer_id, id);
5001 bool Server::hudChange(Player *player, u32 id, HudElementStat stat, void *data) {
5005 SendHUDChange(player->peer_id, id, stat, data);
5009 bool Server::hudSetFlags(Player *player, u32 flags, u32 mask) {
5013 SendHUDSetFlags(player->peer_id, flags, mask);
5017 bool Server::hudSetHotbarItemcount(Player *player, s32 hotbar_itemcount) {
5020 if (hotbar_itemcount <= 0 || hotbar_itemcount > HUD_HOTBAR_ITEMCOUNT_MAX)
5023 std::ostringstream os(std::ios::binary);
5024 writeS32(os, hotbar_itemcount);
5025 SendHUDSetParam(player->peer_id, HUD_PARAM_HOTBAR_ITEMCOUNT, os.str());
5029 void Server::hudSetHotbarImage(Player *player, std::string name) {
5033 SendHUDSetParam(player->peer_id, HUD_PARAM_HOTBAR_IMAGE, name);
5036 void Server::hudSetHotbarSelectedImage(Player *player, std::string name) {
5040 SendHUDSetParam(player->peer_id, HUD_PARAM_HOTBAR_SELECTED_IMAGE, name);
5043 void Server::notifyPlayers(const std::wstring msg)
5045 BroadcastChatMessage(msg);
5048 void Server::spawnParticle(const char *playername, v3f pos,
5049 v3f velocity, v3f acceleration,
5050 float expirationtime, float size, bool
5051 collisiondetection, std::string texture)
5053 Player *player = m_env->getPlayer(playername);
5056 SendSpawnParticle(player->peer_id, pos, velocity, acceleration,
5057 expirationtime, size, collisiondetection, texture);
5060 void Server::spawnParticleAll(v3f pos, v3f velocity, v3f acceleration,
5061 float expirationtime, float size,
5062 bool collisiondetection, std::string texture)
5064 SendSpawnParticleAll(pos, velocity, acceleration,
5065 expirationtime, size, collisiondetection, texture);
5068 u32 Server::addParticleSpawner(const char *playername,
5069 u16 amount, float spawntime,
5070 v3f minpos, v3f maxpos,
5071 v3f minvel, v3f maxvel,
5072 v3f minacc, v3f maxacc,
5073 float minexptime, float maxexptime,
5074 float minsize, float maxsize,
5075 bool collisiondetection, std::string texture)
5077 Player *player = m_env->getPlayer(playername);
5082 for(;;) // look for unused particlespawner id
5085 if (std::find(m_particlespawner_ids.begin(),
5086 m_particlespawner_ids.end(), id)
5087 == m_particlespawner_ids.end())
5089 m_particlespawner_ids.push_back(id);
5094 SendAddParticleSpawner(player->peer_id, amount, spawntime,
5095 minpos, maxpos, minvel, maxvel, minacc, maxacc,
5096 minexptime, maxexptime, minsize, maxsize,
5097 collisiondetection, texture, id);
5102 u32 Server::addParticleSpawnerAll(u16 amount, float spawntime,
5103 v3f minpos, v3f maxpos,
5104 v3f minvel, v3f maxvel,
5105 v3f minacc, v3f maxacc,
5106 float minexptime, float maxexptime,
5107 float minsize, float maxsize,
5108 bool collisiondetection, std::string texture)
5111 for(;;) // look for unused particlespawner id
5114 if (std::find(m_particlespawner_ids.begin(),
5115 m_particlespawner_ids.end(), id)
5116 == m_particlespawner_ids.end())
5118 m_particlespawner_ids.push_back(id);
5123 SendAddParticleSpawnerAll(amount, spawntime,
5124 minpos, maxpos, minvel, maxvel, minacc, maxacc,
5125 minexptime, maxexptime, minsize, maxsize,
5126 collisiondetection, texture, id);
5131 void Server::deleteParticleSpawner(const char *playername, u32 id)
5133 Player *player = m_env->getPlayer(playername);
5137 m_particlespawner_ids.erase(
5138 std::remove(m_particlespawner_ids.begin(),
5139 m_particlespawner_ids.end(), id),
5140 m_particlespawner_ids.end());
5141 SendDeleteParticleSpawner(player->peer_id, id);
5144 void Server::deleteParticleSpawnerAll(u32 id)
5146 m_particlespawner_ids.erase(
5147 std::remove(m_particlespawner_ids.begin(),
5148 m_particlespawner_ids.end(), id),
5149 m_particlespawner_ids.end());
5150 SendDeleteParticleSpawnerAll(id);
5153 Inventory* Server::createDetachedInventory(const std::string &name)
5155 if(m_detached_inventories.count(name) > 0){
5156 infostream<<"Server clearing detached inventory \""<<name<<"\""<<std::endl;
5157 delete m_detached_inventories[name];
5159 infostream<<"Server creating detached inventory \""<<name<<"\""<<std::endl;
5161 Inventory *inv = new Inventory(m_itemdef);
5163 m_detached_inventories[name] = inv;
5164 sendDetachedInventoryToAll(name);
5171 BoolScopeSet(bool *dst, bool val):
5174 m_orig_state = *m_dst;
5179 *m_dst = m_orig_state;
5186 // actions: time-reversed list
5187 // Return value: success/failure
5188 bool Server::rollbackRevertActions(const std::list<RollbackAction> &actions,
5189 std::list<std::string> *log)
5191 infostream<<"Server::rollbackRevertActions(len="<<actions.size()<<")"<<std::endl;
5192 ServerMap *map = (ServerMap*)(&m_env->getMap());
5193 // Disable rollback report sink while reverting
5194 BoolScopeSet rollback_scope_disable(&m_rollback_sink_enabled, false);
5196 // Fail if no actions to handle
5197 if(actions.empty()){
5198 log->push_back("Nothing to do.");
5205 for(std::list<RollbackAction>::const_iterator
5206 i = actions.begin();
5207 i != actions.end(); i++)
5209 const RollbackAction &action = *i;
5211 bool success = action.applyRevert(map, this, this);
5214 std::ostringstream os;
5215 os<<"Revert of step ("<<num_tried<<") "<<action.toString()<<" failed";
5216 infostream<<"Map::rollbackRevertActions(): "<<os.str()<<std::endl;
5218 log->push_back(os.str());
5220 std::ostringstream os;
5221 os<<"Successfully reverted step ("<<num_tried<<") "<<action.toString();
5222 infostream<<"Map::rollbackRevertActions(): "<<os.str()<<std::endl;
5224 log->push_back(os.str());
5228 infostream<<"Map::rollbackRevertActions(): "<<num_failed<<"/"<<num_tried
5229 <<" failed"<<std::endl;
5231 // Call it done if less than half failed
5232 return num_failed <= num_tried/2;
5235 // IGameDef interface
5237 IItemDefManager* Server::getItemDefManager()
5241 INodeDefManager* Server::getNodeDefManager()
5245 ICraftDefManager* Server::getCraftDefManager()
5249 ITextureSource* Server::getTextureSource()
5253 IShaderSource* Server::getShaderSource()
5257 u16 Server::allocateUnknownNodeId(const std::string &name)
5259 return m_nodedef->allocateDummy(name);
5261 ISoundManager* Server::getSoundManager()
5263 return &dummySoundManager;
5265 MtEventManager* Server::getEventManager()
5269 IRollbackReportSink* Server::getRollbackReportSink()
5271 if(!m_enable_rollback_recording)
5273 if(!m_rollback_sink_enabled)
5278 IWritableItemDefManager* Server::getWritableItemDefManager()
5282 IWritableNodeDefManager* Server::getWritableNodeDefManager()
5286 IWritableCraftDefManager* Server::getWritableCraftDefManager()
5291 const ModSpec* Server::getModSpec(const std::string &modname)
5293 for(std::vector<ModSpec>::iterator i = m_mods.begin();
5294 i != m_mods.end(); i++){
5295 const ModSpec &mod = *i;
5296 if(mod.name == modname)
5301 void Server::getModNames(std::list<std::string> &modlist)
5303 for(std::vector<ModSpec>::iterator i = m_mods.begin(); i != m_mods.end(); i++)
5305 modlist.push_back(i->name);
5308 std::string Server::getBuiltinLuaPath()
5310 return porting::path_share + DIR_DELIM + "builtin";
5313 v3f findSpawnPos(ServerMap &map)
5315 //return v3f(50,50,50)*BS;
5320 nodepos = v2s16(0,0);
5325 s16 water_level = map.m_mgparams->water_level;
5327 // Try to find a good place a few times
5328 for(s32 i=0; i<1000; i++)
5331 // We're going to try to throw the player to this position
5332 v2s16 nodepos2d = v2s16(
5333 -range + (myrand() % (range * 2)),
5334 -range + (myrand() % (range * 2)));
5336 // Get ground height at point
5337 s16 groundheight = map.findGroundLevel(nodepos2d, g_settings->getBool("cache_block_before_spawn"));
5338 if (groundheight <= water_level) // Don't go underwater
5340 if (groundheight > water_level + g_settings->getS16("max_spawn_height")) // Don't go to high places
5343 nodepos = v3s16(nodepos2d.X, groundheight, nodepos2d.Y);
5344 bool is_good = false;
5346 for (s32 i = 0; i < 10; i++) {
5347 v3s16 blockpos = getNodeBlockPos(nodepos);
5348 map.emergeBlock(blockpos, true);
5349 content_t c = map.getNodeNoEx(nodepos).getContent();
5350 if (c == CONTENT_AIR || c == CONTENT_IGNORE) {
5352 if (air_count >= 2){
5360 // Found a good place
5361 //infostream<<"Searched through "<<i<<" places."<<std::endl;
5367 return intToFloat(nodepos, BS);
5370 PlayerSAO* Server::emergePlayer(const char *name, u16 peer_id)
5372 RemotePlayer *player = NULL;
5373 bool newplayer = false;
5376 Try to get an existing player
5378 player = static_cast<RemotePlayer*>(m_env->getPlayer(name));
5380 // If player is already connected, cancel
5381 if(player != NULL && player->peer_id != 0)
5383 infostream<<"emergePlayer(): Player already connected"<<std::endl;
5388 If player with the wanted peer_id already exists, cancel.
5390 if(m_env->getPlayer(peer_id) != NULL)
5392 infostream<<"emergePlayer(): Player with wrong name but same"
5393 " peer_id already exists"<<std::endl;
5398 Create a new player if it doesn't exist yet
5403 player = new RemotePlayer(this);
5404 player->updateName(name);
5406 /* Set player position */
5407 infostream<<"Server: Finding spawn place for player \""
5408 <<name<<"\""<<std::endl;
5409 v3f pos = findSpawnPos(m_env->getServerMap());
5410 player->setPosition(pos);
5412 /* Add player to environment */
5413 m_env->addPlayer(player);
5417 Create a new player active object
5419 PlayerSAO *playersao = new PlayerSAO(m_env, player, peer_id,
5420 getPlayerEffectivePrivs(player->getName()),
5423 /* Clean up old HUD elements from previous sessions */
5424 player->hud.clear();
5426 /* Add object to environment */
5427 m_env->addActiveObject(playersao);
5431 m_script->on_newplayer(playersao);
5433 m_script->on_joinplayer(playersao);
5438 void Server::handlePeerChange(PeerChange &c)
5440 JMutexAutoLock envlock(m_env_mutex);
5441 JMutexAutoLock conlock(m_con_mutex);
5443 if(c.type == PEER_ADDED)
5450 std::map<u16, RemoteClient*>::iterator n;
5451 n = m_clients.find(c.peer_id);
5452 // The client shouldn't already exist
5453 assert(n == m_clients.end());
5456 RemoteClient *client = new RemoteClient();
5457 client->peer_id = c.peer_id;
5458 m_clients[client->peer_id] = client;
5461 else if(c.type == PEER_REMOVED)
5467 DeleteClient(c.peer_id, c.timeout?CDR_TIMEOUT:CDR_LEAVE);
5476 void Server::handlePeerChanges()
5478 while(m_peer_change_queue.size() > 0)
5480 PeerChange c = m_peer_change_queue.pop_front();
5482 verbosestream<<"Server: Handling peer change: "
5483 <<"id="<<c.peer_id<<", timeout="<<c.timeout
5486 handlePeerChange(c);
5490 void dedicated_server_loop(Server &server, bool &kill)
5492 DSTACK(__FUNCTION_NAME);
5494 verbosestream<<"dedicated_server_loop()"<<std::endl;
5496 IntervalLimiter m_profiler_interval;
5500 float steplen = g_settings->getFloat("dedicated_server_step");
5501 // This is kind of a hack but can be done like this
5502 // because server.step() is very light
5504 ScopeProfiler sp(g_profiler, "dedicated server sleep");
5505 sleep_ms((int)(steplen*1000.0));
5507 server.step(steplen);
5509 if(server.getShutdownRequested() || kill)
5511 infostream<<"Dedicated server quitting"<<std::endl;
5513 if(g_settings->getBool("server_announce") == true)
5514 ServerList::sendAnnounce("delete");
5522 float profiler_print_interval =
5523 g_settings->getFloat("profiler_print_interval");
5524 if(profiler_print_interval != 0)
5526 if(m_profiler_interval.step(steplen, profiler_print_interval))
5528 infostream<<"Profiler:"<<std::endl;
5529 g_profiler->print(infostream);
5530 g_profiler->clear();