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()
93 log_register_thread("ServerThread");
95 DSTACK(__FUNCTION_NAME);
96 BEGIN_DEBUG_EXCEPTION_HANDLER
98 m_server->AsyncRunStep(true);
102 while(!StopRequested())
105 //TimeTaker timer("AsyncRunStep() + Receive()");
108 //TimeTaker timer("AsyncRunStep()");
109 m_server->AsyncRunStep();
112 //infostream<<"Running m_server->Receive()"<<std::endl;
115 catch(con::NoIncomingDataException &e)
118 catch(con::PeerNotFoundException &e)
120 infostream<<"Server: PeerNotFoundException"<<std::endl;
122 catch(ClientNotFoundException &e)
125 catch(con::ConnectionBindFailed &e)
127 m_server->setAsyncFatalError(e.what());
131 m_server->setAsyncFatalError(e.what());
135 END_DEBUG_EXCEPTION_HANDLER(errorstream)
140 v3f ServerSoundParams::getPos(ServerEnvironment *env, bool *pos_exists) const
142 if(pos_exists) *pos_exists = false;
147 if(pos_exists) *pos_exists = true;
152 ServerActiveObject *sao = env->getActiveObject(object);
155 if(pos_exists) *pos_exists = true;
156 return sao->getBasePosition(); }
161 void RemoteClient::GetNextBlocks(Server *server, float dtime,
162 std::vector<PrioritySortedBlockTransfer> &dest)
164 DSTACK(__FUNCTION_NAME);
167 TimeTaker timer("RemoteClient::GetNextBlocks", &timer_result);*/
170 m_nothing_to_send_pause_timer -= dtime;
171 m_nearest_unsent_reset_timer += dtime;
173 if(m_nothing_to_send_pause_timer >= 0)
176 Player *player = server->m_env->getPlayer(peer_id);
177 // This can happen sometimes; clients and players are not in perfect sync.
181 // Won't send anything if already sending
182 if(m_blocks_sending.size() >= g_settings->getU16
183 ("max_simultaneous_block_sends_per_client"))
185 //infostream<<"Not sending any blocks, Queue full."<<std::endl;
189 //TimeTaker timer("RemoteClient::GetNextBlocks");
191 v3f playerpos = player->getPosition();
192 v3f playerspeed = player->getSpeed();
193 v3f playerspeeddir(0,0,0);
194 if(playerspeed.getLength() > 1.0*BS)
195 playerspeeddir = playerspeed / playerspeed.getLength();
196 // Predict to next block
197 v3f playerpos_predicted = playerpos + playerspeeddir*MAP_BLOCKSIZE*BS;
199 v3s16 center_nodepos = floatToInt(playerpos_predicted, BS);
201 v3s16 center = getNodeBlockPos(center_nodepos);
203 // Camera position and direction
204 v3f camera_pos = player->getEyePosition();
205 v3f camera_dir = v3f(0,0,1);
206 camera_dir.rotateYZBy(player->getPitch());
207 camera_dir.rotateXZBy(player->getYaw());
209 /*infostream<<"camera_dir=("<<camera_dir.X<<","<<camera_dir.Y<<","
210 <<camera_dir.Z<<")"<<std::endl;*/
213 Get the starting value of the block finder radius.
216 if(m_last_center != center)
218 m_nearest_unsent_d = 0;
219 m_last_center = center;
222 /*infostream<<"m_nearest_unsent_reset_timer="
223 <<m_nearest_unsent_reset_timer<<std::endl;*/
225 // Reset periodically to workaround for some bugs or stuff
226 if(m_nearest_unsent_reset_timer > 20.0)
228 m_nearest_unsent_reset_timer = 0;
229 m_nearest_unsent_d = 0;
230 //infostream<<"Resetting m_nearest_unsent_d for "
231 // <<server->getPlayerName(peer_id)<<std::endl;
234 //s16 last_nearest_unsent_d = m_nearest_unsent_d;
235 s16 d_start = m_nearest_unsent_d;
237 //infostream<<"d_start="<<d_start<<std::endl;
239 u16 max_simul_sends_setting = g_settings->getU16
240 ("max_simultaneous_block_sends_per_client");
241 u16 max_simul_sends_usually = max_simul_sends_setting;
244 Check the time from last addNode/removeNode.
246 Decrease send rate if player is building stuff.
248 m_time_from_building += dtime;
249 if(m_time_from_building < g_settings->getFloat(
250 "full_block_send_enable_min_time_from_building"))
252 max_simul_sends_usually
253 = LIMITED_MAX_SIMULTANEOUS_BLOCK_SENDS;
257 Number of blocks sending + number of blocks selected for sending
259 u32 num_blocks_selected = m_blocks_sending.size();
262 next time d will be continued from the d from which the nearest
263 unsent block was found this time.
265 This is because not necessarily any of the blocks found this
266 time are actually sent.
268 s32 new_nearest_unsent_d = -1;
270 s16 d_max = g_settings->getS16("max_block_send_distance");
271 s16 d_max_gen = g_settings->getS16("max_block_generate_distance");
273 // Don't loop very much at a time
274 s16 max_d_increment_at_time = 2;
275 if(d_max > d_start + max_d_increment_at_time)
276 d_max = d_start + max_d_increment_at_time;
277 /*if(d_max_gen > d_start+2)
278 d_max_gen = d_start+2;*/
280 //infostream<<"Starting from "<<d_start<<std::endl;
282 s32 nearest_emerged_d = -1;
283 s32 nearest_emergefull_d = -1;
284 s32 nearest_sent_d = -1;
285 bool queue_is_full = false;
288 for(d = d_start; d <= d_max; d++)
290 /*errorstream<<"checking d="<<d<<" for "
291 <<server->getPlayerName(peer_id)<<std::endl;*/
292 //infostream<<"RemoteClient::SendBlocks(): d="<<d<<std::endl;
295 If m_nearest_unsent_d was changed by the EmergeThread
296 (it can change it to 0 through SetBlockNotSent),
298 Else update m_nearest_unsent_d
300 /*if(m_nearest_unsent_d != last_nearest_unsent_d)
302 d = m_nearest_unsent_d;
303 last_nearest_unsent_d = m_nearest_unsent_d;
307 Get the border/face dot coordinates of a "d-radiused"
310 std::list<v3s16> list;
311 getFacePositions(list, d);
313 std::list<v3s16>::iterator li;
314 for(li=list.begin(); li!=list.end(); ++li)
316 v3s16 p = *li + center;
320 - Don't allow too many simultaneous transfers
321 - EXCEPT when the blocks are very close
323 Also, don't send blocks that are already flying.
326 // Start with the usual maximum
327 u16 max_simul_dynamic = max_simul_sends_usually;
329 // If block is very close, allow full maximum
330 if(d <= BLOCK_SEND_DISABLE_LIMITS_MAX_D)
331 max_simul_dynamic = max_simul_sends_setting;
333 // Don't select too many blocks for sending
334 if(num_blocks_selected >= max_simul_dynamic)
336 queue_is_full = true;
337 goto queue_full_break;
340 // Don't send blocks that are currently being transferred
341 if(m_blocks_sending.find(p) != m_blocks_sending.end())
347 if(p.X < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
348 || p.X > MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
349 || p.Y < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
350 || p.Y > MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
351 || p.Z < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
352 || p.Z > MAP_GENERATION_LIMIT / MAP_BLOCKSIZE)
355 // If this is true, inexistent block will be made from scratch
356 bool generate = d <= d_max_gen;
359 /*// Limit the generating area vertically to 2/3
360 if(abs(p.Y - center.Y) > d_max_gen - d_max_gen / 3)
363 // Limit the send area vertically to 1/2
364 if(abs(p.Y - center.Y) > d_max / 2)
370 If block is far away, don't generate it unless it is
376 // Block center y in nodes
377 f32 y = (f32)(p.Y * MAP_BLOCKSIZE + MAP_BLOCKSIZE/2);
378 // Don't generate if it's very high or very low
379 if(y < -64 || y > 64)
383 v2s16 p2d_nodes_center(
387 // Get ground height in nodes
388 s16 gh = server->m_env->getServerMap().findGroundLevel(
391 // If differs a lot, don't generate
392 if(fabs(gh - y) > MAP_BLOCKSIZE*2)
394 // Actually, don't even send it
400 //infostream<<"d="<<d<<std::endl;
403 Don't generate or send if not in sight
404 FIXME This only works if the client uses a small enough
405 FOV setting. The default of 72 degrees is fine.
408 float camera_fov = (72.0*M_PI/180) * 4./3.;
409 if(isBlockInSight(p, camera_pos, camera_dir, camera_fov, 10000*BS) == false)
415 Don't send already sent blocks
418 if(m_blocks_sent.find(p) != m_blocks_sent.end())
425 Check if map has this block
427 MapBlock *block = server->m_env->getMap().getBlockNoCreateNoEx(p);
429 bool surely_not_found_on_disk = false;
430 bool block_is_invalid = false;
433 // Reset usage timer, this block will be of use in the future.
434 block->resetUsageTimer();
436 // Block is dummy if data doesn't exist.
437 // It means it has been not found from disk and not generated
440 surely_not_found_on_disk = true;
443 // Block is valid if lighting is up-to-date and data exists
444 if(block->isValid() == false)
446 block_is_invalid = true;
449 /*if(block->isFullyGenerated() == false)
451 block_is_invalid = true;
456 ServerMap *map = (ServerMap*)(&server->m_env->getMap());
457 v2s16 chunkpos = map->sector_to_chunk(p2d);
458 if(map->chunkNonVolatile(chunkpos) == false)
459 block_is_invalid = true;
461 if(block->isGenerated() == false)
462 block_is_invalid = true;
465 If block is not close, don't send it unless it is near
468 Block is near ground level if night-time mesh
469 differs from day-time mesh.
473 if(block->getDayNightDiff() == false)
480 If block has been marked to not exist on disk (dummy)
481 and generating new ones is not wanted, skip block.
483 if(generate == false && surely_not_found_on_disk == true)
490 Add inexistent block to emerge queue.
492 if(block == NULL || surely_not_found_on_disk || block_is_invalid)
494 /* //TODO: Get value from somewhere
495 // Allow only one block in emerge queue
496 //if(server->m_emerge_queue.peerItemCount(peer_id) < 1)
497 // Allow two blocks in queue per client
498 //if(server->m_emerge_queue.peerItemCount(peer_id) < 2)
500 // Make it more responsive when needing to generate stuff
501 if(surely_not_found_on_disk)
503 if(server->m_emerge_queue.peerItemCount(peer_id) < max_emerge)
505 //infostream<<"Adding block to emerge queue"<<std::endl;
507 // Add it to the emerge queue and trigger the thread
510 if(generate == false)
511 flags |= BLOCK_EMERGE_FLAG_FROMDISK;
513 server->m_emerge_queue.addBlock(peer_id, p, flags);
514 server->m_emergethread.trigger();
516 if(nearest_emerged_d == -1)
517 nearest_emerged_d = d;
519 if(nearest_emergefull_d == -1)
520 nearest_emergefull_d = d;
521 goto queue_full_break;
525 if (server->m_emerge->enqueueBlockEmerge(peer_id, p, generate)) {
526 if (nearest_emerged_d == -1)
527 nearest_emerged_d = d;
529 if (nearest_emergefull_d == -1)
530 nearest_emergefull_d = d;
531 goto queue_full_break;
538 if(nearest_sent_d == -1)
542 Add block to send queue
545 /*errorstream<<"sending from d="<<d<<" to "
546 <<server->getPlayerName(peer_id)<<std::endl;*/
548 PrioritySortedBlockTransfer q((float)d, p, peer_id);
552 num_blocks_selected += 1;
557 //infostream<<"Stopped at "<<d<<std::endl;
559 // If nothing was found for sending and nothing was queued for
560 // emerging, continue next time browsing from here
561 if(nearest_emerged_d != -1){
562 new_nearest_unsent_d = nearest_emerged_d;
563 } else if(nearest_emergefull_d != -1){
564 new_nearest_unsent_d = nearest_emergefull_d;
566 if(d > g_settings->getS16("max_block_send_distance")){
567 new_nearest_unsent_d = 0;
568 m_nothing_to_send_pause_timer = 2.0;
569 /*infostream<<"GetNextBlocks(): d wrapped around for "
570 <<server->getPlayerName(peer_id)
571 <<"; setting to 0 and pausing"<<std::endl;*/
573 if(nearest_sent_d != -1)
574 new_nearest_unsent_d = nearest_sent_d;
576 new_nearest_unsent_d = d;
580 if(new_nearest_unsent_d != -1)
581 m_nearest_unsent_d = new_nearest_unsent_d;
583 /*timer_result = timer.stop(true);
584 if(timer_result != 0)
585 infostream<<"GetNextBlocks timeout: "<<timer_result<<" (!=0)"<<std::endl;*/
588 void RemoteClient::GotBlock(v3s16 p)
590 if(m_blocks_sending.find(p) != m_blocks_sending.end())
591 m_blocks_sending.erase(p);
594 /*infostream<<"RemoteClient::GotBlock(): Didn't find in"
595 " m_blocks_sending"<<std::endl;*/
596 m_excess_gotblocks++;
598 m_blocks_sent.insert(p);
601 void RemoteClient::SentBlock(v3s16 p)
603 if(m_blocks_sending.find(p) == m_blocks_sending.end())
604 m_blocks_sending[p] = 0.0;
606 infostream<<"RemoteClient::SentBlock(): Sent block"
607 " already in m_blocks_sending"<<std::endl;
610 void RemoteClient::SetBlockNotSent(v3s16 p)
612 m_nearest_unsent_d = 0;
614 if(m_blocks_sending.find(p) != m_blocks_sending.end())
615 m_blocks_sending.erase(p);
616 if(m_blocks_sent.find(p) != m_blocks_sent.end())
617 m_blocks_sent.erase(p);
620 void RemoteClient::SetBlocksNotSent(std::map<v3s16, MapBlock*> &blocks)
622 m_nearest_unsent_d = 0;
624 for(std::map<v3s16, MapBlock*>::iterator
626 i != blocks.end(); ++i)
630 if(m_blocks_sending.find(p) != m_blocks_sending.end())
631 m_blocks_sending.erase(p);
632 if(m_blocks_sent.find(p) != m_blocks_sent.end())
633 m_blocks_sent.erase(p);
642 const std::string &path_world,
643 const SubgameSpec &gamespec,
644 bool simple_singleplayer_mode
646 m_path_world(path_world),
647 m_gamespec(gamespec),
648 m_simple_singleplayer_mode(simple_singleplayer_mode),
649 m_async_fatal_error(""),
651 m_con(PROTOCOL_ID, 512, CONNECTION_TIMEOUT,
652 g_settings->getBool("enable_ipv6") && g_settings->getBool("ipv6_server"), this),
655 m_rollback_sink_enabled(true),
656 m_enable_rollback_recording(false),
659 m_itemdef(createItemDefManager()),
660 m_nodedef(createNodeDefManager()),
661 m_craftdef(createCraftDefManager()),
662 m_event(new EventManager()),
664 m_time_of_day_send_timer(0),
666 m_shutdown_requested(false),
667 m_ignore_map_edit_events(false),
668 m_ignore_map_edit_events_peer_id(0)
670 m_liquid_transform_timer = 0.0;
671 m_liquid_transform_every = 1.0;
672 m_print_info_timer = 0.0;
673 m_masterserver_timer = 0.0;
674 m_objectdata_timer = 0.0;
675 m_emergethread_trigger_timer = 0.0;
676 m_savemap_timer = 0.0;
679 m_lag = g_settings->getFloat("dedicated_server_step");
682 throw ServerError("Supplied empty world path");
684 if(!gamespec.isValid())
685 throw ServerError("Supplied invalid gamespec");
687 infostream<<"Server created for gameid \""<<m_gamespec.id<<"\"";
688 if(m_simple_singleplayer_mode)
689 infostream<<" in simple singleplayer mode"<<std::endl;
691 infostream<<std::endl;
692 infostream<<"- world: "<<m_path_world<<std::endl;
693 infostream<<"- game: "<<m_gamespec.path<<std::endl;
695 // Initialize default settings and override defaults with those provided
697 set_default_settings(g_settings);
698 Settings gamedefaults;
699 getGameMinetestConfig(gamespec.path, gamedefaults);
700 override_default_settings(g_settings, &gamedefaults);
702 // Create server thread
703 m_thread = new ServerThread(this);
705 // Create emerge manager
706 m_emerge = new EmergeManager(this);
708 // Create world if it doesn't exist
709 if(!initializeWorld(m_path_world, m_gamespec.id))
710 throw ServerError("Failed to initialize world");
712 // Create ban manager
713 std::string ban_path = m_path_world+DIR_DELIM+"ipban.txt";
714 m_banmanager = new BanManager(ban_path);
716 // Create rollback manager
717 std::string rollback_path = m_path_world+DIR_DELIM+"rollback.txt";
718 m_rollback = createRollbackManager(rollback_path, this);
720 ModConfiguration modconf(m_path_world);
721 m_mods = modconf.getMods();
722 std::vector<ModSpec> unsatisfied_mods = modconf.getUnsatisfiedMods();
723 // complain about mods with unsatisfied dependencies
724 if(!modconf.isConsistent())
726 for(std::vector<ModSpec>::iterator it = unsatisfied_mods.begin();
727 it != unsatisfied_mods.end(); ++it)
730 errorstream << "mod \"" << mod.name << "\" has unsatisfied dependencies: ";
731 for(std::set<std::string>::iterator dep_it = mod.unsatisfied_depends.begin();
732 dep_it != mod.unsatisfied_depends.end(); ++dep_it)
733 errorstream << " \"" << *dep_it << "\"";
734 errorstream << std::endl;
738 Settings worldmt_settings;
739 std::string worldmt = m_path_world + DIR_DELIM + "world.mt";
740 worldmt_settings.readConfigFile(worldmt.c_str());
741 std::vector<std::string> names = worldmt_settings.getNames();
742 std::set<std::string> load_mod_names;
743 for(std::vector<std::string>::iterator it = names.begin();
744 it != names.end(); ++it)
746 std::string name = *it;
747 if(name.compare(0,9,"load_mod_")==0 && worldmt_settings.getBool(name))
748 load_mod_names.insert(name.substr(9));
750 // complain about mods declared to be loaded, but not found
751 for(std::vector<ModSpec>::iterator it = m_mods.begin();
752 it != m_mods.end(); ++it)
753 load_mod_names.erase((*it).name);
754 for(std::vector<ModSpec>::iterator it = unsatisfied_mods.begin();
755 it != unsatisfied_mods.end(); ++it)
756 load_mod_names.erase((*it).name);
757 if(!load_mod_names.empty())
759 errorstream << "The following mods could not be found:";
760 for(std::set<std::string>::iterator it = load_mod_names.begin();
761 it != load_mod_names.end(); ++it)
762 errorstream << " \"" << (*it) << "\"";
763 errorstream << std::endl;
766 // Path to builtin.lua
767 std::string builtinpath = getBuiltinLuaPath() + DIR_DELIM + "builtin.lua";
770 JMutexAutoLock envlock(m_env_mutex);
771 JMutexAutoLock conlock(m_con_mutex);
773 // Initialize scripting
775 infostream<<"Server: Initializing Lua"<<std::endl;
777 m_script = new GameScripting(this);
780 // Load and run builtin.lua
781 infostream<<"Server: Loading builtin.lua [\""
782 <<builtinpath<<"\"]"<<std::endl;
783 bool success = m_script->loadMod(builtinpath, "__builtin");
785 errorstream<<"Server: Failed to load and run "
786 <<builtinpath<<std::endl;
787 throw ModError("Failed to load and run "+builtinpath);
790 infostream<<"Server: Loading mods: ";
791 for(std::vector<ModSpec>::iterator i = m_mods.begin();
792 i != m_mods.end(); i++){
793 const ModSpec &mod = *i;
794 infostream<<mod.name<<" ";
796 infostream<<std::endl;
797 // Load and run "mod" scripts
798 for(std::vector<ModSpec>::iterator i = m_mods.begin();
799 i != m_mods.end(); i++){
800 const ModSpec &mod = *i;
801 std::string scriptpath = mod.path + DIR_DELIM + "init.lua";
802 infostream<<" ["<<padStringRight(mod.name, 12)<<"] [\""
803 <<scriptpath<<"\"]"<<std::endl;
804 bool success = m_script->loadMod(scriptpath, mod.name);
806 errorstream<<"Server: Failed to load and run "
807 <<scriptpath<<std::endl;
808 throw ModError("Failed to load and run "+scriptpath);
812 // Read Textures and calculate sha1 sums
815 // Apply item aliases in the node definition manager
816 m_nodedef->updateAliases(m_itemdef);
818 // Initialize Environment
819 ServerMap *servermap = new ServerMap(path_world, this, m_emerge);
820 m_env = new ServerEnvironment(servermap, m_script, this, m_emerge);
822 // Run some callbacks after the MG params have been set up but before activation
823 MapgenParams *mgparams = servermap->getMapgenParams();
824 m_script->environment_OnMapgenInit(mgparams);
826 // Initialize mapgens
827 m_emerge->initMapgens(mgparams);
828 servermap->setMapgenParams(m_emerge->params);
830 // Give environment reference to scripting api
831 m_script->initializeEnvironment(m_env);
833 // Register us to receive map edit events
834 servermap->addEventReceiver(this);
836 // If file exists, load environment metadata
837 if(fs::PathExists(m_path_world+DIR_DELIM+"env_meta.txt"))
839 infostream<<"Server: Loading environment metadata"<<std::endl;
840 m_env->loadMeta(m_path_world);
844 infostream<<"Server: Loading players"<<std::endl;
845 m_env->deSerializePlayers(m_path_world);
848 Add some test ActiveBlockModifiers to environment
850 add_legacy_abms(m_env, m_nodedef);
852 m_liquid_transform_every = g_settings->getFloat("liquid_update");
857 infostream<<"Server destructing"<<std::endl;
860 Send shutdown message
863 JMutexAutoLock conlock(m_con_mutex);
865 std::wstring line = L"*** Server shutting down";
868 Send the message to clients
870 for(std::map<u16, RemoteClient*>::iterator
871 i = m_clients.begin();
872 i != m_clients.end(); ++i)
874 // Get client and check that it is valid
875 RemoteClient *client = i->second;
876 assert(client->peer_id == i->first);
877 if(client->serialization_version == SER_FMT_VER_INVALID)
881 SendChatMessage(client->peer_id, line);
883 catch(con::PeerNotFoundException &e)
889 JMutexAutoLock envlock(m_env_mutex);
890 JMutexAutoLock conlock(m_con_mutex);
893 Execute script shutdown hooks
895 m_script->on_shutdown();
899 JMutexAutoLock envlock(m_env_mutex);
904 infostream<<"Server: Saving players"<<std::endl;
905 m_env->serializePlayers(m_path_world);
908 Save environment metadata
910 infostream<<"Server: Saving environment metadata"<<std::endl;
911 m_env->saveMeta(m_path_world);
920 //shutdown all emerge threads first!
927 JMutexAutoLock clientslock(m_con_mutex);
929 for(std::map<u16, RemoteClient*>::iterator
930 i = m_clients.begin();
931 i != m_clients.end(); ++i)
939 // Delete things in the reverse order of creation
948 // Deinitialize scripting
949 infostream<<"Server: Deinitializing scripting"<<std::endl;
952 // Delete detached inventories
954 for(std::map<std::string, Inventory*>::iterator
955 i = m_detached_inventories.begin();
956 i != m_detached_inventories.end(); i++){
962 void Server::start(unsigned short port)
964 DSTACK(__FUNCTION_NAME);
965 infostream<<"Starting server on port "<<port<<"..."<<std::endl;
967 // Stop thread if already running
970 // Initialize connection
971 m_con.SetTimeoutMs(30);
977 // ASCII art for the win!
979 <<" .__ __ __ "<<std::endl
980 <<" _____ |__| ____ _____/ |_ ____ _______/ |_ "<<std::endl
981 <<" / \\| |/ \\_/ __ \\ __\\/ __ \\ / ___/\\ __\\"<<std::endl
982 <<"| Y Y \\ | | \\ ___/| | \\ ___/ \\___ \\ | | "<<std::endl
983 <<"|__|_| /__|___| /\\___ >__| \\___ >____ > |__| "<<std::endl
984 <<" \\/ \\/ \\/ \\/ \\/ "<<std::endl;
985 actionstream<<"World at ["<<m_path_world<<"]"<<std::endl;
986 actionstream<<"Server for gameid=\""<<m_gamespec.id
987 <<"\" listening on port "<<port<<"."<<std::endl;
992 DSTACK(__FUNCTION_NAME);
994 infostream<<"Server: Stopping and waiting threads"<<std::endl;
996 // Stop threads (set run=false first so both start stopping)
998 //m_emergethread.setRun(false);
1000 //m_emergethread.stop();
1002 infostream<<"Server: Threads stopped"<<std::endl;
1005 void Server::step(float dtime)
1007 DSTACK(__FUNCTION_NAME);
1012 JMutexAutoLock lock(m_step_dtime_mutex);
1013 m_step_dtime += dtime;
1015 // Throw if fatal error occurred in thread
1016 std::string async_err = m_async_fatal_error.get();
1017 if(async_err != ""){
1018 throw ServerError(async_err);
1022 void Server::AsyncRunStep(bool initial_step)
1024 DSTACK(__FUNCTION_NAME);
1026 g_profiler->add("Server::AsyncRunStep (num)", 1);
1030 JMutexAutoLock lock1(m_step_dtime_mutex);
1031 dtime = m_step_dtime;
1035 // Send blocks to clients
1039 if((dtime < 0.001) && (initial_step == false))
1042 g_profiler->add("Server::AsyncRunStep with dtime (num)", 1);
1044 //infostream<<"Server steps "<<dtime<<std::endl;
1045 //infostream<<"Server::AsyncRunStep(): dtime="<<dtime<<std::endl;
1048 JMutexAutoLock lock1(m_step_dtime_mutex);
1049 m_step_dtime -= dtime;
1056 m_uptime.set(m_uptime.get() + dtime);
1060 // Process connection's timeouts
1061 JMutexAutoLock lock2(m_con_mutex);
1062 ScopeProfiler sp(g_profiler, "Server: connection timeout processing");
1063 m_con.RunTimeouts(dtime);
1067 // This has to be called so that the client list gets synced
1068 // with the peer list of the connection
1069 handlePeerChanges();
1073 Update time of day and overall game time
1076 JMutexAutoLock envlock(m_env_mutex);
1078 m_env->setTimeOfDaySpeed(g_settings->getFloat("time_speed"));
1081 Send to clients at constant intervals
1084 m_time_of_day_send_timer -= dtime;
1085 if(m_time_of_day_send_timer < 0.0)
1087 m_time_of_day_send_timer = g_settings->getFloat("time_send_interval");
1089 //JMutexAutoLock envlock(m_env_mutex);
1090 JMutexAutoLock conlock(m_con_mutex);
1092 u16 time = m_env->getTimeOfDay();
1093 float time_speed = g_settings->getFloat("time_speed");
1095 for(std::map<u16, RemoteClient*>::iterator
1096 i = m_clients.begin();
1097 i != m_clients.end(); ++i)
1099 RemoteClient *client = i->second;
1100 SendTimeOfDay(client->peer_id, time, time_speed);
1106 JMutexAutoLock lock(m_env_mutex);
1107 // Figure out and report maximum lag to environment
1108 float max_lag = m_env->getMaxLagEstimate();
1109 max_lag *= 0.9998; // Decrease slowly (about half per 5 minutes)
1110 if(dtime > max_lag){
1111 if(dtime > 0.1 && dtime > max_lag * 2.0)
1112 infostream<<"Server: Maximum lag peaked to "<<dtime
1116 m_env->reportMaxLagEstimate(max_lag);
1118 ScopeProfiler sp(g_profiler, "SEnv step");
1119 ScopeProfiler sp2(g_profiler, "SEnv step avg", SPT_AVG);
1123 const float map_timer_and_unload_dtime = 2.92;
1124 if(m_map_timer_and_unload_interval.step(dtime, map_timer_and_unload_dtime))
1126 JMutexAutoLock lock(m_env_mutex);
1127 // Run Map's timers and unload unused data
1128 ScopeProfiler sp(g_profiler, "Server: map timer and unload");
1129 m_env->getMap().timerUpdate(map_timer_and_unload_dtime,
1130 g_settings->getFloat("server_unload_unused_data_timeout"));
1141 JMutexAutoLock lock(m_env_mutex);
1142 JMutexAutoLock lock2(m_con_mutex);
1144 ScopeProfiler sp(g_profiler, "Server: handle players");
1146 for(std::map<u16, RemoteClient*>::iterator
1147 i = m_clients.begin();
1148 i != m_clients.end(); ++i)
1150 RemoteClient *client = i->second;
1151 PlayerSAO *playersao = getPlayerSAO(client->peer_id);
1152 if(playersao == NULL)
1156 Handle player HPs (die if hp=0)
1158 if(playersao->m_hp_not_sent && g_settings->getBool("enable_damage"))
1160 if(playersao->getHP() == 0)
1161 DiePlayer(client->peer_id);
1163 SendPlayerHP(client->peer_id);
1167 Send player breath if changed
1169 if(playersao->m_breath_not_sent){
1170 SendPlayerBreath(client->peer_id);
1174 Send player inventories if necessary
1176 if(playersao->m_moved){
1177 SendMovePlayer(client->peer_id);
1178 playersao->m_moved = false;
1180 if(playersao->m_inventory_not_sent){
1181 UpdateCrafting(client->peer_id);
1182 SendInventory(client->peer_id);
1187 /* Transform liquids */
1188 m_liquid_transform_timer += dtime;
1189 if(m_liquid_transform_timer >= m_liquid_transform_every)
1191 m_liquid_transform_timer -= m_liquid_transform_every;
1193 JMutexAutoLock lock(m_env_mutex);
1195 ScopeProfiler sp(g_profiler, "Server: liquid transform");
1197 std::map<v3s16, MapBlock*> modified_blocks;
1198 m_env->getMap().transformLiquids(modified_blocks);
1203 core::map<v3s16, MapBlock*> lighting_modified_blocks;
1204 ServerMap &map = ((ServerMap&)m_env->getMap());
1205 map.updateLighting(modified_blocks, lighting_modified_blocks);
1207 // Add blocks modified by lighting to modified_blocks
1208 for(core::map<v3s16, MapBlock*>::Iterator
1209 i = lighting_modified_blocks.getIterator();
1210 i.atEnd() == false; i++)
1212 MapBlock *block = i.getNode()->getValue();
1213 modified_blocks.insert(block->getPos(), block);
1217 Set the modified blocks unsent for all the clients
1220 JMutexAutoLock lock2(m_con_mutex);
1222 for(std::map<u16, RemoteClient*>::iterator
1223 i = m_clients.begin();
1224 i != m_clients.end(); ++i)
1226 RemoteClient *client = i->second;
1228 if(modified_blocks.size() > 0)
1230 // Remove block from sent history
1231 client->SetBlocksNotSent(modified_blocks);
1236 // Periodically print some info
1238 float &counter = m_print_info_timer;
1244 JMutexAutoLock lock2(m_con_mutex);
1245 m_clients_names.clear();
1246 if(m_clients.size() != 0)
1247 infostream<<"Players:"<<std::endl;
1248 for(std::map<u16, RemoteClient*>::iterator
1249 i = m_clients.begin();
1250 i != m_clients.end(); ++i)
1252 //u16 peer_id = i.getNode()->getKey();
1253 RemoteClient *client = i->second;
1254 Player *player = m_env->getPlayer(client->peer_id);
1257 infostream<<"* "<<player->getName()<<"\t";
1258 client->PrintInfo(infostream);
1259 m_clients_names.push_back(player->getName());
1265 m_lag += (m_lag > dtime ? -1 : 1) * dtime/100;
1267 // send masterserver announce
1269 float &counter = m_masterserver_timer;
1270 if(!isSingleplayer() && (!counter || counter >= 300.0) && g_settings->getBool("server_announce") == true)
1272 ServerList::sendAnnounce(!counter ? "start" : "update", m_clients_names, m_uptime.get(), m_env->getGameTime(), m_lag, m_gamespec.id, m_mods);
1279 //if(g_settings->getBool("enable_experimental"))
1283 Check added and deleted active objects
1286 //infostream<<"Server: Checking added and deleted active objects"<<std::endl;
1287 JMutexAutoLock envlock(m_env_mutex);
1288 JMutexAutoLock conlock(m_con_mutex);
1290 ScopeProfiler sp(g_profiler, "Server: checking added and deleted objs");
1292 // Radius inside which objects are active
1293 s16 radius = g_settings->getS16("active_object_send_range_blocks");
1294 radius *= MAP_BLOCKSIZE;
1296 for(std::map<u16, RemoteClient*>::iterator
1297 i = m_clients.begin();
1298 i != m_clients.end(); ++i)
1300 RemoteClient *client = i->second;
1302 // If definitions and textures have not been sent, don't
1303 // send objects either
1304 if(!client->definitions_sent)
1307 Player *player = m_env->getPlayer(client->peer_id);
1310 // This can happen if the client timeouts somehow
1311 /*infostream<<"WARNING: "<<__FUNCTION_NAME<<": Client "
1313 <<" has no associated player"<<std::endl;*/
1316 v3s16 pos = floatToInt(player->getPosition(), BS);
1318 std::set<u16> removed_objects;
1319 std::set<u16> added_objects;
1320 m_env->getRemovedActiveObjects(pos, radius,
1321 client->m_known_objects, removed_objects);
1322 m_env->getAddedActiveObjects(pos, radius,
1323 client->m_known_objects, added_objects);
1325 // Ignore if nothing happened
1326 if(removed_objects.size() == 0 && added_objects.size() == 0)
1328 //infostream<<"active objects: none changed"<<std::endl;
1332 std::string data_buffer;
1336 // Handle removed objects
1337 writeU16((u8*)buf, removed_objects.size());
1338 data_buffer.append(buf, 2);
1339 for(std::set<u16>::iterator
1340 i = removed_objects.begin();
1341 i != removed_objects.end(); ++i)
1345 ServerActiveObject* obj = m_env->getActiveObject(id);
1347 // Add to data buffer for sending
1348 writeU16((u8*)buf, id);
1349 data_buffer.append(buf, 2);
1351 // Remove from known objects
1352 client->m_known_objects.erase(id);
1354 if(obj && obj->m_known_by_count > 0)
1355 obj->m_known_by_count--;
1358 // Handle added objects
1359 writeU16((u8*)buf, added_objects.size());
1360 data_buffer.append(buf, 2);
1361 for(std::set<u16>::iterator
1362 i = added_objects.begin();
1363 i != added_objects.end(); ++i)
1367 ServerActiveObject* obj = m_env->getActiveObject(id);
1370 u8 type = ACTIVEOBJECT_TYPE_INVALID;
1372 infostream<<"WARNING: "<<__FUNCTION_NAME
1373 <<": NULL object"<<std::endl;
1375 type = obj->getSendType();
1377 // Add to data buffer for sending
1378 writeU16((u8*)buf, id);
1379 data_buffer.append(buf, 2);
1380 writeU8((u8*)buf, type);
1381 data_buffer.append(buf, 1);
1384 data_buffer.append(serializeLongString(
1385 obj->getClientInitializationData(client->net_proto_version)));
1387 data_buffer.append(serializeLongString(""));
1389 // Add to known objects
1390 client->m_known_objects.insert(id);
1393 obj->m_known_by_count++;
1397 SharedBuffer<u8> reply(2 + data_buffer.size());
1398 writeU16(&reply[0], TOCLIENT_ACTIVE_OBJECT_REMOVE_ADD);
1399 memcpy((char*)&reply[2], data_buffer.c_str(),
1400 data_buffer.size());
1402 m_con.Send(client->peer_id, 0, reply, true);
1404 verbosestream<<"Server: Sent object remove/add: "
1405 <<removed_objects.size()<<" removed, "
1406 <<added_objects.size()<<" added, "
1407 <<"packet size is "<<reply.getSize()<<std::endl;
1412 Collect a list of all the objects known by the clients
1413 and report it back to the environment.
1416 core::map<u16, bool> all_known_objects;
1418 for(core::map<u16, RemoteClient*>::Iterator
1419 i = m_clients.getIterator();
1420 i.atEnd() == false; i++)
1422 RemoteClient *client = i.getNode()->getValue();
1423 // Go through all known objects of client
1424 for(core::map<u16, bool>::Iterator
1425 i = client->m_known_objects.getIterator();
1426 i.atEnd()==false; i++)
1428 u16 id = i.getNode()->getKey();
1429 all_known_objects[id] = true;
1433 m_env->setKnownActiveObjects(whatever);
1439 Send object messages
1442 JMutexAutoLock envlock(m_env_mutex);
1443 JMutexAutoLock conlock(m_con_mutex);
1445 ScopeProfiler sp(g_profiler, "Server: sending object messages");
1448 // Value = data sent by object
1449 std::map<u16, std::list<ActiveObjectMessage>* > buffered_messages;
1451 // Get active object messages from environment
1454 ActiveObjectMessage aom = m_env->getActiveObjectMessage();
1458 std::list<ActiveObjectMessage>* message_list = NULL;
1459 std::map<u16, std::list<ActiveObjectMessage>* >::iterator n;
1460 n = buffered_messages.find(aom.id);
1461 if(n == buffered_messages.end())
1463 message_list = new std::list<ActiveObjectMessage>;
1464 buffered_messages[aom.id] = message_list;
1468 message_list = n->second;
1470 message_list->push_back(aom);
1473 // Route data to every client
1474 for(std::map<u16, RemoteClient*>::iterator
1475 i = m_clients.begin();
1476 i != m_clients.end(); ++i)
1478 RemoteClient *client = i->second;
1479 std::string reliable_data;
1480 std::string unreliable_data;
1481 // Go through all objects in message buffer
1482 for(std::map<u16, std::list<ActiveObjectMessage>* >::iterator
1483 j = buffered_messages.begin();
1484 j != buffered_messages.end(); ++j)
1486 // If object is not known by client, skip it
1488 if(client->m_known_objects.find(id) == client->m_known_objects.end())
1490 // Get message list of object
1491 std::list<ActiveObjectMessage>* list = j->second;
1492 // Go through every message
1493 for(std::list<ActiveObjectMessage>::iterator
1494 k = list->begin(); k != list->end(); ++k)
1496 // Compose the full new data with header
1497 ActiveObjectMessage aom = *k;
1498 std::string new_data;
1501 writeU16((u8*)&buf[0], aom.id);
1502 new_data.append(buf, 2);
1504 new_data += serializeString(aom.datastring);
1505 // Add data to buffer
1507 reliable_data += new_data;
1509 unreliable_data += new_data;
1513 reliable_data and unreliable_data are now ready.
1516 if(reliable_data.size() > 0)
1518 SharedBuffer<u8> reply(2 + reliable_data.size());
1519 writeU16(&reply[0], TOCLIENT_ACTIVE_OBJECT_MESSAGES);
1520 memcpy((char*)&reply[2], reliable_data.c_str(),
1521 reliable_data.size());
1523 m_con.Send(client->peer_id, 0, reply, true);
1525 if(unreliable_data.size() > 0)
1527 SharedBuffer<u8> reply(2 + unreliable_data.size());
1528 writeU16(&reply[0], TOCLIENT_ACTIVE_OBJECT_MESSAGES);
1529 memcpy((char*)&reply[2], unreliable_data.c_str(),
1530 unreliable_data.size());
1531 // Send as unreliable
1532 m_con.Send(client->peer_id, 1, reply, false);
1535 /*if(reliable_data.size() > 0 || unreliable_data.size() > 0)
1537 infostream<<"Server: Size of object message data: "
1538 <<"reliable: "<<reliable_data.size()
1539 <<", unreliable: "<<unreliable_data.size()
1544 // Clear buffered_messages
1545 for(std::map<u16, std::list<ActiveObjectMessage>* >::iterator
1546 i = buffered_messages.begin();
1547 i != buffered_messages.end(); ++i)
1553 } // enable_experimental
1556 Send queued-for-sending map edit events.
1559 // We will be accessing the environment and the connection
1560 JMutexAutoLock lock(m_env_mutex);
1561 JMutexAutoLock conlock(m_con_mutex);
1563 // Don't send too many at a time
1566 // Single change sending is disabled if queue size is not small
1567 bool disable_single_change_sending = false;
1568 if(m_unsent_map_edit_queue.size() >= 4)
1569 disable_single_change_sending = true;
1571 int event_count = m_unsent_map_edit_queue.size();
1573 // We'll log the amount of each
1576 while(m_unsent_map_edit_queue.size() != 0)
1578 MapEditEvent* event = m_unsent_map_edit_queue.pop_front();
1580 // Players far away from the change are stored here.
1581 // Instead of sending the changes, MapBlocks are set not sent
1583 std::list<u16> far_players;
1585 if(event->type == MEET_ADDNODE || event->type == MEET_SWAPNODE)
1587 //infostream<<"Server: MEET_ADDNODE"<<std::endl;
1588 prof.add("MEET_ADDNODE", 1);
1589 if(disable_single_change_sending)
1590 sendAddNode(event->p, event->n, event->already_known_by_peer,
1591 &far_players, 5, event->type == MEET_ADDNODE);
1593 sendAddNode(event->p, event->n, event->already_known_by_peer,
1594 &far_players, 30, event->type == MEET_ADDNODE);
1596 else if(event->type == MEET_REMOVENODE)
1598 //infostream<<"Server: MEET_REMOVENODE"<<std::endl;
1599 prof.add("MEET_REMOVENODE", 1);
1600 if(disable_single_change_sending)
1601 sendRemoveNode(event->p, event->already_known_by_peer,
1604 sendRemoveNode(event->p, event->already_known_by_peer,
1607 else if(event->type == MEET_BLOCK_NODE_METADATA_CHANGED)
1609 infostream<<"Server: MEET_BLOCK_NODE_METADATA_CHANGED"<<std::endl;
1610 prof.add("MEET_BLOCK_NODE_METADATA_CHANGED", 1);
1611 setBlockNotSent(event->p);
1613 else if(event->type == MEET_OTHER)
1615 infostream<<"Server: MEET_OTHER"<<std::endl;
1616 prof.add("MEET_OTHER", 1);
1617 for(std::set<v3s16>::iterator
1618 i = event->modified_blocks.begin();
1619 i != event->modified_blocks.end(); ++i)
1621 setBlockNotSent(*i);
1626 prof.add("unknown", 1);
1627 infostream<<"WARNING: Server: Unknown MapEditEvent "
1628 <<((u32)event->type)<<std::endl;
1632 Set blocks not sent to far players
1634 if(far_players.size() > 0)
1636 // Convert list format to that wanted by SetBlocksNotSent
1637 std::map<v3s16, MapBlock*> modified_blocks2;
1638 for(std::set<v3s16>::iterator
1639 i = event->modified_blocks.begin();
1640 i != event->modified_blocks.end(); ++i)
1642 modified_blocks2[*i] =
1643 m_env->getMap().getBlockNoCreateNoEx(*i);
1645 // Set blocks not sent
1646 for(std::list<u16>::iterator
1647 i = far_players.begin();
1648 i != far_players.end(); ++i)
1651 RemoteClient *client = getClient(peer_id);
1654 client->SetBlocksNotSent(modified_blocks2);
1660 /*// Don't send too many at a time
1662 if(count >= 1 && m_unsent_map_edit_queue.size() < 100)
1666 if(event_count >= 5){
1667 infostream<<"Server: MapEditEvents:"<<std::endl;
1668 prof.print(infostream);
1669 } else if(event_count != 0){
1670 verbosestream<<"Server: MapEditEvents:"<<std::endl;
1671 prof.print(verbosestream);
1677 Trigger emergethread (it somehow gets to a non-triggered but
1678 bysy state sometimes)
1681 float &counter = m_emergethread_trigger_timer;
1687 m_emerge->startAllThreads();
1689 // Update m_enable_rollback_recording here too
1690 m_enable_rollback_recording =
1691 g_settings->getBool("enable_rollback_recording");
1695 // Save map, players and auth stuff
1697 float &counter = m_savemap_timer;
1699 if(counter >= g_settings->getFloat("server_map_save_interval"))
1702 JMutexAutoLock lock(m_env_mutex);
1704 ScopeProfiler sp(g_profiler, "Server: saving stuff");
1707 if(m_banmanager->isModified())
1708 m_banmanager->save();
1710 // Save changed parts of map
1711 m_env->getMap().save(MOD_STATE_WRITE_NEEDED);
1714 m_env->serializePlayers(m_path_world);
1716 // Save environment metadata
1717 m_env->saveMeta(m_path_world);
1722 void Server::Receive()
1724 DSTACK(__FUNCTION_NAME);
1725 SharedBuffer<u8> data;
1730 JMutexAutoLock conlock(m_con_mutex);
1731 datasize = m_con.Receive(peer_id, data);
1734 // This has to be called so that the client list gets synced
1735 // with the peer list of the connection
1736 handlePeerChanges();
1738 ProcessData(*data, datasize, peer_id);
1740 catch(con::InvalidIncomingDataException &e)
1742 infostream<<"Server::Receive(): "
1743 "InvalidIncomingDataException: what()="
1744 <<e.what()<<std::endl;
1746 catch(con::PeerNotFoundException &e)
1748 //NOTE: This is not needed anymore
1750 // The peer has been disconnected.
1751 // Find the associated player and remove it.
1753 /*JMutexAutoLock envlock(m_env_mutex);
1755 infostream<<"ServerThread: peer_id="<<peer_id
1756 <<" has apparently closed connection. "
1757 <<"Removing player."<<std::endl;
1759 m_env->removePlayer(peer_id);*/
1763 void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
1765 DSTACK(__FUNCTION_NAME);
1766 // Environment is locked first.
1767 JMutexAutoLock envlock(m_env_mutex);
1768 JMutexAutoLock conlock(m_con_mutex);
1770 ScopeProfiler sp(g_profiler, "Server::ProcessData");
1774 Address address = m_con.GetPeerAddress(peer_id);
1775 addr_s = address.serializeString();
1777 // drop player if is ip is banned
1778 if(m_banmanager->isIpBanned(addr_s)){
1779 std::string ban_name = m_banmanager->getBanName(addr_s);
1780 infostream<<"Server: A banned client tried to connect from "
1781 <<addr_s<<"; banned name was "
1782 <<ban_name<<std::endl;
1783 // This actually doesn't seem to transfer to the client
1784 DenyAccess(peer_id, L"Your ip is banned. Banned name was "
1785 +narrow_to_wide(ban_name));
1786 m_con.DeletePeer(peer_id);
1790 catch(con::PeerNotFoundException &e)
1792 infostream<<"Server::ProcessData(): Cancelling: peer "
1793 <<peer_id<<" not found"<<std::endl;
1797 u8 peer_ser_ver = getClient(peer_id)->serialization_version;
1805 ToServerCommand command = (ToServerCommand)readU16(&data[0]);
1807 if(command == TOSERVER_INIT)
1809 // [0] u16 TOSERVER_INIT
1810 // [2] u8 SER_FMT_VER_HIGHEST_READ
1811 // [3] u8[20] player_name
1812 // [23] u8[28] password <--- can be sent without this, from old versions
1814 if(datasize < 2+1+PLAYERNAME_SIZE)
1817 // If net_proto_version is set, this client has already been handled
1818 if(getClient(peer_id)->net_proto_version != 0){
1819 verbosestream<<"Server: Ignoring multiple TOSERVER_INITs from "
1820 <<addr_s<<" (peer_id="<<peer_id<<")"<<std::endl;
1824 verbosestream<<"Server: Got TOSERVER_INIT from "<<addr_s<<" (peer_id="
1825 <<peer_id<<")"<<std::endl;
1827 // Do not allow multiple players in simple singleplayer mode.
1828 // This isn't a perfect way to do it, but will suffice for now.
1829 if(m_simple_singleplayer_mode && m_clients.size() > 1){
1830 infostream<<"Server: Not allowing another client ("<<addr_s
1831 <<") to connect in simple singleplayer mode"<<std::endl;
1832 DenyAccess(peer_id, L"Running in simple singleplayer mode.");
1836 // First byte after command is maximum supported
1837 // serialization version
1838 u8 client_max = data[2];
1839 u8 our_max = SER_FMT_VER_HIGHEST_READ;
1840 // Use the highest version supported by both
1841 u8 deployed = std::min(client_max, our_max);
1842 // If it's lower than the lowest supported, give up.
1843 if(deployed < SER_FMT_VER_LOWEST)
1844 deployed = SER_FMT_VER_INVALID;
1846 //peer->serialization_version = deployed;
1847 getClient(peer_id)->pending_serialization_version = deployed;
1849 if(deployed == SER_FMT_VER_INVALID)
1851 actionstream<<"Server: A mismatched client tried to connect from "
1852 <<addr_s<<std::endl;
1853 infostream<<"Server: Cannot negotiate serialization version with "
1854 <<addr_s<<std::endl;
1855 DenyAccess(peer_id, std::wstring(
1856 L"Your client's version is not supported.\n"
1857 L"Server version is ")
1858 + narrow_to_wide(minetest_version_simple) + L"."
1864 Read and check network protocol version
1867 u16 min_net_proto_version = 0;
1868 if(datasize >= 2+1+PLAYERNAME_SIZE+PASSWORD_SIZE+2)
1869 min_net_proto_version = readU16(&data[2+1+PLAYERNAME_SIZE+PASSWORD_SIZE]);
1871 // Use same version as minimum and maximum if maximum version field
1872 // doesn't exist (backwards compatibility)
1873 u16 max_net_proto_version = min_net_proto_version;
1874 if(datasize >= 2+1+PLAYERNAME_SIZE+PASSWORD_SIZE+2+2)
1875 max_net_proto_version = readU16(&data[2+1+PLAYERNAME_SIZE+PASSWORD_SIZE+2]);
1877 // Start with client's maximum version
1878 u16 net_proto_version = max_net_proto_version;
1880 // Figure out a working version if it is possible at all
1881 if(max_net_proto_version >= SERVER_PROTOCOL_VERSION_MIN ||
1882 min_net_proto_version <= SERVER_PROTOCOL_VERSION_MAX)
1884 // If maximum is larger than our maximum, go with our maximum
1885 if(max_net_proto_version > SERVER_PROTOCOL_VERSION_MAX)
1886 net_proto_version = SERVER_PROTOCOL_VERSION_MAX;
1887 // Else go with client's maximum
1889 net_proto_version = max_net_proto_version;
1892 verbosestream<<"Server: "<<addr_s<<": Protocol version: min: "
1893 <<min_net_proto_version<<", max: "<<max_net_proto_version
1894 <<", chosen: "<<net_proto_version<<std::endl;
1896 getClient(peer_id)->net_proto_version = net_proto_version;
1898 if(net_proto_version < SERVER_PROTOCOL_VERSION_MIN ||
1899 net_proto_version > SERVER_PROTOCOL_VERSION_MAX)
1901 actionstream<<"Server: A mismatched client tried to connect from "
1902 <<addr_s<<std::endl;
1903 DenyAccess(peer_id, std::wstring(
1904 L"Your client's version is not supported.\n"
1905 L"Server version is ")
1906 + narrow_to_wide(minetest_version_simple) + L",\n"
1907 + L"server's PROTOCOL_VERSION is "
1908 + narrow_to_wide(itos(SERVER_PROTOCOL_VERSION_MIN))
1910 + narrow_to_wide(itos(SERVER_PROTOCOL_VERSION_MAX))
1911 + L", client's PROTOCOL_VERSION is "
1912 + narrow_to_wide(itos(min_net_proto_version))
1914 + narrow_to_wide(itos(max_net_proto_version))
1919 if(g_settings->getBool("strict_protocol_version_checking"))
1921 if(net_proto_version != LATEST_PROTOCOL_VERSION)
1923 actionstream<<"Server: A mismatched (strict) client tried to "
1924 <<"connect from "<<addr_s<<std::endl;
1925 DenyAccess(peer_id, std::wstring(
1926 L"Your client's version is not supported.\n"
1927 L"Server version is ")
1928 + narrow_to_wide(minetest_version_simple) + L",\n"
1929 + L"server's PROTOCOL_VERSION (strict) is "
1930 + narrow_to_wide(itos(LATEST_PROTOCOL_VERSION))
1931 + L", client's PROTOCOL_VERSION is "
1932 + narrow_to_wide(itos(min_net_proto_version))
1934 + narrow_to_wide(itos(max_net_proto_version))
1945 char playername[PLAYERNAME_SIZE];
1946 for(u32 i=0; i<PLAYERNAME_SIZE-1; i++)
1948 playername[i] = data[3+i];
1950 playername[PLAYERNAME_SIZE-1] = 0;
1952 if(playername[0]=='\0')
1954 actionstream<<"Server: Player with an empty name "
1955 <<"tried to connect from "<<addr_s<<std::endl;
1956 DenyAccess(peer_id, L"Empty name");
1960 if(string_allowed(playername, PLAYERNAME_ALLOWED_CHARS)==false)
1962 actionstream<<"Server: Player with an invalid name "
1963 <<"tried to connect from "<<addr_s<<std::endl;
1964 DenyAccess(peer_id, L"Name contains unallowed characters");
1968 if(!isSingleplayer() && strcasecmp(playername, "singleplayer") == 0)
1970 actionstream<<"Server: Player with the name \"singleplayer\" "
1971 <<"tried to connect from "<<addr_s<<std::endl;
1972 DenyAccess(peer_id, L"Name is not allowed");
1978 if(m_script->on_prejoinplayer(playername, addr_s, reason))
1980 actionstream<<"Server: Player with the name \""<<playername<<"\" "
1981 <<"tried to connect from "<<addr_s<<" "
1982 <<"but it was disallowed for the following reason: "
1983 <<reason<<std::endl;
1984 DenyAccess(peer_id, narrow_to_wide(reason.c_str()));
1989 infostream<<"Server: New connection: \""<<playername<<"\" from "
1990 <<addr_s<<" (peer_id="<<peer_id<<")"<<std::endl;
1993 char given_password[PASSWORD_SIZE];
1994 if(datasize < 2+1+PLAYERNAME_SIZE+PASSWORD_SIZE)
1996 // old version - assume blank password
1997 given_password[0] = 0;
2001 for(u32 i=0; i<PASSWORD_SIZE-1; i++)
2003 given_password[i] = data[23+i];
2005 given_password[PASSWORD_SIZE-1] = 0;
2008 if(!base64_is_valid(given_password)){
2009 actionstream<<"Server: "<<playername
2010 <<" supplied invalid password hash"<<std::endl;
2011 DenyAccess(peer_id, L"Invalid password hash");
2015 // Enforce user limit.
2016 // Don't enforce for users that have some admin right
2017 if(m_clients.size() >= g_settings->getU16("max_users") &&
2018 !checkPriv(playername, "server") &&
2019 !checkPriv(playername, "ban") &&
2020 !checkPriv(playername, "privs") &&
2021 !checkPriv(playername, "password") &&
2022 playername != g_settings->get("name"))
2024 actionstream<<"Server: "<<playername<<" tried to join, but there"
2025 <<" are already max_users="
2026 <<g_settings->getU16("max_users")<<" players."<<std::endl;
2027 DenyAccess(peer_id, L"Too many users.");
2031 std::string checkpwd; // Password hash to check against
2032 bool has_auth = m_script->getAuth(playername, &checkpwd, NULL);
2034 // If no authentication info exists for user, create it
2036 if(!isSingleplayer() &&
2037 g_settings->getBool("disallow_empty_password") &&
2038 std::string(given_password) == ""){
2039 actionstream<<"Server: "<<playername
2040 <<" supplied empty password"<<std::endl;
2041 DenyAccess(peer_id, L"Empty passwords are "
2042 L"disallowed. Set a password and try again.");
2045 std::wstring raw_default_password =
2046 narrow_to_wide(g_settings->get("default_password"));
2047 std::string initial_password =
2048 translatePassword(playername, raw_default_password);
2050 // If default_password is empty, allow any initial password
2051 if (raw_default_password.length() == 0)
2052 initial_password = given_password;
2054 m_script->createAuth(playername, initial_password);
2057 has_auth = m_script->getAuth(playername, &checkpwd, NULL);
2060 actionstream<<"Server: "<<playername<<" cannot be authenticated"
2061 <<" (auth handler does not work?)"<<std::endl;
2062 DenyAccess(peer_id, L"Not allowed to login");
2066 if(given_password != checkpwd){
2067 actionstream<<"Server: "<<playername<<" supplied wrong password"
2069 DenyAccess(peer_id, L"Wrong password");
2074 PlayerSAO *playersao = emergePlayer(playername, peer_id);
2076 // If failed, cancel
2077 if(playersao == NULL)
2079 RemotePlayer *player =
2080 static_cast<RemotePlayer*>(m_env->getPlayer(playername));
2081 if(player && player->peer_id != 0){
2082 errorstream<<"Server: "<<playername<<": Failed to emerge player"
2083 <<" (player allocated to an another client)"<<std::endl;
2084 DenyAccess(peer_id, L"Another client is connected with this "
2085 L"name. If your client closed unexpectedly, try again in "
2088 errorstream<<"Server: "<<playername<<": Failed to emerge player"
2090 DenyAccess(peer_id, L"Could not allocate player.");
2096 Answer with a TOCLIENT_INIT
2099 SharedBuffer<u8> reply(2+1+6+8+4);
2100 writeU16(&reply[0], TOCLIENT_INIT);
2101 writeU8(&reply[2], deployed);
2102 writeV3S16(&reply[2+1], floatToInt(playersao->getPlayer()->getPosition()+v3f(0,BS/2,0), BS));
2103 writeU64(&reply[2+1+6], m_env->getServerMap().getSeed());
2104 writeF1000(&reply[2+1+6+8], g_settings->getFloat("dedicated_server_step"));
2107 m_con.Send(peer_id, 0, reply, true);
2111 Send complete position information
2113 SendMovePlayer(peer_id);
2118 if(command == TOSERVER_INIT2)
2120 verbosestream<<"Server: Got TOSERVER_INIT2 from "
2121 <<peer_id<<std::endl;
2123 Player *player = m_env->getPlayer(peer_id);
2125 verbosestream<<"Server: TOSERVER_INIT2: "
2126 <<"Player not found; ignoring."<<std::endl;
2130 RemoteClient *client = getClient(peer_id);
2131 client->serialization_version =
2132 getClient(peer_id)->pending_serialization_version;
2135 Send some initialization data
2138 infostream<<"Server: Sending content to "
2139 <<getPlayerName(peer_id)<<std::endl;
2141 // Send player movement settings
2142 SendMovement(m_con, peer_id);
2144 // Send item definitions
2145 SendItemDef(m_con, peer_id, m_itemdef, client->net_proto_version);
2147 // Send node definitions
2148 SendNodeDef(m_con, peer_id, m_nodedef, client->net_proto_version);
2150 // Send media announcement
2151 sendMediaAnnouncement(peer_id);
2154 SendPlayerPrivileges(peer_id);
2156 // Send inventory formspec
2157 SendPlayerInventoryFormspec(peer_id);
2160 UpdateCrafting(peer_id);
2161 SendInventory(peer_id);
2164 if(g_settings->getBool("enable_damage"))
2165 SendPlayerHP(peer_id);
2168 SendPlayerBreath(peer_id);
2170 // Send detached inventories
2171 sendDetachedInventories(peer_id);
2173 // Show death screen if necessary
2175 SendDeathscreen(m_con, peer_id, false, v3f(0,0,0));
2179 u16 time = m_env->getTimeOfDay();
2180 float time_speed = g_settings->getFloat("time_speed");
2181 SendTimeOfDay(peer_id, time, time_speed);
2184 // Note things in chat if not in simple singleplayer mode
2185 if(!m_simple_singleplayer_mode)
2187 // Send information about server to player in chat
2188 SendChatMessage(peer_id, getStatusString());
2190 // Send information about joining in chat
2192 std::wstring name = L"unknown";
2193 Player *player = m_env->getPlayer(peer_id);
2195 name = narrow_to_wide(player->getName());
2197 std::wstring message;
2200 message += L" joined the game.";
2201 BroadcastChatMessage(message);
2205 // Warnings about protocol version can be issued here
2206 if(getClient(peer_id)->net_proto_version < LATEST_PROTOCOL_VERSION)
2208 SendChatMessage(peer_id, L"# Server: WARNING: YOUR CLIENT'S "
2209 L"VERSION MAY NOT BE FULLY COMPATIBLE WITH THIS SERVER!");
2216 std::ostringstream os(std::ios_base::binary);
2217 for(std::map<u16, RemoteClient*>::iterator
2218 i = m_clients.begin();
2219 i != m_clients.end(); ++i)
2221 RemoteClient *client = i->second;
2222 assert(client->peer_id == i->first);
2223 if(client->serialization_version == SER_FMT_VER_INVALID)
2226 Player *player = m_env->getPlayer(client->peer_id);
2229 // Get name of player
2230 os<<player->getName()<<" ";
2233 actionstream<<player->getName()<<" ["<<addr_s<<"] "<<"joins game. List of players: "
2234 <<os.str()<<std::endl;
2240 if(peer_ser_ver == SER_FMT_VER_INVALID)
2242 infostream<<"Server::ProcessData(): Cancelling: Peer"
2243 " serialization format invalid or not initialized."
2244 " Skipping incoming command="<<command<<std::endl;
2248 Player *player = m_env->getPlayer(peer_id);
2250 infostream<<"Server::ProcessData(): Cancelling: "
2251 "No player for peer_id="<<peer_id
2256 PlayerSAO *playersao = player->getPlayerSAO();
2257 if(playersao == NULL){
2258 infostream<<"Server::ProcessData(): Cancelling: "
2259 "No player object for peer_id="<<peer_id
2264 if(command == TOSERVER_PLAYERPOS)
2266 if(datasize < 2+12+12+4+4)
2270 v3s32 ps = readV3S32(&data[start+2]);
2271 v3s32 ss = readV3S32(&data[start+2+12]);
2272 f32 pitch = (f32)readS32(&data[2+12+12]) / 100.0;
2273 f32 yaw = (f32)readS32(&data[2+12+12+4]) / 100.0;
2275 if(datasize >= 2+12+12+4+4+4)
2276 keyPressed = (u32)readU32(&data[2+12+12+4+4]);
2277 v3f position((f32)ps.X/100., (f32)ps.Y/100., (f32)ps.Z/100.);
2278 v3f speed((f32)ss.X/100., (f32)ss.Y/100., (f32)ss.Z/100.);
2279 pitch = wrapDegrees(pitch);
2280 yaw = wrapDegrees(yaw);
2282 player->setPosition(position);
2283 player->setSpeed(speed);
2284 player->setPitch(pitch);
2285 player->setYaw(yaw);
2286 player->keyPressed=keyPressed;
2287 player->control.up = (bool)(keyPressed&1);
2288 player->control.down = (bool)(keyPressed&2);
2289 player->control.left = (bool)(keyPressed&4);
2290 player->control.right = (bool)(keyPressed&8);
2291 player->control.jump = (bool)(keyPressed&16);
2292 player->control.aux1 = (bool)(keyPressed&32);
2293 player->control.sneak = (bool)(keyPressed&64);
2294 player->control.LMB = (bool)(keyPressed&128);
2295 player->control.RMB = (bool)(keyPressed&256);
2297 bool cheated = playersao->checkMovementCheat();
2300 m_script->on_cheat(playersao, "moved_too_fast");
2303 /*infostream<<"Server::ProcessData(): Moved player "<<peer_id<<" to "
2304 <<"("<<position.X<<","<<position.Y<<","<<position.Z<<")"
2305 <<" pitch="<<pitch<<" yaw="<<yaw<<std::endl;*/
2307 else if(command == TOSERVER_GOTBLOCKS)
2320 u16 count = data[2];
2321 for(u16 i=0; i<count; i++)
2323 if((s16)datasize < 2+1+(i+1)*6)
2324 throw con::InvalidIncomingDataException
2325 ("GOTBLOCKS length is too short");
2326 v3s16 p = readV3S16(&data[2+1+i*6]);
2327 /*infostream<<"Server: GOTBLOCKS ("
2328 <<p.X<<","<<p.Y<<","<<p.Z<<")"<<std::endl;*/
2329 RemoteClient *client = getClient(peer_id);
2330 client->GotBlock(p);
2333 else if(command == TOSERVER_DELETEDBLOCKS)
2346 u16 count = data[2];
2347 for(u16 i=0; i<count; i++)
2349 if((s16)datasize < 2+1+(i+1)*6)
2350 throw con::InvalidIncomingDataException
2351 ("DELETEDBLOCKS length is too short");
2352 v3s16 p = readV3S16(&data[2+1+i*6]);
2353 /*infostream<<"Server: DELETEDBLOCKS ("
2354 <<p.X<<","<<p.Y<<","<<p.Z<<")"<<std::endl;*/
2355 RemoteClient *client = getClient(peer_id);
2356 client->SetBlockNotSent(p);
2359 else if(command == TOSERVER_CLICK_OBJECT)
2361 infostream<<"Server: CLICK_OBJECT not supported anymore"<<std::endl;
2364 else if(command == TOSERVER_CLICK_ACTIVEOBJECT)
2366 infostream<<"Server: CLICK_ACTIVEOBJECT not supported anymore"<<std::endl;
2369 else if(command == TOSERVER_GROUND_ACTION)
2371 infostream<<"Server: GROUND_ACTION not supported anymore"<<std::endl;
2375 else if(command == TOSERVER_RELEASE)
2377 infostream<<"Server: RELEASE not supported anymore"<<std::endl;
2380 else if(command == TOSERVER_SIGNTEXT)
2382 infostream<<"Server: SIGNTEXT not supported anymore"
2386 else if(command == TOSERVER_SIGNNODETEXT)
2388 infostream<<"Server: SIGNNODETEXT not supported anymore"
2392 else if(command == TOSERVER_INVENTORY_ACTION)
2394 // Strip command and create a stream
2395 std::string datastring((char*)&data[2], datasize-2);
2396 verbosestream<<"TOSERVER_INVENTORY_ACTION: data="<<datastring<<std::endl;
2397 std::istringstream is(datastring, std::ios_base::binary);
2399 InventoryAction *a = InventoryAction::deSerialize(is);
2402 infostream<<"TOSERVER_INVENTORY_ACTION: "
2403 <<"InventoryAction::deSerialize() returned NULL"
2408 // If something goes wrong, this player is to blame
2409 RollbackScopeActor rollback_scope(m_rollback,
2410 std::string("player:")+player->getName());
2413 Note: Always set inventory not sent, to repair cases
2414 where the client made a bad prediction.
2418 Handle restrictions and special cases of the move action
2420 if(a->getType() == IACTION_MOVE)
2422 IMoveAction *ma = (IMoveAction*)a;
2424 ma->from_inv.applyCurrentPlayer(player->getName());
2425 ma->to_inv.applyCurrentPlayer(player->getName());
2427 setInventoryModified(ma->from_inv);
2428 setInventoryModified(ma->to_inv);
2430 bool from_inv_is_current_player =
2431 (ma->from_inv.type == InventoryLocation::PLAYER) &&
2432 (ma->from_inv.name == player->getName());
2434 bool to_inv_is_current_player =
2435 (ma->to_inv.type == InventoryLocation::PLAYER) &&
2436 (ma->to_inv.name == player->getName());
2439 Disable moving items out of craftpreview
2441 if(ma->from_list == "craftpreview")
2443 infostream<<"Ignoring IMoveAction from "
2444 <<(ma->from_inv.dump())<<":"<<ma->from_list
2445 <<" to "<<(ma->to_inv.dump())<<":"<<ma->to_list
2446 <<" because src is "<<ma->from_list<<std::endl;
2452 Disable moving items into craftresult and craftpreview
2454 if(ma->to_list == "craftpreview" || ma->to_list == "craftresult")
2456 infostream<<"Ignoring IMoveAction from "
2457 <<(ma->from_inv.dump())<<":"<<ma->from_list
2458 <<" to "<<(ma->to_inv.dump())<<":"<<ma->to_list
2459 <<" because dst is "<<ma->to_list<<std::endl;
2464 // Disallow moving items in elsewhere than player's inventory
2465 // if not allowed to interact
2466 if(!checkPriv(player->getName(), "interact") &&
2467 (!from_inv_is_current_player ||
2468 !to_inv_is_current_player))
2470 infostream<<"Cannot move outside of player's inventory: "
2471 <<"No interact privilege"<<std::endl;
2477 Handle restrictions and special cases of the drop action
2479 else if(a->getType() == IACTION_DROP)
2481 IDropAction *da = (IDropAction*)a;
2483 da->from_inv.applyCurrentPlayer(player->getName());
2485 setInventoryModified(da->from_inv);
2488 Disable dropping items out of craftpreview
2490 if(da->from_list == "craftpreview")
2492 infostream<<"Ignoring IDropAction from "
2493 <<(da->from_inv.dump())<<":"<<da->from_list
2494 <<" because src is "<<da->from_list<<std::endl;
2499 // Disallow dropping items if not allowed to interact
2500 if(!checkPriv(player->getName(), "interact"))
2507 Handle restrictions and special cases of the craft action
2509 else if(a->getType() == IACTION_CRAFT)
2511 ICraftAction *ca = (ICraftAction*)a;
2513 ca->craft_inv.applyCurrentPlayer(player->getName());
2515 setInventoryModified(ca->craft_inv);
2517 //bool craft_inv_is_current_player =
2518 // (ca->craft_inv.type == InventoryLocation::PLAYER) &&
2519 // (ca->craft_inv.name == player->getName());
2521 // Disallow crafting if not allowed to interact
2522 if(!checkPriv(player->getName(), "interact"))
2524 infostream<<"Cannot craft: "
2525 <<"No interact privilege"<<std::endl;
2532 a->apply(this, playersao, this);
2536 else if(command == TOSERVER_CHAT_MESSAGE)
2544 std::string datastring((char*)&data[2], datasize-2);
2545 std::istringstream is(datastring, std::ios_base::binary);
2548 is.read((char*)buf, 2);
2549 u16 len = readU16(buf);
2551 std::wstring message;
2552 for(u16 i=0; i<len; i++)
2554 is.read((char*)buf, 2);
2555 message += (wchar_t)readU16(buf);
2558 // If something goes wrong, this player is to blame
2559 RollbackScopeActor rollback_scope(m_rollback,
2560 std::string("player:")+player->getName());
2562 // Get player name of this client
2563 std::wstring name = narrow_to_wide(player->getName());
2566 bool ate = m_script->on_chat_message(player->getName(),
2567 wide_to_narrow(message));
2568 // If script ate the message, don't proceed
2572 // Line to send to players
2574 // Whether to send to the player that sent the line
2575 bool send_to_sender = false;
2576 // Whether to send to other players
2577 bool send_to_others = false;
2579 // Commands are implemented in Lua, so only catch invalid
2580 // commands that were not "eaten" and send an error back
2581 if(message[0] == L'/')
2583 message = message.substr(1);
2584 send_to_sender = true;
2585 if(message.length() == 0)
2586 line += L"-!- Empty command";
2588 line += L"-!- Invalid command: " + str_split(message, L' ')[0];
2592 if(checkPriv(player->getName(), "shout")){
2597 send_to_others = true;
2599 line += L"-!- You don't have permission to shout.";
2600 send_to_sender = true;
2607 actionstream<<"CHAT: "<<wide_to_narrow(line)<<std::endl;
2610 Send the message to clients
2612 for(std::map<u16, RemoteClient*>::iterator
2613 i = m_clients.begin();
2614 i != m_clients.end(); ++i)
2616 // Get client and check that it is valid
2617 RemoteClient *client = i->second;
2618 assert(client->peer_id == i->first);
2619 if(client->serialization_version == SER_FMT_VER_INVALID)
2623 bool sender_selected = (peer_id == client->peer_id);
2624 if(sender_selected == true && send_to_sender == false)
2626 if(sender_selected == false && send_to_others == false)
2629 SendChatMessage(client->peer_id, line);
2633 else if(command == TOSERVER_DAMAGE)
2635 std::string datastring((char*)&data[2], datasize-2);
2636 std::istringstream is(datastring, std::ios_base::binary);
2637 u8 damage = readU8(is);
2639 if(g_settings->getBool("enable_damage"))
2641 actionstream<<player->getName()<<" damaged by "
2642 <<(int)damage<<" hp at "<<PP(player->getPosition()/BS)
2645 playersao->setHP(playersao->getHP() - damage);
2647 if(playersao->getHP() == 0 && playersao->m_hp_not_sent)
2650 if(playersao->m_hp_not_sent)
2651 SendPlayerHP(peer_id);
2654 else if(command == TOSERVER_BREATH)
2656 std::string datastring((char*)&data[2], datasize-2);
2657 std::istringstream is(datastring, std::ios_base::binary);
2658 u16 breath = readU16(is);
2659 playersao->setBreath(breath);
2661 else if(command == TOSERVER_PASSWORD)
2664 [0] u16 TOSERVER_PASSWORD
2665 [2] u8[28] old password
2666 [30] u8[28] new password
2669 if(datasize != 2+PASSWORD_SIZE*2)
2671 /*char password[PASSWORD_SIZE];
2672 for(u32 i=0; i<PASSWORD_SIZE-1; i++)
2673 password[i] = data[2+i];
2674 password[PASSWORD_SIZE-1] = 0;*/
2676 for(u32 i=0; i<PASSWORD_SIZE-1; i++)
2684 for(u32 i=0; i<PASSWORD_SIZE-1; i++)
2686 char c = data[2+PASSWORD_SIZE+i];
2692 if(!base64_is_valid(newpwd)){
2693 infostream<<"Server: "<<player->getName()<<" supplied invalid password hash"<<std::endl;
2694 // Wrong old password supplied!!
2695 SendChatMessage(peer_id, L"Invalid new password hash supplied. Password NOT changed.");
2699 infostream<<"Server: Client requests a password change from "
2700 <<"'"<<oldpwd<<"' to '"<<newpwd<<"'"<<std::endl;
2702 std::string playername = player->getName();
2704 std::string checkpwd;
2705 m_script->getAuth(playername, &checkpwd, NULL);
2707 if(oldpwd != checkpwd)
2709 infostream<<"Server: invalid old password"<<std::endl;
2710 // Wrong old password supplied!!
2711 SendChatMessage(peer_id, L"Invalid old password supplied. Password NOT changed.");
2715 bool success = m_script->setPassword(playername, newpwd);
2717 actionstream<<player->getName()<<" changes password"<<std::endl;
2718 SendChatMessage(peer_id, L"Password change successful.");
2720 actionstream<<player->getName()<<" tries to change password but "
2721 <<"it fails"<<std::endl;
2722 SendChatMessage(peer_id, L"Password change failed or inavailable.");
2725 else if(command == TOSERVER_PLAYERITEM)
2730 u16 item = readU16(&data[2]);
2731 playersao->setWieldIndex(item);
2733 else if(command == TOSERVER_RESPAWN)
2735 if(player->hp != 0 || !g_settings->getBool("enable_damage"))
2738 RespawnPlayer(peer_id);
2740 actionstream<<player->getName()<<" respawns at "
2741 <<PP(player->getPosition()/BS)<<std::endl;
2743 // ActiveObject is added to environment in AsyncRunStep after
2744 // the previous addition has been succesfully removed
2746 else if(command == TOSERVER_REQUEST_MEDIA) {
2747 std::string datastring((char*)&data[2], datasize-2);
2748 std::istringstream is(datastring, std::ios_base::binary);
2750 std::list<std::string> tosend;
2751 u16 numfiles = readU16(is);
2753 infostream<<"Sending "<<numfiles<<" files to "
2754 <<getPlayerName(peer_id)<<std::endl;
2755 verbosestream<<"TOSERVER_REQUEST_MEDIA: "<<std::endl;
2757 for(int i = 0; i < numfiles; i++) {
2758 std::string name = deSerializeString(is);
2759 tosend.push_back(name);
2760 verbosestream<<"TOSERVER_REQUEST_MEDIA: requested file "
2764 sendRequestedMedia(peer_id, tosend);
2766 // Now the client should know about everything
2767 // (definitions and files)
2768 getClient(peer_id)->definitions_sent = true;
2770 else if(command == TOSERVER_RECEIVED_MEDIA) {
2771 getClient(peer_id)->definitions_sent = true;
2773 else if(command == TOSERVER_INTERACT)
2775 std::string datastring((char*)&data[2], datasize-2);
2776 std::istringstream is(datastring, std::ios_base::binary);
2782 [5] u32 length of the next item
2783 [9] serialized PointedThing
2785 0: start digging (from undersurface) or use
2786 1: stop digging (all parameters ignored)
2787 2: digging completed
2788 3: place block or item (to abovesurface)
2791 u8 action = readU8(is);
2792 u16 item_i = readU16(is);
2793 std::istringstream tmp_is(deSerializeLongString(is), std::ios::binary);
2794 PointedThing pointed;
2795 pointed.deSerialize(tmp_is);
2797 verbosestream<<"TOSERVER_INTERACT: action="<<(int)action<<", item="
2798 <<item_i<<", pointed="<<pointed.dump()<<std::endl;
2802 verbosestream<<"TOSERVER_INTERACT: "<<player->getName()
2803 <<" tried to interact, but is dead!"<<std::endl;
2807 v3f player_pos = playersao->getLastGoodPosition();
2809 // Update wielded item
2810 playersao->setWieldIndex(item_i);
2812 // Get pointed to node (undefined if not POINTEDTYPE_NODE)
2813 v3s16 p_under = pointed.node_undersurface;
2814 v3s16 p_above = pointed.node_abovesurface;
2816 // Get pointed to object (NULL if not POINTEDTYPE_OBJECT)
2817 ServerActiveObject *pointed_object = NULL;
2818 if(pointed.type == POINTEDTHING_OBJECT)
2820 pointed_object = m_env->getActiveObject(pointed.object_id);
2821 if(pointed_object == NULL)
2823 verbosestream<<"TOSERVER_INTERACT: "
2824 "pointed object is NULL"<<std::endl;
2830 v3f pointed_pos_under = player_pos;
2831 v3f pointed_pos_above = player_pos;
2832 if(pointed.type == POINTEDTHING_NODE)
2834 pointed_pos_under = intToFloat(p_under, BS);
2835 pointed_pos_above = intToFloat(p_above, BS);
2837 else if(pointed.type == POINTEDTHING_OBJECT)
2839 pointed_pos_under = pointed_object->getBasePosition();
2840 pointed_pos_above = pointed_pos_under;
2844 Check that target is reasonably close
2845 (only when digging or placing things)
2847 if(action == 0 || action == 2 || action == 3)
2849 float d = player_pos.getDistanceFrom(pointed_pos_under);
2850 float max_d = BS * 14; // Just some large enough value
2852 actionstream<<"Player "<<player->getName()
2853 <<" tried to access "<<pointed.dump()
2855 <<"d="<<d<<", max_d="<<max_d
2856 <<". ignoring."<<std::endl;
2857 // Re-send block to revert change on client-side
2858 RemoteClient *client = getClient(peer_id);
2859 v3s16 blockpos = getNodeBlockPos(floatToInt(pointed_pos_under, BS));
2860 client->SetBlockNotSent(blockpos);
2862 m_script->on_cheat(playersao, "interacted_too_far");
2869 Make sure the player is allowed to do it
2871 if(!checkPriv(player->getName(), "interact"))
2873 actionstream<<player->getName()<<" attempted to interact with "
2874 <<pointed.dump()<<" without 'interact' privilege"
2876 // Re-send block to revert change on client-side
2877 RemoteClient *client = getClient(peer_id);
2878 // Digging completed -> under
2880 v3s16 blockpos = getNodeBlockPos(floatToInt(pointed_pos_under, BS));
2881 client->SetBlockNotSent(blockpos);
2883 // Placement -> above
2885 v3s16 blockpos = getNodeBlockPos(floatToInt(pointed_pos_above, BS));
2886 client->SetBlockNotSent(blockpos);
2892 If something goes wrong, this player is to blame
2894 RollbackScopeActor rollback_scope(m_rollback,
2895 std::string("player:")+player->getName());
2898 0: start digging or punch object
2902 if(pointed.type == POINTEDTHING_NODE)
2905 NOTE: This can be used in the future to check if
2906 somebody is cheating, by checking the timing.
2908 MapNode n(CONTENT_IGNORE);
2911 n = m_env->getMap().getNode(p_under);
2913 catch(InvalidPositionException &e)
2915 infostream<<"Server: Not punching: Node not found."
2916 <<" Adding block to emerge queue."
2918 m_emerge->enqueueBlockEmerge(peer_id, getNodeBlockPos(p_above), false);
2920 if(n.getContent() != CONTENT_IGNORE)
2921 m_script->node_on_punch(p_under, n, playersao);
2923 playersao->noCheatDigStart(p_under);
2925 else if(pointed.type == POINTEDTHING_OBJECT)
2927 // Skip if object has been removed
2928 if(pointed_object->m_removed)
2931 actionstream<<player->getName()<<" punches object "
2932 <<pointed.object_id<<": "
2933 <<pointed_object->getDescription()<<std::endl;
2935 ItemStack punchitem = playersao->getWieldedItem();
2936 ToolCapabilities toolcap =
2937 punchitem.getToolCapabilities(m_itemdef);
2938 v3f dir = (pointed_object->getBasePosition() -
2939 (player->getPosition() + player->getEyeOffset())
2941 float time_from_last_punch =
2942 playersao->resetTimeFromLastPunch();
2943 pointed_object->punch(dir, &toolcap, playersao,
2944 time_from_last_punch);
2952 else if(action == 1)
2957 2: Digging completed
2959 else if(action == 2)
2961 // Only digging of nodes
2962 if(pointed.type == POINTEDTHING_NODE)
2964 MapNode n(CONTENT_IGNORE);
2967 n = m_env->getMap().getNode(p_under);
2969 catch(InvalidPositionException &e)
2971 infostream<<"Server: Not finishing digging: Node not found."
2972 <<" Adding block to emerge queue."
2974 m_emerge->enqueueBlockEmerge(peer_id, getNodeBlockPos(p_above), false);
2977 /* Cheat prevention */
2978 bool is_valid_dig = true;
2979 if(!isSingleplayer() && !g_settings->getBool("disable_anticheat"))
2981 v3s16 nocheat_p = playersao->getNoCheatDigPos();
2982 float nocheat_t = playersao->getNoCheatDigTime();
2983 playersao->noCheatDigEnd();
2984 // If player didn't start digging this, ignore dig
2985 if(nocheat_p != p_under){
2986 infostream<<"Server: NoCheat: "<<player->getName()
2987 <<" started digging "
2988 <<PP(nocheat_p)<<" and completed digging "
2989 <<PP(p_under)<<"; not digging."<<std::endl;
2990 is_valid_dig = false;
2992 m_script->on_cheat(playersao, "finished_unknown_dig");
2994 // Get player's wielded item
2995 ItemStack playeritem;
2996 InventoryList *mlist = playersao->getInventory()->getList("main");
2998 playeritem = mlist->getItem(playersao->getWieldIndex());
2999 ToolCapabilities playeritem_toolcap =
3000 playeritem.getToolCapabilities(m_itemdef);
3001 // Get diggability and expected digging time
3002 DigParams params = getDigParams(m_nodedef->get(n).groups,
3003 &playeritem_toolcap);
3004 // If can't dig, try hand
3005 if(!params.diggable){
3006 const ItemDefinition &hand = m_itemdef->get("");
3007 const ToolCapabilities *tp = hand.tool_capabilities;
3009 params = getDigParams(m_nodedef->get(n).groups, tp);
3011 // If can't dig, ignore dig
3012 if(!params.diggable){
3013 infostream<<"Server: NoCheat: "<<player->getName()
3014 <<" completed digging "<<PP(p_under)
3015 <<", which is not diggable with tool. not digging."
3017 is_valid_dig = false;
3019 m_script->on_cheat(playersao, "dug_unbreakable");
3021 // Check digging time
3022 // If already invalidated, we don't have to
3024 // Well not our problem then
3026 // Clean and long dig
3027 else if(params.time > 2.0 && nocheat_t * 1.2 > params.time){
3028 // All is good, but grab time from pool; don't care if
3029 // it's actually available
3030 playersao->getDigPool().grab(params.time);
3032 // Short or laggy dig
3033 // Try getting the time from pool
3034 else if(playersao->getDigPool().grab(params.time)){
3039 infostream<<"Server: NoCheat: "<<player->getName()
3040 <<" completed digging "<<PP(p_under)
3041 <<"too fast; not digging."<<std::endl;
3042 is_valid_dig = false;
3044 m_script->on_cheat(playersao, "dug_too_fast");
3048 /* Actually dig node */
3050 if(is_valid_dig && n.getContent() != CONTENT_IGNORE)
3051 m_script->node_on_dig(p_under, n, playersao);
3053 // Send unusual result (that is, node not being removed)
3054 if(m_env->getMap().getNodeNoEx(p_under).getContent() != CONTENT_AIR)
3056 // Re-send block to revert change on client-side
3057 RemoteClient *client = getClient(peer_id);
3058 v3s16 blockpos = getNodeBlockPos(floatToInt(pointed_pos_under, BS));
3059 client->SetBlockNotSent(blockpos);
3065 3: place block or right-click object
3067 else if(action == 3)
3069 ItemStack item = playersao->getWieldedItem();
3071 // Reset build time counter
3072 if(pointed.type == POINTEDTHING_NODE &&
3073 item.getDefinition(m_itemdef).type == ITEM_NODE)
3074 getClient(peer_id)->m_time_from_building = 0.0;
3076 if(pointed.type == POINTEDTHING_OBJECT)
3078 // Right click object
3080 // Skip if object has been removed
3081 if(pointed_object->m_removed)
3084 actionstream<<player->getName()<<" right-clicks object "
3085 <<pointed.object_id<<": "
3086 <<pointed_object->getDescription()<<std::endl;
3089 pointed_object->rightClick(playersao);
3091 else if(m_script->item_OnPlace(
3092 item, playersao, pointed))
3094 // Placement was handled in lua
3096 // Apply returned ItemStack
3097 playersao->setWieldedItem(item);
3100 // If item has node placement prediction, always send the
3101 // blocks to make sure the client knows what exactly happened
3102 if(item.getDefinition(m_itemdef).node_placement_prediction != ""){
3103 RemoteClient *client = getClient(peer_id);
3104 v3s16 blockpos = getNodeBlockPos(floatToInt(pointed_pos_above, BS));
3105 client->SetBlockNotSent(blockpos);
3106 v3s16 blockpos2 = getNodeBlockPos(floatToInt(pointed_pos_under, BS));
3107 if(blockpos2 != blockpos){
3108 client->SetBlockNotSent(blockpos2);
3116 else if(action == 4)
3118 ItemStack item = playersao->getWieldedItem();
3120 actionstream<<player->getName()<<" uses "<<item.name
3121 <<", pointing at "<<pointed.dump()<<std::endl;
3123 if(m_script->item_OnUse(
3124 item, playersao, pointed))
3126 // Apply returned ItemStack
3127 playersao->setWieldedItem(item);
3134 Catch invalid actions
3138 infostream<<"WARNING: Server: Invalid action "
3139 <<action<<std::endl;
3142 else if(command == TOSERVER_REMOVED_SOUNDS)
3144 std::string datastring((char*)&data[2], datasize-2);
3145 std::istringstream is(datastring, std::ios_base::binary);
3147 int num = readU16(is);
3148 for(int k=0; k<num; k++){
3149 s32 id = readS32(is);
3150 std::map<s32, ServerPlayingSound>::iterator i =
3151 m_playing_sounds.find(id);
3152 if(i == m_playing_sounds.end())
3154 ServerPlayingSound &psound = i->second;
3155 psound.clients.erase(peer_id);
3156 if(psound.clients.size() == 0)
3157 m_playing_sounds.erase(i++);
3160 else if(command == TOSERVER_NODEMETA_FIELDS)
3162 std::string datastring((char*)&data[2], datasize-2);
3163 std::istringstream is(datastring, std::ios_base::binary);
3165 v3s16 p = readV3S16(is);
3166 std::string formname = deSerializeString(is);
3167 int num = readU16(is);
3168 std::map<std::string, std::string> fields;
3169 for(int k=0; k<num; k++){
3170 std::string fieldname = deSerializeString(is);
3171 std::string fieldvalue = deSerializeLongString(is);
3172 fields[fieldname] = fieldvalue;
3175 // If something goes wrong, this player is to blame
3176 RollbackScopeActor rollback_scope(m_rollback,
3177 std::string("player:")+player->getName());
3179 // Check the target node for rollback data; leave others unnoticed
3180 RollbackNode rn_old(&m_env->getMap(), p, this);
3182 m_script->node_on_receive_fields(p, formname, fields,playersao);
3184 // Report rollback data
3185 RollbackNode rn_new(&m_env->getMap(), p, this);
3186 if(rollback() && rn_new != rn_old){
3187 RollbackAction action;
3188 action.setSetNode(p, rn_old, rn_new);
3189 rollback()->reportAction(action);
3192 else if(command == TOSERVER_INVENTORY_FIELDS)
3194 std::string datastring((char*)&data[2], datasize-2);
3195 std::istringstream is(datastring, std::ios_base::binary);
3197 std::string formname = deSerializeString(is);
3198 int num = readU16(is);
3199 std::map<std::string, std::string> fields;
3200 for(int k=0; k<num; k++){
3201 std::string fieldname = deSerializeString(is);
3202 std::string fieldvalue = deSerializeLongString(is);
3203 fields[fieldname] = fieldvalue;
3206 m_script->on_playerReceiveFields(playersao, formname, fields);
3210 infostream<<"Server::ProcessData(): Ignoring "
3211 "unknown command "<<command<<std::endl;
3215 catch(SendFailedException &e)
3217 errorstream<<"Server::ProcessData(): SendFailedException: "
3223 void Server::setTimeOfDay(u32 time)
3225 m_env->setTimeOfDay(time);
3226 m_time_of_day_send_timer = 0;
3229 void Server::onMapEditEvent(MapEditEvent *event)
3231 //infostream<<"Server::onMapEditEvent()"<<std::endl;
3232 if(m_ignore_map_edit_events)
3234 if(m_ignore_map_edit_events_area.contains(event->getArea()))
3236 MapEditEvent *e = event->clone();
3237 m_unsent_map_edit_queue.push_back(e);
3240 Inventory* Server::getInventory(const InventoryLocation &loc)
3243 case InventoryLocation::UNDEFINED:
3246 case InventoryLocation::CURRENT_PLAYER:
3249 case InventoryLocation::PLAYER:
3251 Player *player = m_env->getPlayer(loc.name.c_str());
3254 PlayerSAO *playersao = player->getPlayerSAO();
3257 return playersao->getInventory();
3260 case InventoryLocation::NODEMETA:
3262 NodeMetadata *meta = m_env->getMap().getNodeMetadata(loc.p);
3265 return meta->getInventory();
3268 case InventoryLocation::DETACHED:
3270 if(m_detached_inventories.count(loc.name) == 0)
3272 return m_detached_inventories[loc.name];
3280 void Server::setInventoryModified(const InventoryLocation &loc)
3283 case InventoryLocation::UNDEFINED:
3286 case InventoryLocation::PLAYER:
3288 Player *player = m_env->getPlayer(loc.name.c_str());
3291 PlayerSAO *playersao = player->getPlayerSAO();
3294 playersao->m_inventory_not_sent = true;
3295 playersao->m_wielded_item_not_sent = true;
3298 case InventoryLocation::NODEMETA:
3300 v3s16 blockpos = getNodeBlockPos(loc.p);
3302 MapBlock *block = m_env->getMap().getBlockNoCreateNoEx(blockpos);
3304 block->raiseModified(MOD_STATE_WRITE_NEEDED);
3306 setBlockNotSent(blockpos);
3309 case InventoryLocation::DETACHED:
3311 sendDetachedInventoryToAll(loc.name);
3319 void Server::peerAdded(con::Peer *peer)
3321 DSTACK(__FUNCTION_NAME);
3322 verbosestream<<"Server::peerAdded(): peer->id="
3323 <<peer->id<<std::endl;
3326 c.type = PEER_ADDED;
3327 c.peer_id = peer->id;
3329 m_peer_change_queue.push_back(c);
3332 void Server::deletingPeer(con::Peer *peer, bool timeout)
3334 DSTACK(__FUNCTION_NAME);
3335 verbosestream<<"Server::deletingPeer(): peer->id="
3336 <<peer->id<<", timeout="<<timeout<<std::endl;
3339 c.type = PEER_REMOVED;
3340 c.peer_id = peer->id;
3341 c.timeout = timeout;
3342 m_peer_change_queue.push_back(c);
3349 void Server::SendMovement(con::Connection &con, u16 peer_id)
3351 DSTACK(__FUNCTION_NAME);
3352 std::ostringstream os(std::ios_base::binary);
3354 writeU16(os, TOCLIENT_MOVEMENT);
3355 writeF1000(os, g_settings->getFloat("movement_acceleration_default"));
3356 writeF1000(os, g_settings->getFloat("movement_acceleration_air"));
3357 writeF1000(os, g_settings->getFloat("movement_acceleration_fast"));
3358 writeF1000(os, g_settings->getFloat("movement_speed_walk"));
3359 writeF1000(os, g_settings->getFloat("movement_speed_crouch"));
3360 writeF1000(os, g_settings->getFloat("movement_speed_fast"));
3361 writeF1000(os, g_settings->getFloat("movement_speed_climb"));
3362 writeF1000(os, g_settings->getFloat("movement_speed_jump"));
3363 writeF1000(os, g_settings->getFloat("movement_liquid_fluidity"));
3364 writeF1000(os, g_settings->getFloat("movement_liquid_fluidity_smooth"));
3365 writeF1000(os, g_settings->getFloat("movement_liquid_sink"));
3366 writeF1000(os, g_settings->getFloat("movement_gravity"));
3369 std::string s = os.str();
3370 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3372 con.Send(peer_id, 0, data, true);
3375 void Server::SendHP(con::Connection &con, u16 peer_id, u8 hp)
3377 DSTACK(__FUNCTION_NAME);
3378 std::ostringstream os(std::ios_base::binary);
3380 writeU16(os, TOCLIENT_HP);
3384 std::string s = os.str();
3385 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3387 con.Send(peer_id, 0, data, true);
3390 void Server::SendBreath(con::Connection &con, u16 peer_id, u16 breath)
3392 DSTACK(__FUNCTION_NAME);
3393 std::ostringstream os(std::ios_base::binary);
3395 writeU16(os, TOCLIENT_BREATH);
3396 writeU16(os, breath);
3399 std::string s = os.str();
3400 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3402 con.Send(peer_id, 0, data, true);
3405 void Server::SendAccessDenied(con::Connection &con, u16 peer_id,
3406 const std::wstring &reason)
3408 DSTACK(__FUNCTION_NAME);
3409 std::ostringstream os(std::ios_base::binary);
3411 writeU16(os, TOCLIENT_ACCESS_DENIED);
3412 os<<serializeWideString(reason);
3415 std::string s = os.str();
3416 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3418 con.Send(peer_id, 0, data, true);
3421 void Server::SendDeathscreen(con::Connection &con, u16 peer_id,
3422 bool set_camera_point_target, v3f camera_point_target)
3424 DSTACK(__FUNCTION_NAME);
3425 std::ostringstream os(std::ios_base::binary);
3427 writeU16(os, TOCLIENT_DEATHSCREEN);
3428 writeU8(os, set_camera_point_target);
3429 writeV3F1000(os, camera_point_target);
3432 std::string s = os.str();
3433 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3435 con.Send(peer_id, 0, data, true);
3438 void Server::SendItemDef(con::Connection &con, u16 peer_id,
3439 IItemDefManager *itemdef, u16 protocol_version)
3441 DSTACK(__FUNCTION_NAME);
3442 std::ostringstream os(std::ios_base::binary);
3446 u32 length of the next item
3447 zlib-compressed serialized ItemDefManager
3449 writeU16(os, TOCLIENT_ITEMDEF);
3450 std::ostringstream tmp_os(std::ios::binary);
3451 itemdef->serialize(tmp_os, protocol_version);
3452 std::ostringstream tmp_os2(std::ios::binary);
3453 compressZlib(tmp_os.str(), tmp_os2);
3454 os<<serializeLongString(tmp_os2.str());
3457 std::string s = os.str();
3458 verbosestream<<"Server: Sending item definitions to id("<<peer_id
3459 <<"): size="<<s.size()<<std::endl;
3460 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3462 con.Send(peer_id, 0, data, true);
3465 void Server::SendNodeDef(con::Connection &con, u16 peer_id,
3466 INodeDefManager *nodedef, u16 protocol_version)
3468 DSTACK(__FUNCTION_NAME);
3469 std::ostringstream os(std::ios_base::binary);
3473 u32 length of the next item
3474 zlib-compressed serialized NodeDefManager
3476 writeU16(os, TOCLIENT_NODEDEF);
3477 std::ostringstream tmp_os(std::ios::binary);
3478 nodedef->serialize(tmp_os, protocol_version);
3479 std::ostringstream tmp_os2(std::ios::binary);
3480 compressZlib(tmp_os.str(), tmp_os2);
3481 os<<serializeLongString(tmp_os2.str());
3484 std::string s = os.str();
3485 verbosestream<<"Server: Sending node definitions to id("<<peer_id
3486 <<"): size="<<s.size()<<std::endl;
3487 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3489 con.Send(peer_id, 0, data, true);
3493 Non-static send methods
3496 void Server::SendInventory(u16 peer_id)
3498 DSTACK(__FUNCTION_NAME);
3500 PlayerSAO *playersao = getPlayerSAO(peer_id);
3503 playersao->m_inventory_not_sent = false;
3509 std::ostringstream os;
3510 playersao->getInventory()->serialize(os);
3512 std::string s = os.str();
3514 SharedBuffer<u8> data(s.size()+2);
3515 writeU16(&data[0], TOCLIENT_INVENTORY);
3516 memcpy(&data[2], s.c_str(), s.size());
3519 m_con.Send(peer_id, 0, data, true);
3522 void Server::SendChatMessage(u16 peer_id, const std::wstring &message)
3524 DSTACK(__FUNCTION_NAME);
3526 std::ostringstream os(std::ios_base::binary);
3530 writeU16(buf, TOCLIENT_CHAT_MESSAGE);
3531 os.write((char*)buf, 2);
3534 writeU16(buf, message.size());
3535 os.write((char*)buf, 2);
3538 for(u32 i=0; i<message.size(); i++)
3542 os.write((char*)buf, 2);
3546 std::string s = os.str();
3547 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3549 m_con.Send(peer_id, 0, data, true);
3552 void Server::SendShowFormspecMessage(u16 peer_id, const std::string formspec,
3553 const std::string formname)
3555 DSTACK(__FUNCTION_NAME);
3557 std::ostringstream os(std::ios_base::binary);
3561 writeU16(buf, TOCLIENT_SHOW_FORMSPEC);
3562 os.write((char*)buf, 2);
3563 os<<serializeLongString(formspec);
3564 os<<serializeString(formname);
3567 std::string s = os.str();
3568 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3570 m_con.Send(peer_id, 0, data, true);
3573 // Spawns a particle on peer with peer_id
3574 void Server::SendSpawnParticle(u16 peer_id, v3f pos, v3f velocity, v3f acceleration,
3575 float expirationtime, float size, bool collisiondetection,
3576 bool vertical, std::string texture)
3578 DSTACK(__FUNCTION_NAME);
3580 std::ostringstream os(std::ios_base::binary);
3581 writeU16(os, TOCLIENT_SPAWN_PARTICLE);
3582 writeV3F1000(os, pos);
3583 writeV3F1000(os, velocity);
3584 writeV3F1000(os, acceleration);
3585 writeF1000(os, expirationtime);
3586 writeF1000(os, size);
3587 writeU8(os, collisiondetection);
3588 os<<serializeLongString(texture);
3589 writeU8(os, vertical);
3592 std::string s = os.str();
3593 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3595 m_con.Send(peer_id, 0, data, true);
3598 // Spawns a particle on all peers
3599 void Server::SendSpawnParticleAll(v3f pos, v3f velocity, v3f acceleration,
3600 float expirationtime, float size, bool collisiondetection,
3601 bool vertical, std::string texture)
3603 for(std::map<u16, RemoteClient*>::iterator
3604 i = m_clients.begin();
3605 i != m_clients.end(); i++)
3607 // Get client and check that it is valid
3608 RemoteClient *client = i->second;
3609 assert(client->peer_id == i->first);
3610 if(client->serialization_version == SER_FMT_VER_INVALID)
3613 SendSpawnParticle(client->peer_id, pos, velocity, acceleration,
3614 expirationtime, size, collisiondetection, vertical, texture);
3618 // Adds a ParticleSpawner on peer with peer_id
3619 void Server::SendAddParticleSpawner(u16 peer_id, u16 amount, float spawntime, v3f minpos, v3f maxpos,
3620 v3f minvel, v3f maxvel, v3f minacc, v3f maxacc, float minexptime, float maxexptime,
3621 float minsize, float maxsize, bool collisiondetection, bool vertical, std::string texture, u32 id)
3623 DSTACK(__FUNCTION_NAME);
3625 std::ostringstream os(std::ios_base::binary);
3626 writeU16(os, TOCLIENT_ADD_PARTICLESPAWNER);
3628 writeU16(os, amount);
3629 writeF1000(os, spawntime);
3630 writeV3F1000(os, minpos);
3631 writeV3F1000(os, maxpos);
3632 writeV3F1000(os, minvel);
3633 writeV3F1000(os, maxvel);
3634 writeV3F1000(os, minacc);
3635 writeV3F1000(os, maxacc);
3636 writeF1000(os, minexptime);
3637 writeF1000(os, maxexptime);
3638 writeF1000(os, minsize);
3639 writeF1000(os, maxsize);
3640 writeU8(os, collisiondetection);
3641 os<<serializeLongString(texture);
3643 writeU8(os, vertical);
3646 std::string s = os.str();
3647 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3649 m_con.Send(peer_id, 0, data, true);
3652 // Adds a ParticleSpawner on all peers
3653 void Server::SendAddParticleSpawnerAll(u16 amount, float spawntime, v3f minpos, v3f maxpos,
3654 v3f minvel, v3f maxvel, v3f minacc, v3f maxacc, float minexptime, float maxexptime,
3655 float minsize, float maxsize, bool collisiondetection, bool vertical, std::string texture, u32 id)
3657 for(std::map<u16, RemoteClient*>::iterator
3658 i = m_clients.begin();
3659 i != m_clients.end(); i++)
3661 // Get client and check that it is valid
3662 RemoteClient *client = i->second;
3663 assert(client->peer_id == i->first);
3664 if(client->serialization_version == SER_FMT_VER_INVALID)
3667 SendAddParticleSpawner(client->peer_id, amount, spawntime,
3668 minpos, maxpos, minvel, maxvel, minacc, maxacc,
3669 minexptime, maxexptime, minsize, maxsize, collisiondetection, vertical, texture, id);
3673 void Server::SendDeleteParticleSpawner(u16 peer_id, u32 id)
3675 DSTACK(__FUNCTION_NAME);
3677 std::ostringstream os(std::ios_base::binary);
3678 writeU16(os, TOCLIENT_DELETE_PARTICLESPAWNER);
3683 std::string s = os.str();
3684 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3686 m_con.Send(peer_id, 0, data, true);
3689 void Server::SendDeleteParticleSpawnerAll(u32 id)
3691 for(std::map<u16, RemoteClient*>::iterator
3692 i = m_clients.begin();
3693 i != m_clients.end(); i++)
3695 // Get client and check that it is valid
3696 RemoteClient *client = i->second;
3697 assert(client->peer_id == i->first);
3698 if(client->serialization_version == SER_FMT_VER_INVALID)
3701 SendDeleteParticleSpawner(client->peer_id, id);
3705 void Server::SendHUDAdd(u16 peer_id, u32 id, HudElement *form)
3707 std::ostringstream os(std::ios_base::binary);
3710 writeU16(os, TOCLIENT_HUDADD);
3712 writeU8(os, (u8)form->type);
3713 writeV2F1000(os, form->pos);
3714 os << serializeString(form->name);
3715 writeV2F1000(os, form->scale);
3716 os << serializeString(form->text);
3717 writeU32(os, form->number);
3718 writeU32(os, form->item);
3719 writeU32(os, form->dir);
3720 writeV2F1000(os, form->align);
3721 writeV2F1000(os, form->offset);
3724 std::string s = os.str();
3725 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3727 m_con.Send(peer_id, 1, data, true);
3730 void Server::SendHUDRemove(u16 peer_id, u32 id)
3732 std::ostringstream os(std::ios_base::binary);
3735 writeU16(os, TOCLIENT_HUDRM);
3739 std::string s = os.str();
3740 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3743 m_con.Send(peer_id, 1, data, true);
3746 void Server::SendHUDChange(u16 peer_id, u32 id, HudElementStat stat, void *value)
3748 std::ostringstream os(std::ios_base::binary);
3751 writeU16(os, TOCLIENT_HUDCHANGE);
3753 writeU8(os, (u8)stat);
3756 case HUD_STAT_SCALE:
3757 case HUD_STAT_ALIGN:
3758 case HUD_STAT_OFFSET:
3759 writeV2F1000(os, *(v2f *)value);
3763 os << serializeString(*(std::string *)value);
3765 case HUD_STAT_NUMBER:
3769 writeU32(os, *(u32 *)value);
3774 std::string s = os.str();
3775 SharedBuffer<u8> data((u8 *)s.c_str(), s.size());
3777 m_con.Send(peer_id, 0, data, true);
3780 void Server::SendHUDSetFlags(u16 peer_id, u32 flags, u32 mask)
3782 std::ostringstream os(std::ios_base::binary);
3785 writeU16(os, TOCLIENT_HUD_SET_FLAGS);
3786 writeU32(os, flags);
3790 std::string s = os.str();
3791 SharedBuffer<u8> data((u8 *)s.c_str(), s.size());
3793 m_con.Send(peer_id, 0, data, true);
3796 void Server::SendHUDSetParam(u16 peer_id, u16 param, const std::string &value)
3798 std::ostringstream os(std::ios_base::binary);
3801 writeU16(os, TOCLIENT_HUD_SET_PARAM);
3802 writeU16(os, param);
3803 os<<serializeString(value);
3806 std::string s = os.str();
3807 SharedBuffer<u8> data((u8 *)s.c_str(), s.size());
3809 m_con.Send(peer_id, 0, data, true);
3812 void Server::BroadcastChatMessage(const std::wstring &message)
3814 for(std::map<u16, RemoteClient*>::iterator
3815 i = m_clients.begin();
3816 i != m_clients.end(); ++i)
3818 // Get client and check that it is valid
3819 RemoteClient *client = i->second;
3820 assert(client->peer_id == i->first);
3821 if(client->serialization_version == SER_FMT_VER_INVALID)
3824 SendChatMessage(client->peer_id, message);
3828 void Server::SendTimeOfDay(u16 peer_id, u16 time, f32 time_speed)
3830 DSTACK(__FUNCTION_NAME);
3833 SharedBuffer<u8> data(2+2+4);
3834 writeU16(&data[0], TOCLIENT_TIME_OF_DAY);
3835 writeU16(&data[2], time);
3836 writeF1000(&data[4], time_speed);
3839 m_con.Send(peer_id, 0, data, true);
3842 void Server::SendPlayerHP(u16 peer_id)
3844 DSTACK(__FUNCTION_NAME);
3845 PlayerSAO *playersao = getPlayerSAO(peer_id);
3847 playersao->m_hp_not_sent = false;
3848 SendHP(m_con, peer_id, playersao->getHP());
3850 // Send to other clients
3851 std::string str = gob_cmd_punched(playersao->readDamage(), playersao->getHP());
3852 ActiveObjectMessage aom(playersao->getId(), true, str);
3853 playersao->m_messages_out.push_back(aom);
3856 void Server::SendPlayerBreath(u16 peer_id)
3858 DSTACK(__FUNCTION_NAME);
3859 PlayerSAO *playersao = getPlayerSAO(peer_id);
3861 playersao->m_breath_not_sent = false;
3862 SendBreath(m_con, peer_id, playersao->getBreath());
3865 void Server::SendMovePlayer(u16 peer_id)
3867 DSTACK(__FUNCTION_NAME);
3868 Player *player = m_env->getPlayer(peer_id);
3871 std::ostringstream os(std::ios_base::binary);
3872 writeU16(os, TOCLIENT_MOVE_PLAYER);
3873 writeV3F1000(os, player->getPosition());
3874 writeF1000(os, player->getPitch());
3875 writeF1000(os, player->getYaw());
3878 v3f pos = player->getPosition();
3879 f32 pitch = player->getPitch();
3880 f32 yaw = player->getYaw();
3881 verbosestream<<"Server: Sending TOCLIENT_MOVE_PLAYER"
3882 <<" pos=("<<pos.X<<","<<pos.Y<<","<<pos.Z<<")"
3889 std::string s = os.str();
3890 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3892 m_con.Send(peer_id, 0, data, true);
3895 void Server::SendPlayerPrivileges(u16 peer_id)
3897 Player *player = m_env->getPlayer(peer_id);
3899 if(player->peer_id == PEER_ID_INEXISTENT)
3902 std::set<std::string> privs;
3903 m_script->getAuth(player->getName(), NULL, &privs);
3905 std::ostringstream os(std::ios_base::binary);
3906 writeU16(os, TOCLIENT_PRIVILEGES);
3907 writeU16(os, privs.size());
3908 for(std::set<std::string>::const_iterator i = privs.begin();
3909 i != privs.end(); i++){
3910 os<<serializeString(*i);
3914 std::string s = os.str();
3915 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3917 m_con.Send(peer_id, 0, data, true);
3920 void Server::SendPlayerInventoryFormspec(u16 peer_id)
3922 Player *player = m_env->getPlayer(peer_id);
3924 if(player->peer_id == PEER_ID_INEXISTENT)
3927 std::ostringstream os(std::ios_base::binary);
3928 writeU16(os, TOCLIENT_INVENTORY_FORMSPEC);
3929 os<<serializeLongString(player->inventory_formspec);
3932 std::string s = os.str();
3933 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3935 m_con.Send(peer_id, 0, data, true);
3938 s32 Server::playSound(const SimpleSoundSpec &spec,
3939 const ServerSoundParams ¶ms)
3941 // Find out initial position of sound
3942 bool pos_exists = false;
3943 v3f pos = params.getPos(m_env, &pos_exists);
3944 // If position is not found while it should be, cancel sound
3945 if(pos_exists != (params.type != ServerSoundParams::SSP_LOCAL))
3947 // Filter destination clients
3948 std::set<RemoteClient*> dst_clients;
3949 if(params.to_player != "")
3951 Player *player = m_env->getPlayer(params.to_player.c_str());
3953 infostream<<"Server::playSound: Player \""<<params.to_player
3954 <<"\" not found"<<std::endl;
3957 if(player->peer_id == PEER_ID_INEXISTENT){
3958 infostream<<"Server::playSound: Player \""<<params.to_player
3959 <<"\" not connected"<<std::endl;
3962 RemoteClient *client = getClient(player->peer_id);
3963 dst_clients.insert(client);
3967 for(std::map<u16, RemoteClient*>::iterator
3968 i = m_clients.begin(); i != m_clients.end(); ++i)
3970 RemoteClient *client = i->second;
3971 Player *player = m_env->getPlayer(client->peer_id);
3975 if(player->getPosition().getDistanceFrom(pos) >
3976 params.max_hear_distance)
3979 dst_clients.insert(client);
3982 if(dst_clients.size() == 0)
3985 s32 id = m_next_sound_id++;
3986 // The sound will exist as a reference in m_playing_sounds
3987 m_playing_sounds[id] = ServerPlayingSound();
3988 ServerPlayingSound &psound = m_playing_sounds[id];
3989 psound.params = params;
3990 for(std::set<RemoteClient*>::iterator i = dst_clients.begin();
3991 i != dst_clients.end(); i++)
3992 psound.clients.insert((*i)->peer_id);
3994 std::ostringstream os(std::ios_base::binary);
3995 writeU16(os, TOCLIENT_PLAY_SOUND);
3997 os<<serializeString(spec.name);
3998 writeF1000(os, spec.gain * params.gain);
3999 writeU8(os, params.type);
4000 writeV3F1000(os, pos);
4001 writeU16(os, params.object);
4002 writeU8(os, params.loop);
4004 std::string s = os.str();
4005 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
4007 for(std::set<RemoteClient*>::iterator i = dst_clients.begin();
4008 i != dst_clients.end(); i++){
4010 m_con.Send((*i)->peer_id, 0, data, true);
4014 void Server::stopSound(s32 handle)
4016 // Get sound reference
4017 std::map<s32, ServerPlayingSound>::iterator i =
4018 m_playing_sounds.find(handle);
4019 if(i == m_playing_sounds.end())
4021 ServerPlayingSound &psound = i->second;
4023 std::ostringstream os(std::ios_base::binary);
4024 writeU16(os, TOCLIENT_STOP_SOUND);
4025 writeS32(os, handle);
4027 std::string s = os.str();
4028 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
4030 for(std::set<u16>::iterator i = psound.clients.begin();
4031 i != psound.clients.end(); i++){
4033 m_con.Send(*i, 0, data, true);
4035 // Remove sound reference
4036 m_playing_sounds.erase(i);
4039 void Server::sendRemoveNode(v3s16 p, u16 ignore_id,
4040 std::list<u16> *far_players, float far_d_nodes)
4042 float maxd = far_d_nodes*BS;
4043 v3f p_f = intToFloat(p, BS);
4047 SharedBuffer<u8> reply(replysize);
4048 writeU16(&reply[0], TOCLIENT_REMOVENODE);
4049 writeS16(&reply[2], p.X);
4050 writeS16(&reply[4], p.Y);
4051 writeS16(&reply[6], p.Z);
4053 for(std::map<u16, RemoteClient*>::iterator
4054 i = m_clients.begin();
4055 i != m_clients.end(); ++i)
4057 // Get client and check that it is valid
4058 RemoteClient *client = i->second;
4059 assert(client->peer_id == i->first);
4060 if(client->serialization_version == SER_FMT_VER_INVALID)
4063 // Don't send if it's the same one
4064 if(client->peer_id == ignore_id)
4070 Player *player = m_env->getPlayer(client->peer_id);
4073 // If player is far away, only set modified blocks not sent
4074 v3f player_pos = player->getPosition();
4075 if(player_pos.getDistanceFrom(p_f) > maxd)
4077 far_players->push_back(client->peer_id);
4084 m_con.Send(client->peer_id, 0, reply, true);
4088 void Server::sendAddNode(v3s16 p, MapNode n, u16 ignore_id,
4089 std::list<u16> *far_players, float far_d_nodes,
4090 bool remove_metadata)
4092 float maxd = far_d_nodes*BS;
4093 v3f p_f = intToFloat(p, BS);
4095 for(std::map<u16, RemoteClient*>::iterator
4096 i = m_clients.begin();
4097 i != m_clients.end(); ++i)
4099 // Get client and check that it is valid
4100 RemoteClient *client = i->second;
4101 assert(client->peer_id == i->first);
4102 if(client->serialization_version == SER_FMT_VER_INVALID)
4105 // Don't send if it's the same one
4106 if(client->peer_id == ignore_id)
4112 Player *player = m_env->getPlayer(client->peer_id);
4115 // If player is far away, only set modified blocks not sent
4116 v3f player_pos = player->getPosition();
4117 if(player_pos.getDistanceFrom(p_f) > maxd)
4119 far_players->push_back(client->peer_id);
4126 u32 replysize = 9 + MapNode::serializedLength(client->serialization_version);
4127 SharedBuffer<u8> reply(replysize);
4128 writeU16(&reply[0], TOCLIENT_ADDNODE);
4129 writeS16(&reply[2], p.X);
4130 writeS16(&reply[4], p.Y);
4131 writeS16(&reply[6], p.Z);
4132 n.serialize(&reply[8], client->serialization_version);
4133 u32 index = 8 + MapNode::serializedLength(client->serialization_version);
4134 writeU8(&reply[index], remove_metadata ? 0 : 1);
4136 if (!remove_metadata) {
4137 if (client->net_proto_version <= 21) {
4138 // Old clients always clear metadata; fix it
4139 // by sending the full block again.
4140 client->SetBlockNotSent(p);
4145 m_con.Send(client->peer_id, 0, reply, true);
4149 void Server::setBlockNotSent(v3s16 p)
4151 for(std::map<u16, RemoteClient*>::iterator
4152 i = m_clients.begin();
4153 i != m_clients.end(); ++i)
4155 RemoteClient *client = i->second;
4156 client->SetBlockNotSent(p);
4160 void Server::SendBlockNoLock(u16 peer_id, MapBlock *block, u8 ver, u16 net_proto_version)
4162 DSTACK(__FUNCTION_NAME);
4164 v3s16 p = block->getPos();
4168 bool completely_air = true;
4169 for(s16 z0=0; z0<MAP_BLOCKSIZE; z0++)
4170 for(s16 x0=0; x0<MAP_BLOCKSIZE; x0++)
4171 for(s16 y0=0; y0<MAP_BLOCKSIZE; y0++)
4173 if(block->getNodeNoEx(v3s16(x0,y0,z0)).d != CONTENT_AIR)
4175 completely_air = false;
4176 x0 = y0 = z0 = MAP_BLOCKSIZE; // Break out
4181 infostream<<"Server: Sending block ("<<p.X<<","<<p.Y<<","<<p.Z<<"): ";
4183 infostream<<"[completely air] ";
4184 infostream<<std::endl;
4188 Create a packet with the block in the right format
4191 std::ostringstream os(std::ios_base::binary);
4192 block->serialize(os, ver, false);
4193 block->serializeNetworkSpecific(os, net_proto_version);
4194 std::string s = os.str();
4195 SharedBuffer<u8> blockdata((u8*)s.c_str(), s.size());
4197 u32 replysize = 8 + blockdata.getSize();
4198 SharedBuffer<u8> reply(replysize);
4199 writeU16(&reply[0], TOCLIENT_BLOCKDATA);
4200 writeS16(&reply[2], p.X);
4201 writeS16(&reply[4], p.Y);
4202 writeS16(&reply[6], p.Z);
4203 memcpy(&reply[8], *blockdata, blockdata.getSize());
4205 /*infostream<<"Server: Sending block ("<<p.X<<","<<p.Y<<","<<p.Z<<")"
4206 <<": \tpacket size: "<<replysize<<std::endl;*/
4211 m_con.Send(peer_id, 2, reply, true);
4214 void Server::SendBlocks(float dtime)
4216 DSTACK(__FUNCTION_NAME);
4218 JMutexAutoLock envlock(m_env_mutex);
4219 JMutexAutoLock conlock(m_con_mutex);
4221 ScopeProfiler sp(g_profiler, "Server: sel and send blocks to clients");
4223 std::vector<PrioritySortedBlockTransfer> queue;
4225 s32 total_sending = 0;
4228 ScopeProfiler sp(g_profiler, "Server: selecting blocks for sending");
4230 for(std::map<u16, RemoteClient*>::iterator
4231 i = m_clients.begin();
4232 i != m_clients.end(); ++i)
4234 RemoteClient *client = i->second;
4235 assert(client->peer_id == i->first);
4237 // If definitions and textures have not been sent, don't
4238 // send MapBlocks either
4239 if(!client->definitions_sent)
4242 total_sending += client->SendingCount();
4244 if(client->serialization_version == SER_FMT_VER_INVALID)
4247 client->GetNextBlocks(this, dtime, queue);
4252 // Lowest priority number comes first.
4253 // Lowest is most important.
4254 std::sort(queue.begin(), queue.end());
4256 for(u32 i=0; i<queue.size(); i++)
4258 //TODO: Calculate limit dynamically
4259 if(total_sending >= g_settings->getS32
4260 ("max_simultaneous_block_sends_server_total"))
4263 PrioritySortedBlockTransfer q = queue[i];
4265 MapBlock *block = NULL;
4268 block = m_env->getMap().getBlockNoCreate(q.pos);
4270 catch(InvalidPositionException &e)
4275 RemoteClient *client = getClientNoEx(q.peer_id);
4281 SendBlockNoLock(q.peer_id, block, client->serialization_version, client->net_proto_version);
4283 client->SentBlock(q.pos);
4289 void Server::fillMediaCache()
4291 DSTACK(__FUNCTION_NAME);
4293 infostream<<"Server: Calculating media file checksums"<<std::endl;
4295 // Collect all media file paths
4296 std::list<std::string> paths;
4297 for(std::vector<ModSpec>::iterator i = m_mods.begin();
4298 i != m_mods.end(); i++){
4299 const ModSpec &mod = *i;
4300 paths.push_back(mod.path + DIR_DELIM + "textures");
4301 paths.push_back(mod.path + DIR_DELIM + "sounds");
4302 paths.push_back(mod.path + DIR_DELIM + "media");
4303 paths.push_back(mod.path + DIR_DELIM + "models");
4305 paths.push_back(porting::path_user + DIR_DELIM + "textures" + DIR_DELIM + "server");
4307 // Collect media file information from paths into cache
4308 for(std::list<std::string>::iterator i = paths.begin();
4309 i != paths.end(); i++)
4311 std::string mediapath = *i;
4312 std::vector<fs::DirListNode> dirlist = fs::GetDirListing(mediapath);
4313 for(u32 j=0; j<dirlist.size(); j++){
4314 if(dirlist[j].dir) // Ignode dirs
4316 std::string filename = dirlist[j].name;
4317 // If name contains illegal characters, ignore the file
4318 if(!string_allowed(filename, TEXTURENAME_ALLOWED_CHARS)){
4319 infostream<<"Server: ignoring illegal file name: \""
4320 <<filename<<"\""<<std::endl;
4323 // If name is not in a supported format, ignore it
4324 const char *supported_ext[] = {
4325 ".png", ".jpg", ".bmp", ".tga",
4326 ".pcx", ".ppm", ".psd", ".wal", ".rgb",
4328 ".x", ".b3d", ".md2", ".obj",
4331 if(removeStringEnd(filename, supported_ext) == ""){
4332 infostream<<"Server: ignoring unsupported file extension: \""
4333 <<filename<<"\""<<std::endl;
4336 // Ok, attempt to load the file and add to cache
4337 std::string filepath = mediapath + DIR_DELIM + filename;
4339 std::ifstream fis(filepath.c_str(), std::ios_base::binary);
4340 if(fis.good() == false){
4341 errorstream<<"Server::fillMediaCache(): Could not open \""
4342 <<filename<<"\" for reading"<<std::endl;
4345 std::ostringstream tmp_os(std::ios_base::binary);
4349 fis.read(buf, 1024);
4350 std::streamsize len = fis.gcount();
4351 tmp_os.write(buf, len);
4360 errorstream<<"Server::fillMediaCache(): Failed to read \""
4361 <<filename<<"\""<<std::endl;
4364 if(tmp_os.str().length() == 0){
4365 errorstream<<"Server::fillMediaCache(): Empty file \""
4366 <<filepath<<"\""<<std::endl;
4371 sha1.addBytes(tmp_os.str().c_str(), tmp_os.str().length());
4373 unsigned char *digest = sha1.getDigest();
4374 std::string sha1_base64 = base64_encode(digest, 20);
4375 std::string sha1_hex = hex_encode((char*)digest, 20);
4379 this->m_media[filename] = MediaInfo(filepath, sha1_base64);
4380 verbosestream<<"Server: "<<sha1_hex<<" is "<<filename<<std::endl;
4385 struct SendableMediaAnnouncement
4388 std::string sha1_digest;
4390 SendableMediaAnnouncement(const std::string name_="",
4391 const std::string sha1_digest_=""):
4393 sha1_digest(sha1_digest_)
4397 void Server::sendMediaAnnouncement(u16 peer_id)
4399 DSTACK(__FUNCTION_NAME);
4401 verbosestream<<"Server: Announcing files to id("<<peer_id<<")"
4404 std::list<SendableMediaAnnouncement> file_announcements;
4406 for(std::map<std::string, MediaInfo>::iterator i = m_media.begin();
4407 i != m_media.end(); i++){
4409 file_announcements.push_back(
4410 SendableMediaAnnouncement(i->first, i->second.sha1_digest));
4414 std::ostringstream os(std::ios_base::binary);
4422 u16 length of sha1_digest
4427 writeU16(os, TOCLIENT_ANNOUNCE_MEDIA);
4428 writeU16(os, file_announcements.size());
4430 for(std::list<SendableMediaAnnouncement>::iterator
4431 j = file_announcements.begin();
4432 j != file_announcements.end(); ++j){
4433 os<<serializeString(j->name);
4434 os<<serializeString(j->sha1_digest);
4436 os<<serializeString(g_settings->get("remote_media"));
4439 std::string s = os.str();
4440 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
4443 m_con.Send(peer_id, 0, data, true);
4446 struct SendableMedia
4452 SendableMedia(const std::string &name_="", const std::string path_="",
4453 const std::string &data_=""):
4460 void Server::sendRequestedMedia(u16 peer_id,
4461 const std::list<std::string> &tosend)
4463 DSTACK(__FUNCTION_NAME);
4465 verbosestream<<"Server::sendRequestedMedia(): "
4466 <<"Sending files to client"<<std::endl;
4470 // Put 5kB in one bunch (this is not accurate)
4471 u32 bytes_per_bunch = 5000;
4473 std::vector< std::list<SendableMedia> > file_bunches;
4474 file_bunches.push_back(std::list<SendableMedia>());
4476 u32 file_size_bunch_total = 0;
4478 for(std::list<std::string>::const_iterator i = tosend.begin();
4479 i != tosend.end(); ++i)
4481 const std::string &name = *i;
4483 if(m_media.find(name) == m_media.end()){
4484 errorstream<<"Server::sendRequestedMedia(): Client asked for "
4485 <<"unknown file \""<<(name)<<"\""<<std::endl;
4489 //TODO get path + name
4490 std::string tpath = m_media[name].path;
4493 std::ifstream fis(tpath.c_str(), std::ios_base::binary);
4494 if(fis.good() == false){
4495 errorstream<<"Server::sendRequestedMedia(): Could not open \""
4496 <<tpath<<"\" for reading"<<std::endl;
4499 std::ostringstream tmp_os(std::ios_base::binary);
4503 fis.read(buf, 1024);
4504 std::streamsize len = fis.gcount();
4505 tmp_os.write(buf, len);
4506 file_size_bunch_total += len;
4515 errorstream<<"Server::sendRequestedMedia(): Failed to read \""
4516 <<name<<"\""<<std::endl;
4519 /*infostream<<"Server::sendRequestedMedia(): Loaded \""
4520 <<tname<<"\""<<std::endl;*/
4522 file_bunches[file_bunches.size()-1].push_back(
4523 SendableMedia(name, tpath, tmp_os.str()));
4525 // Start next bunch if got enough data
4526 if(file_size_bunch_total >= bytes_per_bunch){
4527 file_bunches.push_back(std::list<SendableMedia>());
4528 file_size_bunch_total = 0;
4533 /* Create and send packets */
4535 u32 num_bunches = file_bunches.size();
4536 for(u32 i=0; i<num_bunches; i++)
4538 std::ostringstream os(std::ios_base::binary);
4542 u16 total number of texture bunches
4543 u16 index of this bunch
4544 u32 number of files in this bunch
4553 writeU16(os, TOCLIENT_MEDIA);
4554 writeU16(os, num_bunches);
4556 writeU32(os, file_bunches[i].size());
4558 for(std::list<SendableMedia>::iterator
4559 j = file_bunches[i].begin();
4560 j != file_bunches[i].end(); ++j){
4561 os<<serializeString(j->name);
4562 os<<serializeLongString(j->data);
4566 std::string s = os.str();
4567 verbosestream<<"Server::sendRequestedMedia(): bunch "
4568 <<i<<"/"<<num_bunches
4569 <<" files="<<file_bunches[i].size()
4570 <<" size=" <<s.size()<<std::endl;
4571 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
4573 m_con.Send(peer_id, 2, data, true);
4577 void Server::sendDetachedInventory(const std::string &name, u16 peer_id)
4579 if(m_detached_inventories.count(name) == 0){
4580 errorstream<<__FUNCTION_NAME<<": \""<<name<<"\" not found"<<std::endl;
4583 Inventory *inv = m_detached_inventories[name];
4585 std::ostringstream os(std::ios_base::binary);
4586 writeU16(os, TOCLIENT_DETACHED_INVENTORY);
4587 os<<serializeString(name);
4591 std::string s = os.str();
4592 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
4594 m_con.Send(peer_id, 0, data, true);
4597 void Server::sendDetachedInventoryToAll(const std::string &name)
4599 DSTACK(__FUNCTION_NAME);
4601 for(std::map<u16, RemoteClient*>::iterator
4602 i = m_clients.begin();
4603 i != m_clients.end(); ++i){
4604 RemoteClient *client = i->second;
4605 sendDetachedInventory(name, client->peer_id);
4609 void Server::sendDetachedInventories(u16 peer_id)
4611 DSTACK(__FUNCTION_NAME);
4613 for(std::map<std::string, Inventory*>::iterator
4614 i = m_detached_inventories.begin();
4615 i != m_detached_inventories.end(); i++){
4616 const std::string &name = i->first;
4617 //Inventory *inv = i->second;
4618 sendDetachedInventory(name, peer_id);
4626 void Server::DiePlayer(u16 peer_id)
4628 DSTACK(__FUNCTION_NAME);
4630 PlayerSAO *playersao = getPlayerSAO(peer_id);
4633 infostream<<"Server::DiePlayer(): Player "
4634 <<playersao->getPlayer()->getName()
4635 <<" dies"<<std::endl;
4637 playersao->setHP(0);
4639 // Trigger scripted stuff
4640 m_script->on_dieplayer(playersao);
4642 SendPlayerHP(peer_id);
4643 SendDeathscreen(m_con, peer_id, false, v3f(0,0,0));
4646 void Server::RespawnPlayer(u16 peer_id)
4648 DSTACK(__FUNCTION_NAME);
4650 PlayerSAO *playersao = getPlayerSAO(peer_id);
4653 infostream<<"Server::RespawnPlayer(): Player "
4654 <<playersao->getPlayer()->getName()
4655 <<" respawns"<<std::endl;
4657 playersao->setHP(PLAYER_MAX_HP);
4659 bool repositioned = m_script->on_respawnplayer(playersao);
4661 v3f pos = findSpawnPos(m_env->getServerMap());
4662 playersao->setPos(pos);
4666 void Server::DenyAccess(u16 peer_id, const std::wstring &reason)
4668 DSTACK(__FUNCTION_NAME);
4670 SendAccessDenied(m_con, peer_id, reason);
4672 RemoteClient *client = getClientNoEx(peer_id);
4674 client->denied = true;
4676 // If there are way too many clients, get rid of denied new ones immediately
4677 if((int)m_clients.size() > 2 * g_settings->getU16("max_users")){
4678 verbosestream<<"Server: DenyAccess: Too many clients; getting rid of "
4679 <<"peer_id="<<peer_id<<" immediately"<<std::endl;
4680 // Delete peer to stop sending it data
4681 m_con.DeletePeer(peer_id);
4682 // Delete client also to stop block sends and other stuff
4683 DeleteClient(peer_id, CDR_DENY);
4687 void Server::DeleteClient(u16 peer_id, ClientDeletionReason reason)
4689 DSTACK(__FUNCTION_NAME);
4692 std::map<u16, RemoteClient*>::iterator n;
4693 n = m_clients.find(peer_id);
4694 // The client may not exist; clients are immediately removed if their
4695 // access is denied, and this event occurs later then.
4696 if(n == m_clients.end())
4700 Mark objects to be not known by the client
4702 RemoteClient *client = n->second;
4704 for(std::set<u16>::iterator
4705 i = client->m_known_objects.begin();
4706 i != client->m_known_objects.end(); ++i)
4710 ServerActiveObject* obj = m_env->getActiveObject(id);
4712 if(obj && obj->m_known_by_count > 0)
4713 obj->m_known_by_count--;
4717 Clear references to playing sounds
4719 for(std::map<s32, ServerPlayingSound>::iterator
4720 i = m_playing_sounds.begin();
4721 i != m_playing_sounds.end();)
4723 ServerPlayingSound &psound = i->second;
4724 psound.clients.erase(peer_id);
4725 if(psound.clients.size() == 0)
4726 m_playing_sounds.erase(i++);
4731 Player *player = m_env->getPlayer(peer_id);
4733 // Collect information about leaving in chat
4734 std::wstring message;
4736 if(player != NULL && reason != CDR_DENY)
4738 std::wstring name = narrow_to_wide(player->getName());
4741 message += L" left the game.";
4742 if(reason == CDR_TIMEOUT)
4743 message += L" (timed out)";
4747 /* Run scripts and remove from environment */
4751 PlayerSAO *playersao = player->getPlayerSAO();
4754 m_script->on_leaveplayer(playersao);
4756 playersao->disconnected();
4764 if(player != NULL && reason != CDR_DENY)
4766 std::ostringstream os(std::ios_base::binary);
4767 for(std::map<u16, RemoteClient*>::iterator
4768 i = m_clients.begin();
4769 i != m_clients.end(); ++i)
4771 RemoteClient *client = i->second;
4772 assert(client->peer_id == i->first);
4773 if(client->serialization_version == SER_FMT_VER_INVALID)
4776 Player *player = m_env->getPlayer(client->peer_id);
4779 // Get name of player
4780 os<<player->getName()<<" ";
4783 actionstream<<player->getName()<<" "
4784 <<(reason==CDR_TIMEOUT?"times out.":"leaves game.")
4785 <<" List of players: "<<os.str()<<std::endl;
4790 delete m_clients[peer_id];
4791 m_clients.erase(peer_id);
4793 // Send leave chat message to all remaining clients
4794 if(message.length() != 0)
4795 BroadcastChatMessage(message);
4798 void Server::UpdateCrafting(u16 peer_id)
4800 DSTACK(__FUNCTION_NAME);
4802 Player* player = m_env->getPlayer(peer_id);
4805 // Get a preview for crafting
4807 InventoryLocation loc;
4808 loc.setPlayer(player->getName());
4809 getCraftingResult(&player->inventory, preview, false, this);
4810 m_env->getScriptIface()->item_CraftPredict(preview, player->getPlayerSAO(), (&player->inventory)->getList("craft"), loc);
4812 // Put the new preview in
4813 InventoryList *plist = player->inventory.getList("craftpreview");
4815 assert(plist->getSize() >= 1);
4816 plist->changeItem(0, preview);
4819 RemoteClient* Server::getClient(u16 peer_id)
4821 RemoteClient *client = getClientNoEx(peer_id);
4823 throw ClientNotFoundException("Client not found");
4826 RemoteClient* Server::getClientNoEx(u16 peer_id)
4828 std::map<u16, RemoteClient*>::iterator n;
4829 n = m_clients.find(peer_id);
4830 // The client may not exist; clients are immediately removed if their
4831 // access is denied, and this event occurs later then.
4832 if(n == m_clients.end())
4837 std::string Server::getPlayerName(u16 peer_id)
4839 Player *player = m_env->getPlayer(peer_id);
4841 return "[id="+itos(peer_id)+"]";
4842 return player->getName();
4845 PlayerSAO* Server::getPlayerSAO(u16 peer_id)
4847 Player *player = m_env->getPlayer(peer_id);
4850 return player->getPlayerSAO();
4853 std::wstring Server::getStatusString()
4855 std::wostringstream os(std::ios_base::binary);
4858 os<<L"version="<<narrow_to_wide(minetest_version_simple);
4860 os<<L", uptime="<<m_uptime.get();
4862 os<<L", max_lag="<<m_env->getMaxLagEstimate();
4863 // Information about clients
4864 std::map<u16, RemoteClient*>::iterator i;
4867 for(i = m_clients.begin(), first = true;
4868 i != m_clients.end(); ++i)
4870 // Get client and check that it is valid
4871 RemoteClient *client = i->second;
4872 assert(client->peer_id == i->first);
4873 if(client->serialization_version == SER_FMT_VER_INVALID)
4876 Player *player = m_env->getPlayer(client->peer_id);
4877 // Get name of player
4878 std::wstring name = L"unknown";
4880 name = narrow_to_wide(player->getName());
4881 // Add name to information string
4889 if(((ServerMap*)(&m_env->getMap()))->isSavingEnabled() == false)
4890 os<<std::endl<<L"# Server: "<<" WARNING: Map saving is disabled.";
4891 if(g_settings->get("motd") != "")
4892 os<<std::endl<<L"# Server: "<<narrow_to_wide(g_settings->get("motd"));
4896 std::set<std::string> Server::getPlayerEffectivePrivs(const std::string &name)
4898 std::set<std::string> privs;
4899 m_script->getAuth(name, NULL, &privs);
4903 bool Server::checkPriv(const std::string &name, const std::string &priv)
4905 std::set<std::string> privs = getPlayerEffectivePrivs(name);
4906 return (privs.count(priv) != 0);
4909 void Server::reportPrivsModified(const std::string &name)
4912 for(std::map<u16, RemoteClient*>::iterator
4913 i = m_clients.begin();
4914 i != m_clients.end(); ++i){
4915 RemoteClient *client = i->second;
4916 Player *player = m_env->getPlayer(client->peer_id);
4917 reportPrivsModified(player->getName());
4920 Player *player = m_env->getPlayer(name.c_str());
4923 SendPlayerPrivileges(player->peer_id);
4924 PlayerSAO *sao = player->getPlayerSAO();
4927 sao->updatePrivileges(
4928 getPlayerEffectivePrivs(name),
4933 void Server::reportInventoryFormspecModified(const std::string &name)
4935 Player *player = m_env->getPlayer(name.c_str());
4938 SendPlayerInventoryFormspec(player->peer_id);
4941 void Server::setIpBanned(const std::string &ip, const std::string &name)
4943 m_banmanager->add(ip, name);
4946 void Server::unsetIpBanned(const std::string &ip_or_name)
4948 m_banmanager->remove(ip_or_name);
4951 std::string Server::getBanDescription(const std::string &ip_or_name)
4953 return m_banmanager->getBanDescription(ip_or_name);
4956 void Server::notifyPlayer(const char *name, const std::wstring msg, const bool prepend = true)
4958 Player *player = m_env->getPlayer(name);
4962 SendChatMessage(player->peer_id, std::wstring(L"Server -!- ")+msg);
4964 SendChatMessage(player->peer_id, msg);
4967 bool Server::showFormspec(const char *playername, const std::string &formspec, const std::string &formname)
4969 Player *player = m_env->getPlayer(playername);
4973 infostream<<"showFormspec: couldn't find player:"<<playername<<std::endl;
4977 SendShowFormspecMessage(player->peer_id, formspec, formname);
4981 u32 Server::hudAdd(Player *player, HudElement *form) {
4985 u32 id = player->getFreeHudID();
4986 if (id < player->hud.size())
4987 player->hud[id] = form;
4989 player->hud.push_back(form);
4991 SendHUDAdd(player->peer_id, id, form);
4995 bool Server::hudRemove(Player *player, u32 id) {
4996 if (!player || id >= player->hud.size() || !player->hud[id])
4999 delete player->hud[id];
5000 player->hud[id] = NULL;
5002 SendHUDRemove(player->peer_id, id);
5006 bool Server::hudChange(Player *player, u32 id, HudElementStat stat, void *data) {
5010 SendHUDChange(player->peer_id, id, stat, data);
5014 bool Server::hudSetFlags(Player *player, u32 flags, u32 mask) {
5018 SendHUDSetFlags(player->peer_id, flags, mask);
5022 bool Server::hudSetHotbarItemcount(Player *player, s32 hotbar_itemcount) {
5025 if (hotbar_itemcount <= 0 || hotbar_itemcount > HUD_HOTBAR_ITEMCOUNT_MAX)
5028 std::ostringstream os(std::ios::binary);
5029 writeS32(os, hotbar_itemcount);
5030 SendHUDSetParam(player->peer_id, HUD_PARAM_HOTBAR_ITEMCOUNT, os.str());
5034 void Server::hudSetHotbarImage(Player *player, std::string name) {
5038 SendHUDSetParam(player->peer_id, HUD_PARAM_HOTBAR_IMAGE, name);
5041 void Server::hudSetHotbarSelectedImage(Player *player, std::string name) {
5045 SendHUDSetParam(player->peer_id, HUD_PARAM_HOTBAR_SELECTED_IMAGE, name);
5048 void Server::notifyPlayers(const std::wstring msg)
5050 BroadcastChatMessage(msg);
5053 void Server::spawnParticle(const char *playername, v3f pos,
5054 v3f velocity, v3f acceleration,
5055 float expirationtime, float size, bool
5056 collisiondetection, bool vertical, std::string texture)
5058 Player *player = m_env->getPlayer(playername);
5061 SendSpawnParticle(player->peer_id, pos, velocity, acceleration,
5062 expirationtime, size, collisiondetection, vertical, texture);
5065 void Server::spawnParticleAll(v3f pos, v3f velocity, v3f acceleration,
5066 float expirationtime, float size,
5067 bool collisiondetection, bool vertical, std::string texture)
5069 SendSpawnParticleAll(pos, velocity, acceleration,
5070 expirationtime, size, collisiondetection, vertical, texture);
5073 u32 Server::addParticleSpawner(const char *playername,
5074 u16 amount, float spawntime,
5075 v3f minpos, v3f maxpos,
5076 v3f minvel, v3f maxvel,
5077 v3f minacc, v3f maxacc,
5078 float minexptime, float maxexptime,
5079 float minsize, float maxsize,
5080 bool collisiondetection, bool vertical, std::string texture)
5082 Player *player = m_env->getPlayer(playername);
5087 for(;;) // look for unused particlespawner id
5090 if (std::find(m_particlespawner_ids.begin(),
5091 m_particlespawner_ids.end(), id)
5092 == m_particlespawner_ids.end())
5094 m_particlespawner_ids.push_back(id);
5099 SendAddParticleSpawner(player->peer_id, amount, spawntime,
5100 minpos, maxpos, minvel, maxvel, minacc, maxacc,
5101 minexptime, maxexptime, minsize, maxsize,
5102 collisiondetection, vertical, texture, id);
5107 u32 Server::addParticleSpawnerAll(u16 amount, float spawntime,
5108 v3f minpos, v3f maxpos,
5109 v3f minvel, v3f maxvel,
5110 v3f minacc, v3f maxacc,
5111 float minexptime, float maxexptime,
5112 float minsize, float maxsize,
5113 bool collisiondetection, bool vertical, std::string texture)
5116 for(;;) // look for unused particlespawner id
5119 if (std::find(m_particlespawner_ids.begin(),
5120 m_particlespawner_ids.end(), id)
5121 == m_particlespawner_ids.end())
5123 m_particlespawner_ids.push_back(id);
5128 SendAddParticleSpawnerAll(amount, spawntime,
5129 minpos, maxpos, minvel, maxvel, minacc, maxacc,
5130 minexptime, maxexptime, minsize, maxsize,
5131 collisiondetection, vertical, texture, id);
5136 void Server::deleteParticleSpawner(const char *playername, u32 id)
5138 Player *player = m_env->getPlayer(playername);
5142 m_particlespawner_ids.erase(
5143 std::remove(m_particlespawner_ids.begin(),
5144 m_particlespawner_ids.end(), id),
5145 m_particlespawner_ids.end());
5146 SendDeleteParticleSpawner(player->peer_id, id);
5149 void Server::deleteParticleSpawnerAll(u32 id)
5151 m_particlespawner_ids.erase(
5152 std::remove(m_particlespawner_ids.begin(),
5153 m_particlespawner_ids.end(), id),
5154 m_particlespawner_ids.end());
5155 SendDeleteParticleSpawnerAll(id);
5158 Inventory* Server::createDetachedInventory(const std::string &name)
5160 if(m_detached_inventories.count(name) > 0){
5161 infostream<<"Server clearing detached inventory \""<<name<<"\""<<std::endl;
5162 delete m_detached_inventories[name];
5164 infostream<<"Server creating detached inventory \""<<name<<"\""<<std::endl;
5166 Inventory *inv = new Inventory(m_itemdef);
5168 m_detached_inventories[name] = inv;
5169 sendDetachedInventoryToAll(name);
5176 BoolScopeSet(bool *dst, bool val):
5179 m_orig_state = *m_dst;
5184 *m_dst = m_orig_state;
5191 // actions: time-reversed list
5192 // Return value: success/failure
5193 bool Server::rollbackRevertActions(const std::list<RollbackAction> &actions,
5194 std::list<std::string> *log)
5196 infostream<<"Server::rollbackRevertActions(len="<<actions.size()<<")"<<std::endl;
5197 ServerMap *map = (ServerMap*)(&m_env->getMap());
5198 // Disable rollback report sink while reverting
5199 BoolScopeSet rollback_scope_disable(&m_rollback_sink_enabled, false);
5201 // Fail if no actions to handle
5202 if(actions.empty()){
5203 log->push_back("Nothing to do.");
5210 for(std::list<RollbackAction>::const_iterator
5211 i = actions.begin();
5212 i != actions.end(); i++)
5214 const RollbackAction &action = *i;
5216 bool success = action.applyRevert(map, this, this);
5219 std::ostringstream os;
5220 os<<"Revert of step ("<<num_tried<<") "<<action.toString()<<" failed";
5221 infostream<<"Map::rollbackRevertActions(): "<<os.str()<<std::endl;
5223 log->push_back(os.str());
5225 std::ostringstream os;
5226 os<<"Successfully reverted step ("<<num_tried<<") "<<action.toString();
5227 infostream<<"Map::rollbackRevertActions(): "<<os.str()<<std::endl;
5229 log->push_back(os.str());
5233 infostream<<"Map::rollbackRevertActions(): "<<num_failed<<"/"<<num_tried
5234 <<" failed"<<std::endl;
5236 // Call it done if less than half failed
5237 return num_failed <= num_tried/2;
5240 // IGameDef interface
5242 IItemDefManager* Server::getItemDefManager()
5246 INodeDefManager* Server::getNodeDefManager()
5250 ICraftDefManager* Server::getCraftDefManager()
5254 ITextureSource* Server::getTextureSource()
5258 IShaderSource* Server::getShaderSource()
5262 u16 Server::allocateUnknownNodeId(const std::string &name)
5264 return m_nodedef->allocateDummy(name);
5266 ISoundManager* Server::getSoundManager()
5268 return &dummySoundManager;
5270 MtEventManager* Server::getEventManager()
5274 IRollbackReportSink* Server::getRollbackReportSink()
5276 if(!m_enable_rollback_recording)
5278 if(!m_rollback_sink_enabled)
5283 IWritableItemDefManager* Server::getWritableItemDefManager()
5287 IWritableNodeDefManager* Server::getWritableNodeDefManager()
5291 IWritableCraftDefManager* Server::getWritableCraftDefManager()
5296 const ModSpec* Server::getModSpec(const std::string &modname)
5298 for(std::vector<ModSpec>::iterator i = m_mods.begin();
5299 i != m_mods.end(); i++){
5300 const ModSpec &mod = *i;
5301 if(mod.name == modname)
5306 void Server::getModNames(std::list<std::string> &modlist)
5308 for(std::vector<ModSpec>::iterator i = m_mods.begin(); i != m_mods.end(); i++)
5310 modlist.push_back(i->name);
5313 std::string Server::getBuiltinLuaPath()
5315 return porting::path_share + DIR_DELIM + "builtin";
5318 v3f findSpawnPos(ServerMap &map)
5320 //return v3f(50,50,50)*BS;
5325 nodepos = v2s16(0,0);
5330 s16 water_level = map.m_mgparams->water_level;
5332 // Try to find a good place a few times
5333 for(s32 i=0; i<1000; i++)
5336 // We're going to try to throw the player to this position
5337 v2s16 nodepos2d = v2s16(
5338 -range + (myrand() % (range * 2)),
5339 -range + (myrand() % (range * 2)));
5341 // Get ground height at point
5342 s16 groundheight = map.findGroundLevel(nodepos2d);
5343 if (groundheight <= water_level) // Don't go underwater
5345 if (groundheight > water_level + 6) // Don't go to high places
5348 nodepos = v3s16(nodepos2d.X, groundheight, nodepos2d.Y);
5349 bool is_good = false;
5351 for (s32 i = 0; i < 10; i++) {
5352 v3s16 blockpos = getNodeBlockPos(nodepos);
5353 map.emergeBlock(blockpos, true);
5354 content_t c = map.getNodeNoEx(nodepos).getContent();
5355 if (c == CONTENT_AIR || c == CONTENT_IGNORE) {
5357 if (air_count >= 2){
5365 // Found a good place
5366 //infostream<<"Searched through "<<i<<" places."<<std::endl;
5372 return intToFloat(nodepos, BS);
5375 PlayerSAO* Server::emergePlayer(const char *name, u16 peer_id)
5377 RemotePlayer *player = NULL;
5378 bool newplayer = false;
5381 Try to get an existing player
5383 player = static_cast<RemotePlayer*>(m_env->getPlayer(name));
5385 // If player is already connected, cancel
5386 if(player != NULL && player->peer_id != 0)
5388 infostream<<"emergePlayer(): Player already connected"<<std::endl;
5393 If player with the wanted peer_id already exists, cancel.
5395 if(m_env->getPlayer(peer_id) != NULL)
5397 infostream<<"emergePlayer(): Player with wrong name but same"
5398 " peer_id already exists"<<std::endl;
5403 Create a new player if it doesn't exist yet
5408 player = new RemotePlayer(this);
5409 player->updateName(name);
5411 /* Set player position */
5412 infostream<<"Server: Finding spawn place for player \""
5413 <<name<<"\""<<std::endl;
5414 v3f pos = findSpawnPos(m_env->getServerMap());
5415 player->setPosition(pos);
5417 /* Add player to environment */
5418 m_env->addPlayer(player);
5422 Create a new player active object
5424 PlayerSAO *playersao = new PlayerSAO(m_env, player, peer_id,
5425 getPlayerEffectivePrivs(player->getName()),
5428 /* Clean up old HUD elements from previous sessions */
5429 player->hud.clear();
5431 /* Add object to environment */
5432 m_env->addActiveObject(playersao);
5436 m_script->on_newplayer(playersao);
5438 m_script->on_joinplayer(playersao);
5443 void Server::handlePeerChange(PeerChange &c)
5445 JMutexAutoLock envlock(m_env_mutex);
5446 JMutexAutoLock conlock(m_con_mutex);
5448 if(c.type == PEER_ADDED)
5455 std::map<u16, RemoteClient*>::iterator n;
5456 n = m_clients.find(c.peer_id);
5457 // The client shouldn't already exist
5458 assert(n == m_clients.end());
5461 RemoteClient *client = new RemoteClient();
5462 client->peer_id = c.peer_id;
5463 m_clients[client->peer_id] = client;
5466 else if(c.type == PEER_REMOVED)
5472 DeleteClient(c.peer_id, c.timeout?CDR_TIMEOUT:CDR_LEAVE);
5481 void Server::handlePeerChanges()
5483 while(m_peer_change_queue.size() > 0)
5485 PeerChange c = m_peer_change_queue.pop_front();
5487 verbosestream<<"Server: Handling peer change: "
5488 <<"id="<<c.peer_id<<", timeout="<<c.timeout
5491 handlePeerChange(c);
5495 void dedicated_server_loop(Server &server, bool &kill)
5497 DSTACK(__FUNCTION_NAME);
5499 verbosestream<<"dedicated_server_loop()"<<std::endl;
5501 IntervalLimiter m_profiler_interval;
5505 float steplen = g_settings->getFloat("dedicated_server_step");
5506 // This is kind of a hack but can be done like this
5507 // because server.step() is very light
5509 ScopeProfiler sp(g_profiler, "dedicated server sleep");
5510 sleep_ms((int)(steplen*1000.0));
5512 server.step(steplen);
5514 if(server.getShutdownRequested() || kill)
5516 infostream<<"Dedicated server quitting"<<std::endl;
5518 if(g_settings->getBool("server_announce") == true)
5519 ServerList::sendAnnounce("delete");
5527 float profiler_print_interval =
5528 g_settings->getFloat("profiler_print_interval");
5529 if(profiler_print_interval != 0)
5531 if(m_profiler_interval.step(steplen, profiler_print_interval))
5533 infostream<<"Profiler:"<<std::endl;
5534 g_profiler->print(infostream);
5535 g_profiler->clear();