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 "jmutexautolock.h"
28 #include "constants.h"
33 #include "serverobject.h"
38 #include "scriptapi.h"
45 #include "content_mapnode.h"
46 #include "content_nodemeta.h"
47 #include "content_abm.h"
48 #include "content_sao.h"
53 #include "sound.h" // dummySoundManager
54 #include "event_manager.h"
56 #include "serverlist.h"
57 #include "util/string.h"
58 #include "util/pointedthing.h"
59 #include "util/mathconstants.h"
61 #include "util/serialize.h"
62 #include "defaultsettings.h"
64 void * ServerThread::Thread()
68 log_register_thread("ServerThread");
70 DSTACK(__FUNCTION_NAME);
72 BEGIN_DEBUG_EXCEPTION_HANDLER
77 //TimeTaker timer("AsyncRunStep() + Receive()");
80 //TimeTaker timer("AsyncRunStep()");
81 m_server->AsyncRunStep();
84 //infostream<<"Running m_server->Receive()"<<std::endl;
87 catch(con::NoIncomingDataException &e)
90 catch(con::PeerNotFoundException &e)
92 infostream<<"Server: PeerNotFoundException"<<std::endl;
94 catch(con::ConnectionBindFailed &e)
96 m_server->setAsyncFatalError(e.what());
100 m_server->setAsyncFatalError(e.what());
104 END_DEBUG_EXCEPTION_HANDLER(errorstream)
109 v3f ServerSoundParams::getPos(ServerEnvironment *env, bool *pos_exists) const
111 if(pos_exists) *pos_exists = false;
116 if(pos_exists) *pos_exists = true;
121 ServerActiveObject *sao = env->getActiveObject(object);
124 if(pos_exists) *pos_exists = true;
125 return sao->getBasePosition(); }
130 void RemoteClient::GetNextBlocks(Server *server, float dtime,
131 std::vector<PrioritySortedBlockTransfer> &dest)
133 DSTACK(__FUNCTION_NAME);
136 TimeTaker timer("RemoteClient::GetNextBlocks", &timer_result);*/
139 m_nothing_to_send_pause_timer -= dtime;
140 m_nearest_unsent_reset_timer += dtime;
142 if(m_nothing_to_send_pause_timer >= 0)
145 Player *player = server->m_env->getPlayer(peer_id);
146 // This can happen sometimes; clients and players are not in perfect sync.
150 // Won't send anything if already sending
151 if(m_blocks_sending.size() >= g_settings->getU16
152 ("max_simultaneous_block_sends_per_client"))
154 //infostream<<"Not sending any blocks, Queue full."<<std::endl;
158 //TimeTaker timer("RemoteClient::GetNextBlocks");
160 v3f playerpos = player->getPosition();
161 v3f playerspeed = player->getSpeed();
162 v3f playerspeeddir(0,0,0);
163 if(playerspeed.getLength() > 1.0*BS)
164 playerspeeddir = playerspeed / playerspeed.getLength();
165 // Predict to next block
166 v3f playerpos_predicted = playerpos + playerspeeddir*MAP_BLOCKSIZE*BS;
168 v3s16 center_nodepos = floatToInt(playerpos_predicted, BS);
170 v3s16 center = getNodeBlockPos(center_nodepos);
172 // Camera position and direction
173 v3f camera_pos = player->getEyePosition();
174 v3f camera_dir = v3f(0,0,1);
175 camera_dir.rotateYZBy(player->getPitch());
176 camera_dir.rotateXZBy(player->getYaw());
178 /*infostream<<"camera_dir=("<<camera_dir.X<<","<<camera_dir.Y<<","
179 <<camera_dir.Z<<")"<<std::endl;*/
182 Get the starting value of the block finder radius.
185 if(m_last_center != center)
187 m_nearest_unsent_d = 0;
188 m_last_center = center;
191 /*infostream<<"m_nearest_unsent_reset_timer="
192 <<m_nearest_unsent_reset_timer<<std::endl;*/
194 // Reset periodically to workaround for some bugs or stuff
195 if(m_nearest_unsent_reset_timer > 20.0)
197 m_nearest_unsent_reset_timer = 0;
198 m_nearest_unsent_d = 0;
199 //infostream<<"Resetting m_nearest_unsent_d for "
200 // <<server->getPlayerName(peer_id)<<std::endl;
203 //s16 last_nearest_unsent_d = m_nearest_unsent_d;
204 s16 d_start = m_nearest_unsent_d;
206 //infostream<<"d_start="<<d_start<<std::endl;
208 u16 max_simul_sends_setting = g_settings->getU16
209 ("max_simultaneous_block_sends_per_client");
210 u16 max_simul_sends_usually = max_simul_sends_setting;
213 Check the time from last addNode/removeNode.
215 Decrease send rate if player is building stuff.
217 m_time_from_building += dtime;
218 if(m_time_from_building < g_settings->getFloat(
219 "full_block_send_enable_min_time_from_building"))
221 max_simul_sends_usually
222 = LIMITED_MAX_SIMULTANEOUS_BLOCK_SENDS;
226 Number of blocks sending + number of blocks selected for sending
228 u32 num_blocks_selected = m_blocks_sending.size();
231 next time d will be continued from the d from which the nearest
232 unsent block was found this time.
234 This is because not necessarily any of the blocks found this
235 time are actually sent.
237 s32 new_nearest_unsent_d = -1;
239 s16 d_max = g_settings->getS16("max_block_send_distance");
240 s16 d_max_gen = g_settings->getS16("max_block_generate_distance");
242 // Don't loop very much at a time
243 s16 max_d_increment_at_time = 2;
244 if(d_max > d_start + max_d_increment_at_time)
245 d_max = d_start + max_d_increment_at_time;
246 /*if(d_max_gen > d_start+2)
247 d_max_gen = d_start+2;*/
249 //infostream<<"Starting from "<<d_start<<std::endl;
251 s32 nearest_emerged_d = -1;
252 s32 nearest_emergefull_d = -1;
253 s32 nearest_sent_d = -1;
254 bool queue_is_full = false;
257 for(d = d_start; d <= d_max; d++)
259 /*errorstream<<"checking d="<<d<<" for "
260 <<server->getPlayerName(peer_id)<<std::endl;*/
261 //infostream<<"RemoteClient::SendBlocks(): d="<<d<<std::endl;
264 If m_nearest_unsent_d was changed by the EmergeThread
265 (it can change it to 0 through SetBlockNotSent),
267 Else update m_nearest_unsent_d
269 /*if(m_nearest_unsent_d != last_nearest_unsent_d)
271 d = m_nearest_unsent_d;
272 last_nearest_unsent_d = m_nearest_unsent_d;
276 Get the border/face dot coordinates of a "d-radiused"
279 std::list<v3s16> list;
280 getFacePositions(list, d);
282 std::list<v3s16>::iterator li;
283 for(li=list.begin(); li!=list.end(); ++li)
285 v3s16 p = *li + center;
289 - Don't allow too many simultaneous transfers
290 - EXCEPT when the blocks are very close
292 Also, don't send blocks that are already flying.
295 // Start with the usual maximum
296 u16 max_simul_dynamic = max_simul_sends_usually;
298 // If block is very close, allow full maximum
299 if(d <= BLOCK_SEND_DISABLE_LIMITS_MAX_D)
300 max_simul_dynamic = max_simul_sends_setting;
302 // Don't select too many blocks for sending
303 if(num_blocks_selected >= max_simul_dynamic)
305 queue_is_full = true;
306 goto queue_full_break;
309 // Don't send blocks that are currently being transferred
310 if(m_blocks_sending.find(p) != m_blocks_sending.end())
316 if(p.X < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
317 || p.X > MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
318 || p.Y < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
319 || p.Y > MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
320 || p.Z < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
321 || p.Z > MAP_GENERATION_LIMIT / MAP_BLOCKSIZE)
324 // If this is true, inexistent block will be made from scratch
325 bool generate = d <= d_max_gen;
328 /*// Limit the generating area vertically to 2/3
329 if(abs(p.Y - center.Y) > d_max_gen - d_max_gen / 3)
332 // Limit the send area vertically to 1/2
333 if(abs(p.Y - center.Y) > d_max / 2)
339 If block is far away, don't generate it unless it is
345 // Block center y in nodes
346 f32 y = (f32)(p.Y * MAP_BLOCKSIZE + MAP_BLOCKSIZE/2);
347 // Don't generate if it's very high or very low
348 if(y < -64 || y > 64)
352 v2s16 p2d_nodes_center(
356 // Get ground height in nodes
357 s16 gh = server->m_env->getServerMap().findGroundLevel(
360 // If differs a lot, don't generate
361 if(fabs(gh - y) > MAP_BLOCKSIZE*2)
363 // Actually, don't even send it
369 //infostream<<"d="<<d<<std::endl;
372 Don't generate or send if not in sight
373 FIXME This only works if the client uses a small enough
374 FOV setting. The default of 72 degrees is fine.
377 float camera_fov = (72.0*M_PI/180) * 4./3.;
378 if(isBlockInSight(p, camera_pos, camera_dir, camera_fov, 10000*BS) == false)
384 Don't send already sent blocks
387 if(m_blocks_sent.find(p) != m_blocks_sent.end())
394 Check if map has this block
396 MapBlock *block = server->m_env->getMap().getBlockNoCreateNoEx(p);
398 bool surely_not_found_on_disk = false;
399 bool block_is_invalid = false;
402 // Reset usage timer, this block will be of use in the future.
403 block->resetUsageTimer();
405 // Block is dummy if data doesn't exist.
406 // It means it has been not found from disk and not generated
409 surely_not_found_on_disk = true;
412 // Block is valid if lighting is up-to-date and data exists
413 if(block->isValid() == false)
415 block_is_invalid = true;
418 /*if(block->isFullyGenerated() == false)
420 block_is_invalid = true;
425 ServerMap *map = (ServerMap*)(&server->m_env->getMap());
426 v2s16 chunkpos = map->sector_to_chunk(p2d);
427 if(map->chunkNonVolatile(chunkpos) == false)
428 block_is_invalid = true;
430 if(block->isGenerated() == false)
431 block_is_invalid = true;
434 If block is not close, don't send it unless it is near
437 Block is near ground level if night-time mesh
438 differs from day-time mesh.
442 if(block->getDayNightDiff() == false)
449 If block has been marked to not exist on disk (dummy)
450 and generating new ones is not wanted, skip block.
452 if(generate == false && surely_not_found_on_disk == true)
459 Add inexistent block to emerge queue.
461 if(block == NULL || surely_not_found_on_disk || block_is_invalid)
463 /* //TODO: Get value from somewhere
464 // Allow only one block in emerge queue
465 //if(server->m_emerge_queue.peerItemCount(peer_id) < 1)
466 // Allow two blocks in queue per client
467 //if(server->m_emerge_queue.peerItemCount(peer_id) < 2)
469 // Make it more responsive when needing to generate stuff
470 if(surely_not_found_on_disk)
472 if(server->m_emerge_queue.peerItemCount(peer_id) < max_emerge)
474 //infostream<<"Adding block to emerge queue"<<std::endl;
476 // Add it to the emerge queue and trigger the thread
479 if(generate == false)
480 flags |= BLOCK_EMERGE_FLAG_FROMDISK;
482 server->m_emerge_queue.addBlock(peer_id, p, flags);
483 server->m_emergethread.trigger();
485 if(nearest_emerged_d == -1)
486 nearest_emerged_d = d;
488 if(nearest_emergefull_d == -1)
489 nearest_emergefull_d = d;
490 goto queue_full_break;
494 if (server->m_emerge->enqueueBlockEmerge(peer_id, p, generate)) {
495 if (nearest_emerged_d == -1)
496 nearest_emerged_d = d;
498 if (nearest_emergefull_d == -1)
499 nearest_emergefull_d = d;
500 goto queue_full_break;
507 if(nearest_sent_d == -1)
511 Add block to send queue
514 /*errorstream<<"sending from d="<<d<<" to "
515 <<server->getPlayerName(peer_id)<<std::endl;*/
517 PrioritySortedBlockTransfer q((float)d, p, peer_id);
521 num_blocks_selected += 1;
526 //infostream<<"Stopped at "<<d<<std::endl;
528 // If nothing was found for sending and nothing was queued for
529 // emerging, continue next time browsing from here
530 if(nearest_emerged_d != -1){
531 new_nearest_unsent_d = nearest_emerged_d;
532 } else if(nearest_emergefull_d != -1){
533 new_nearest_unsent_d = nearest_emergefull_d;
535 if(d > g_settings->getS16("max_block_send_distance")){
536 new_nearest_unsent_d = 0;
537 m_nothing_to_send_pause_timer = 2.0;
538 /*infostream<<"GetNextBlocks(): d wrapped around for "
539 <<server->getPlayerName(peer_id)
540 <<"; setting to 0 and pausing"<<std::endl;*/
542 if(nearest_sent_d != -1)
543 new_nearest_unsent_d = nearest_sent_d;
545 new_nearest_unsent_d = d;
549 if(new_nearest_unsent_d != -1)
550 m_nearest_unsent_d = new_nearest_unsent_d;
552 /*timer_result = timer.stop(true);
553 if(timer_result != 0)
554 infostream<<"GetNextBlocks timeout: "<<timer_result<<" (!=0)"<<std::endl;*/
557 void RemoteClient::GotBlock(v3s16 p)
559 if(m_blocks_sending.find(p) != m_blocks_sending.end())
560 m_blocks_sending.erase(p);
563 /*infostream<<"RemoteClient::GotBlock(): Didn't find in"
564 " m_blocks_sending"<<std::endl;*/
565 m_excess_gotblocks++;
567 m_blocks_sent.insert(p);
570 void RemoteClient::SentBlock(v3s16 p)
572 if(m_blocks_sending.find(p) == m_blocks_sending.end())
573 m_blocks_sending[p] = 0.0;
575 infostream<<"RemoteClient::SentBlock(): Sent block"
576 " already in m_blocks_sending"<<std::endl;
579 void RemoteClient::SetBlockNotSent(v3s16 p)
581 m_nearest_unsent_d = 0;
583 if(m_blocks_sending.find(p) != m_blocks_sending.end())
584 m_blocks_sending.erase(p);
585 if(m_blocks_sent.find(p) != m_blocks_sent.end())
586 m_blocks_sent.erase(p);
589 void RemoteClient::SetBlocksNotSent(std::map<v3s16, MapBlock*> &blocks)
591 m_nearest_unsent_d = 0;
593 for(std::map<v3s16, MapBlock*>::iterator
595 i != blocks.end(); ++i)
599 if(m_blocks_sending.find(p) != m_blocks_sending.end())
600 m_blocks_sending.erase(p);
601 if(m_blocks_sent.find(p) != m_blocks_sent.end())
602 m_blocks_sent.erase(p);
610 PlayerInfo::PlayerInfo()
616 void PlayerInfo::PrintLine(std::ostream *s)
619 (*s)<<"\""<<name<<"\" ("
620 <<(position.X/10)<<","<<(position.Y/10)
621 <<","<<(position.Z/10)<<") ";
623 (*s)<<" avg_rtt="<<avg_rtt;
632 const std::string &path_world,
633 const std::string &path_config,
634 const SubgameSpec &gamespec,
635 bool simple_singleplayer_mode
637 m_path_world(path_world),
638 m_path_config(path_config),
639 m_gamespec(gamespec),
640 m_simple_singleplayer_mode(simple_singleplayer_mode),
641 m_async_fatal_error(""),
643 m_con(PROTOCOL_ID, 512, CONNECTION_TIMEOUT, this),
644 m_banmanager(path_world+DIR_DELIM+"ipban.txt"),
646 m_rollback_sink_enabled(true),
647 m_enable_rollback_recording(false),
651 m_itemdef(createItemDefManager()),
652 m_nodedef(createNodeDefManager()),
653 m_craftdef(createCraftDefManager()),
654 m_event(new EventManager()),
656 m_time_of_day_send_timer(0),
658 m_shutdown_requested(false),
659 m_ignore_map_edit_events(false),
660 m_ignore_map_edit_events_peer_id(0)
662 m_liquid_transform_timer = 0.0;
663 m_liquid_transform_every = 1.0;
664 m_print_info_timer = 0.0;
665 m_masterserver_timer = 0.0;
666 m_objectdata_timer = 0.0;
667 m_emergethread_trigger_timer = 0.0;
668 m_savemap_timer = 0.0;
669 m_clients_number = 0;
673 m_step_dtime_mutex.Init();
677 throw ServerError("Supplied empty world path");
679 if(!gamespec.isValid())
680 throw ServerError("Supplied invalid gamespec");
682 infostream<<"Server created for gameid \""<<m_gamespec.id<<"\"";
683 if(m_simple_singleplayer_mode)
684 infostream<<" in simple singleplayer mode"<<std::endl;
686 infostream<<std::endl;
687 infostream<<"- world: "<<m_path_world<<std::endl;
688 infostream<<"- config: "<<m_path_config<<std::endl;
689 infostream<<"- game: "<<m_gamespec.path<<std::endl;
691 // Initialize default settings and override defaults with those provided
693 set_default_settings(g_settings);
694 Settings gamedefaults;
695 getGameMinetestConfig(gamespec.path, gamedefaults);
696 override_default_settings(g_settings, &gamedefaults);
698 // Create biome definition manager
699 m_biomedef = new BiomeDefManager(this);
701 // Create emerge manager
702 m_emerge = new EmergeManager(this, m_biomedef);
704 // Create rollback manager
705 std::string rollback_path = m_path_world+DIR_DELIM+"rollback.txt";
706 m_rollback = createRollbackManager(rollback_path, 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 ModConfiguration modconf(m_path_world);
713 m_mods = modconf.getMods();
714 std::list<ModSpec> unsatisfied_mods = modconf.getUnsatisfiedMods();
715 // complain about mods with unsatisfied dependencies
716 if(!modconf.isConsistent())
718 for(std::list<ModSpec>::iterator it = unsatisfied_mods.begin();
719 it != unsatisfied_mods.end(); ++it)
722 errorstream << "mod \"" << mod.name << "\" has unsatisfied dependencies: ";
723 for(std::set<std::string>::iterator dep_it = mod.unsatisfied_depends.begin();
724 dep_it != mod.unsatisfied_depends.end(); ++dep_it)
725 errorstream << " \"" << *dep_it << "\"";
726 errorstream << std::endl;
730 Settings worldmt_settings;
731 std::string worldmt = m_path_world + DIR_DELIM + "world.mt";
732 worldmt_settings.readConfigFile(worldmt.c_str());
733 std::vector<std::string> names = worldmt_settings.getNames();
734 std::set<std::string> exclude_mod_names;
735 std::set<std::string> load_mod_names;
736 for(std::vector<std::string>::iterator it = names.begin();
737 it != names.end(); ++it)
739 std::string name = *it;
740 if (name.compare(0,9,"load_mod_")==0)
742 if(worldmt_settings.getBool(name))
743 load_mod_names.insert(name.substr(9));
745 exclude_mod_names.insert(name.substr(9));
748 // complain about mods declared to be loaded, but not found
749 for(std::vector<ModSpec>::iterator it = m_mods.begin();
750 it != m_mods.end(); ++it)
751 load_mod_names.erase((*it).name);
752 for(std::list<ModSpec>::iterator it = unsatisfied_mods.begin();
753 it != unsatisfied_mods.end(); ++it)
754 load_mod_names.erase((*it).name);
755 if(!load_mod_names.empty())
757 errorstream << "The following mods could not be found:";
758 for(std::set<std::string>::iterator it = load_mod_names.begin();
759 it != load_mod_names.end(); ++it)
760 errorstream << " \"" << (*it) << "\"";
761 errorstream << std::endl;
764 // Path to builtin.lua
765 std::string builtinpath = getBuiltinLuaPath() + DIR_DELIM + "builtin.lua";
768 JMutexAutoLock envlock(m_env_mutex);
769 JMutexAutoLock conlock(m_con_mutex);
771 // Initialize scripting
773 infostream<<"Server: Initializing Lua"<<std::endl;
774 m_lua = script_init();
777 scriptapi_export(m_lua, this);
778 // Load and run builtin.lua
779 infostream<<"Server: Loading builtin.lua [\""
780 <<builtinpath<<"\"]"<<std::endl;
781 bool success = scriptapi_loadmod(m_lua, builtinpath, "__builtin");
783 errorstream<<"Server: Failed to load and run "
784 <<builtinpath<<std::endl;
785 throw ModError("Failed to load and run "+builtinpath);
788 infostream<<"Server: Loading mods: ";
789 for(std::vector<ModSpec>::iterator i = m_mods.begin();
790 i != m_mods.end(); i++){
791 const ModSpec &mod = *i;
792 infostream<<mod.name<<" ";
794 infostream<<std::endl;
795 // Load and run "mod" scripts
796 for(std::vector<ModSpec>::iterator i = m_mods.begin();
797 i != m_mods.end(); i++){
798 const ModSpec &mod = *i;
799 std::string scriptpath = mod.path + DIR_DELIM + "init.lua";
800 infostream<<" ["<<padStringRight(mod.name, 12)<<"] [\""
801 <<scriptpath<<"\"]"<<std::endl;
802 bool success = scriptapi_loadmod(m_lua, scriptpath, mod.name);
804 errorstream<<"Server: Failed to load and run "
805 <<scriptpath<<std::endl;
806 throw ModError("Failed to load and run "+scriptpath);
810 // Read Textures and calculate sha1 sums
813 // Apply item aliases in the node definition manager
814 m_nodedef->updateAliases(m_itemdef);
816 // Add default biomes after nodedef had its aliases added
817 m_biomedef->addDefaultBiomes();
819 // Initialize Environment
820 ServerMap *servermap = new ServerMap(path_world, this, m_emerge);
821 m_env = new ServerEnvironment(servermap, m_lua, this, this);
823 m_emerge->initMapgens(servermap->getMapgenParams());
825 // Give environment reference to scripting api
826 scriptapi_add_environment(m_lua, m_env);
828 // Register us to receive map edit events
829 servermap->addEventReceiver(this);
831 // If file exists, load environment metadata
832 if(fs::PathExists(m_path_world+DIR_DELIM+"env_meta.txt"))
834 infostream<<"Server: Loading environment metadata"<<std::endl;
835 m_env->loadMeta(m_path_world);
839 infostream<<"Server: Loading players"<<std::endl;
840 m_env->deSerializePlayers(m_path_world);
843 Add some test ActiveBlockModifiers to environment
845 add_legacy_abms(m_env, m_nodedef);
847 m_liquid_transform_every = g_settings->getFloat("liquid_update");
852 infostream<<"Server destructing"<<std::endl;
855 Send shutdown message
858 JMutexAutoLock conlock(m_con_mutex);
860 std::wstring line = L"*** Server shutting down";
863 Send the message to clients
865 for(std::map<u16, RemoteClient*>::iterator
866 i = m_clients.begin();
867 i != m_clients.end(); ++i)
869 // Get client and check that it is valid
870 RemoteClient *client = i->second;
871 assert(client->peer_id == i->first);
872 if(client->serialization_version == SER_FMT_VER_INVALID)
876 SendChatMessage(client->peer_id, line);
878 catch(con::PeerNotFoundException &e)
884 JMutexAutoLock envlock(m_env_mutex);
885 JMutexAutoLock conlock(m_con_mutex);
888 Execute script shutdown hooks
890 scriptapi_on_shutdown(m_lua);
894 JMutexAutoLock envlock(m_env_mutex);
899 infostream<<"Server: Saving players"<<std::endl;
900 m_env->serializePlayers(m_path_world);
903 Save environment metadata
905 infostream<<"Server: Saving environment metadata"<<std::endl;
906 m_env->saveMeta(m_path_world);
918 JMutexAutoLock clientslock(m_con_mutex);
920 for(std::map<u16, RemoteClient*>::iterator
921 i = m_clients.begin();
922 i != m_clients.end(); ++i)
930 // Delete things in the reverse order of creation
939 // Deinitialize scripting
940 infostream<<"Server: Deinitializing scripting"<<std::endl;
941 script_deinit(m_lua);
943 // Delete detached inventories
945 for(std::map<std::string, Inventory*>::iterator
946 i = m_detached_inventories.begin();
947 i != m_detached_inventories.end(); i++){
953 void Server::start(unsigned short port)
955 DSTACK(__FUNCTION_NAME);
956 infostream<<"Starting server on port "<<port<<"..."<<std::endl;
958 // Stop thread if already running
961 // Initialize connection
962 m_con.SetTimeoutMs(30);
966 m_thread.setRun(true);
969 // ASCII art for the win!
971 <<" .__ __ __ "<<std::endl
972 <<" _____ |__| ____ _____/ |_ ____ _______/ |_ "<<std::endl
973 <<" / \\| |/ \\_/ __ \\ __\\/ __ \\ / ___/\\ __\\"<<std::endl
974 <<"| Y Y \\ | | \\ ___/| | \\ ___/ \\___ \\ | | "<<std::endl
975 <<"|__|_| /__|___| /\\___ >__| \\___ >____ > |__| "<<std::endl
976 <<" \\/ \\/ \\/ \\/ \\/ "<<std::endl;
977 actionstream<<"World at ["<<m_path_world<<"]"<<std::endl;
978 actionstream<<"Server for gameid=\""<<m_gamespec.id
979 <<"\" listening on port "<<port<<"."<<std::endl;
984 DSTACK(__FUNCTION_NAME);
986 infostream<<"Server: Stopping and waiting threads"<<std::endl;
988 // Stop threads (set run=false first so both start stopping)
989 m_thread.setRun(false);
990 //m_emergethread.setRun(false);
992 //m_emergethread.stop();
994 infostream<<"Server: Threads stopped"<<std::endl;
997 void Server::step(float dtime)
999 DSTACK(__FUNCTION_NAME);
1004 JMutexAutoLock lock(m_step_dtime_mutex);
1005 m_step_dtime += dtime;
1007 // Throw if fatal error occurred in thread
1008 std::string async_err = m_async_fatal_error.get();
1009 if(async_err != ""){
1010 throw ServerError(async_err);
1014 void Server::AsyncRunStep()
1016 DSTACK(__FUNCTION_NAME);
1018 g_profiler->add("Server::AsyncRunStep (num)", 1);
1022 JMutexAutoLock lock1(m_step_dtime_mutex);
1023 dtime = m_step_dtime;
1027 // Send blocks to clients
1034 g_profiler->add("Server::AsyncRunStep with dtime (num)", 1);
1036 //infostream<<"Server steps "<<dtime<<std::endl;
1037 //infostream<<"Server::AsyncRunStep(): dtime="<<dtime<<std::endl;
1040 JMutexAutoLock lock1(m_step_dtime_mutex);
1041 m_step_dtime -= dtime;
1048 m_uptime.set(m_uptime.get() + dtime);
1052 // Process connection's timeouts
1053 JMutexAutoLock lock2(m_con_mutex);
1054 ScopeProfiler sp(g_profiler, "Server: connection timeout processing");
1055 m_con.RunTimeouts(dtime);
1059 // This has to be called so that the client list gets synced
1060 // with the peer list of the connection
1061 handlePeerChanges();
1065 Update time of day and overall game time
1068 JMutexAutoLock envlock(m_env_mutex);
1070 m_env->setTimeOfDaySpeed(g_settings->getFloat("time_speed"));
1073 Send to clients at constant intervals
1076 m_time_of_day_send_timer -= dtime;
1077 if(m_time_of_day_send_timer < 0.0)
1079 m_time_of_day_send_timer = g_settings->getFloat("time_send_interval");
1081 //JMutexAutoLock envlock(m_env_mutex);
1082 JMutexAutoLock conlock(m_con_mutex);
1084 for(std::map<u16, RemoteClient*>::iterator
1085 i = m_clients.begin();
1086 i != m_clients.end(); ++i)
1088 RemoteClient *client = i->second;
1089 SharedBuffer<u8> data = makePacket_TOCLIENT_TIME_OF_DAY(
1090 m_env->getTimeOfDay(), g_settings->getFloat("time_speed"));
1092 m_con.Send(client->peer_id, 0, data, true);
1098 JMutexAutoLock lock(m_env_mutex);
1100 ScopeProfiler sp(g_profiler, "SEnv step");
1101 ScopeProfiler sp2(g_profiler, "SEnv step avg", SPT_AVG);
1105 const float map_timer_and_unload_dtime = 2.92;
1106 if(m_map_timer_and_unload_interval.step(dtime, map_timer_and_unload_dtime))
1108 JMutexAutoLock lock(m_env_mutex);
1109 // Run Map's timers and unload unused data
1110 ScopeProfiler sp(g_profiler, "Server: map timer and unload");
1111 m_env->getMap().timerUpdate(map_timer_and_unload_dtime,
1112 g_settings->getFloat("server_unload_unused_data_timeout"));
1123 JMutexAutoLock lock(m_env_mutex);
1124 JMutexAutoLock lock2(m_con_mutex);
1126 ScopeProfiler sp(g_profiler, "Server: handle players");
1128 for(std::map<u16, RemoteClient*>::iterator
1129 i = m_clients.begin();
1130 i != m_clients.end(); ++i)
1132 RemoteClient *client = i->second;
1133 PlayerSAO *playersao = getPlayerSAO(client->peer_id);
1134 if(playersao == NULL)
1138 Handle player HPs (die if hp=0)
1140 if(playersao->m_hp_not_sent && g_settings->getBool("enable_damage"))
1142 if(playersao->getHP() == 0)
1143 DiePlayer(client->peer_id);
1145 SendPlayerHP(client->peer_id);
1149 Send player inventories if necessary
1151 if(playersao->m_moved){
1152 SendMovePlayer(client->peer_id);
1153 playersao->m_moved = false;
1155 if(playersao->m_inventory_not_sent){
1156 UpdateCrafting(client->peer_id);
1157 SendInventory(client->peer_id);
1162 /* Transform liquids */
1163 m_liquid_transform_timer += dtime;
1164 if(m_liquid_transform_timer >= m_liquid_transform_every)
1166 m_liquid_transform_timer -= m_liquid_transform_every;
1168 JMutexAutoLock lock(m_env_mutex);
1170 ScopeProfiler sp(g_profiler, "Server: liquid transform");
1172 std::map<v3s16, MapBlock*> modified_blocks;
1173 m_env->getMap().transformLiquids(modified_blocks);
1178 core::map<v3s16, MapBlock*> lighting_modified_blocks;
1179 ServerMap &map = ((ServerMap&)m_env->getMap());
1180 map.updateLighting(modified_blocks, lighting_modified_blocks);
1182 // Add blocks modified by lighting to modified_blocks
1183 for(core::map<v3s16, MapBlock*>::Iterator
1184 i = lighting_modified_blocks.getIterator();
1185 i.atEnd() == false; i++)
1187 MapBlock *block = i.getNode()->getValue();
1188 modified_blocks.insert(block->getPos(), block);
1192 Set the modified blocks unsent for all the clients
1195 JMutexAutoLock lock2(m_con_mutex);
1197 for(std::map<u16, RemoteClient*>::iterator
1198 i = m_clients.begin();
1199 i != m_clients.end(); ++i)
1201 RemoteClient *client = i->second;
1203 if(modified_blocks.size() > 0)
1205 // Remove block from sent history
1206 client->SetBlocksNotSent(modified_blocks);
1211 // Periodically print some info
1213 float &counter = m_print_info_timer;
1219 JMutexAutoLock lock2(m_con_mutex);
1220 m_clients_number = 0;
1221 if(m_clients.size() != 0)
1222 infostream<<"Players:"<<std::endl;
1223 for(std::map<u16, RemoteClient*>::iterator
1224 i = m_clients.begin();
1225 i != m_clients.end(); ++i)
1227 //u16 peer_id = i.getNode()->getKey();
1228 RemoteClient *client = i->second;
1229 Player *player = m_env->getPlayer(client->peer_id);
1232 infostream<<"* "<<player->getName()<<"\t";
1233 client->PrintInfo(infostream);
1241 // send masterserver announce
1243 float &counter = m_masterserver_timer;
1244 if((!counter || counter >= 300.0) && g_settings->getBool("server_announce") == true)
1246 ServerList::sendAnnounce(!counter ? "start" : "update", m_clients_number, m_uptime.get(), m_gamespec.id);
1253 //if(g_settings->getBool("enable_experimental"))
1257 Check added and deleted active objects
1260 //infostream<<"Server: Checking added and deleted active objects"<<std::endl;
1261 JMutexAutoLock envlock(m_env_mutex);
1262 JMutexAutoLock conlock(m_con_mutex);
1264 ScopeProfiler sp(g_profiler, "Server: checking added and deleted objs");
1266 // Radius inside which objects are active
1267 s16 radius = g_settings->getS16("active_object_send_range_blocks");
1268 radius *= MAP_BLOCKSIZE;
1270 for(std::map<u16, RemoteClient*>::iterator
1271 i = m_clients.begin();
1272 i != m_clients.end(); ++i)
1274 RemoteClient *client = i->second;
1276 // If definitions and textures have not been sent, don't
1277 // send objects either
1278 if(!client->definitions_sent)
1281 Player *player = m_env->getPlayer(client->peer_id);
1284 // This can happen if the client timeouts somehow
1285 /*infostream<<"WARNING: "<<__FUNCTION_NAME<<": Client "
1287 <<" has no associated player"<<std::endl;*/
1290 v3s16 pos = floatToInt(player->getPosition(), BS);
1292 std::set<u16> removed_objects;
1293 std::set<u16> added_objects;
1294 m_env->getRemovedActiveObjects(pos, radius,
1295 client->m_known_objects, removed_objects);
1296 m_env->getAddedActiveObjects(pos, radius,
1297 client->m_known_objects, added_objects);
1299 // Ignore if nothing happened
1300 if(removed_objects.size() == 0 && added_objects.size() == 0)
1302 //infostream<<"active objects: none changed"<<std::endl;
1306 std::string data_buffer;
1310 // Handle removed objects
1311 writeU16((u8*)buf, removed_objects.size());
1312 data_buffer.append(buf, 2);
1313 for(std::set<u16>::iterator
1314 i = removed_objects.begin();
1315 i != removed_objects.end(); ++i)
1319 ServerActiveObject* obj = m_env->getActiveObject(id);
1321 // Add to data buffer for sending
1322 writeU16((u8*)buf, id);
1323 data_buffer.append(buf, 2);
1325 // Remove from known objects
1326 client->m_known_objects.erase(id);
1328 if(obj && obj->m_known_by_count > 0)
1329 obj->m_known_by_count--;
1332 // Handle added objects
1333 writeU16((u8*)buf, added_objects.size());
1334 data_buffer.append(buf, 2);
1335 for(std::set<u16>::iterator
1336 i = added_objects.begin();
1337 i != added_objects.end(); ++i)
1341 ServerActiveObject* obj = m_env->getActiveObject(id);
1344 u8 type = ACTIVEOBJECT_TYPE_INVALID;
1346 infostream<<"WARNING: "<<__FUNCTION_NAME
1347 <<": NULL object"<<std::endl;
1349 type = obj->getSendType();
1351 // Add to data buffer for sending
1352 writeU16((u8*)buf, id);
1353 data_buffer.append(buf, 2);
1354 writeU8((u8*)buf, type);
1355 data_buffer.append(buf, 1);
1358 data_buffer.append(serializeLongString(
1359 obj->getClientInitializationData(client->net_proto_version)));
1361 data_buffer.append(serializeLongString(""));
1363 // Add to known objects
1364 client->m_known_objects.insert(id);
1367 obj->m_known_by_count++;
1371 SharedBuffer<u8> reply(2 + data_buffer.size());
1372 writeU16(&reply[0], TOCLIENT_ACTIVE_OBJECT_REMOVE_ADD);
1373 memcpy((char*)&reply[2], data_buffer.c_str(),
1374 data_buffer.size());
1376 m_con.Send(client->peer_id, 0, reply, true);
1378 verbosestream<<"Server: Sent object remove/add: "
1379 <<removed_objects.size()<<" removed, "
1380 <<added_objects.size()<<" added, "
1381 <<"packet size is "<<reply.getSize()<<std::endl;
1386 Collect a list of all the objects known by the clients
1387 and report it back to the environment.
1390 core::map<u16, bool> all_known_objects;
1392 for(core::map<u16, RemoteClient*>::Iterator
1393 i = m_clients.getIterator();
1394 i.atEnd() == false; i++)
1396 RemoteClient *client = i.getNode()->getValue();
1397 // Go through all known objects of client
1398 for(core::map<u16, bool>::Iterator
1399 i = client->m_known_objects.getIterator();
1400 i.atEnd()==false; i++)
1402 u16 id = i.getNode()->getKey();
1403 all_known_objects[id] = true;
1407 m_env->setKnownActiveObjects(whatever);
1413 Send object messages
1416 JMutexAutoLock envlock(m_env_mutex);
1417 JMutexAutoLock conlock(m_con_mutex);
1419 ScopeProfiler sp(g_profiler, "Server: sending object messages");
1422 // Value = data sent by object
1423 std::map<u16, std::list<ActiveObjectMessage>* > buffered_messages;
1425 // Get active object messages from environment
1428 ActiveObjectMessage aom = m_env->getActiveObjectMessage();
1432 std::list<ActiveObjectMessage>* message_list = NULL;
1433 std::map<u16, std::list<ActiveObjectMessage>* >::iterator n;
1434 n = buffered_messages.find(aom.id);
1435 if(n == buffered_messages.end())
1437 message_list = new std::list<ActiveObjectMessage>;
1438 buffered_messages[aom.id] = message_list;
1442 message_list = n->second;
1444 message_list->push_back(aom);
1447 // Route data to every client
1448 for(std::map<u16, RemoteClient*>::iterator
1449 i = m_clients.begin();
1450 i != m_clients.end(); ++i)
1452 RemoteClient *client = i->second;
1453 std::string reliable_data;
1454 std::string unreliable_data;
1455 // Go through all objects in message buffer
1456 for(std::map<u16, std::list<ActiveObjectMessage>* >::iterator
1457 j = buffered_messages.begin();
1458 j != buffered_messages.end(); ++j)
1460 // If object is not known by client, skip it
1462 if(client->m_known_objects.find(id) == client->m_known_objects.end())
1464 // Get message list of object
1465 std::list<ActiveObjectMessage>* list = j->second;
1466 // Go through every message
1467 for(std::list<ActiveObjectMessage>::iterator
1468 k = list->begin(); k != list->end(); ++k)
1470 // Compose the full new data with header
1471 ActiveObjectMessage aom = *k;
1472 std::string new_data;
1475 writeU16((u8*)&buf[0], aom.id);
1476 new_data.append(buf, 2);
1478 new_data += serializeString(aom.datastring);
1479 // Add data to buffer
1481 reliable_data += new_data;
1483 unreliable_data += new_data;
1487 reliable_data and unreliable_data are now ready.
1490 if(reliable_data.size() > 0)
1492 SharedBuffer<u8> reply(2 + reliable_data.size());
1493 writeU16(&reply[0], TOCLIENT_ACTIVE_OBJECT_MESSAGES);
1494 memcpy((char*)&reply[2], reliable_data.c_str(),
1495 reliable_data.size());
1497 m_con.Send(client->peer_id, 0, reply, true);
1499 if(unreliable_data.size() > 0)
1501 SharedBuffer<u8> reply(2 + unreliable_data.size());
1502 writeU16(&reply[0], TOCLIENT_ACTIVE_OBJECT_MESSAGES);
1503 memcpy((char*)&reply[2], unreliable_data.c_str(),
1504 unreliable_data.size());
1505 // Send as unreliable
1506 m_con.Send(client->peer_id, 0, reply, false);
1509 /*if(reliable_data.size() > 0 || unreliable_data.size() > 0)
1511 infostream<<"Server: Size of object message data: "
1512 <<"reliable: "<<reliable_data.size()
1513 <<", unreliable: "<<unreliable_data.size()
1518 // Clear buffered_messages
1519 for(std::map<u16, std::list<ActiveObjectMessage>* >::iterator
1520 i = buffered_messages.begin();
1521 i != buffered_messages.end(); ++i)
1527 } // enable_experimental
1530 Send queued-for-sending map edit events.
1533 // We will be accessing the environment and the connection
1534 JMutexAutoLock lock(m_env_mutex);
1535 JMutexAutoLock conlock(m_con_mutex);
1537 // Don't send too many at a time
1540 // Single change sending is disabled if queue size is not small
1541 bool disable_single_change_sending = false;
1542 if(m_unsent_map_edit_queue.size() >= 4)
1543 disable_single_change_sending = true;
1545 int event_count = m_unsent_map_edit_queue.size();
1547 // We'll log the amount of each
1550 while(m_unsent_map_edit_queue.size() != 0)
1552 MapEditEvent* event = m_unsent_map_edit_queue.pop_front();
1554 // Players far away from the change are stored here.
1555 // Instead of sending the changes, MapBlocks are set not sent
1557 std::list<u16> far_players;
1559 if(event->type == MEET_ADDNODE)
1561 //infostream<<"Server: MEET_ADDNODE"<<std::endl;
1562 prof.add("MEET_ADDNODE", 1);
1563 if(disable_single_change_sending)
1564 sendAddNode(event->p, event->n, event->already_known_by_peer,
1567 sendAddNode(event->p, event->n, event->already_known_by_peer,
1570 else if(event->type == MEET_REMOVENODE)
1572 //infostream<<"Server: MEET_REMOVENODE"<<std::endl;
1573 prof.add("MEET_REMOVENODE", 1);
1574 if(disable_single_change_sending)
1575 sendRemoveNode(event->p, event->already_known_by_peer,
1578 sendRemoveNode(event->p, event->already_known_by_peer,
1581 else if(event->type == MEET_BLOCK_NODE_METADATA_CHANGED)
1583 infostream<<"Server: MEET_BLOCK_NODE_METADATA_CHANGED"<<std::endl;
1584 prof.add("MEET_BLOCK_NODE_METADATA_CHANGED", 1);
1585 setBlockNotSent(event->p);
1587 else if(event->type == MEET_OTHER)
1589 infostream<<"Server: MEET_OTHER"<<std::endl;
1590 prof.add("MEET_OTHER", 1);
1591 for(std::set<v3s16>::iterator
1592 i = event->modified_blocks.begin();
1593 i != event->modified_blocks.end(); ++i)
1595 setBlockNotSent(*i);
1600 prof.add("unknown", 1);
1601 infostream<<"WARNING: Server: Unknown MapEditEvent "
1602 <<((u32)event->type)<<std::endl;
1606 Set blocks not sent to far players
1608 if(far_players.size() > 0)
1610 // Convert list format to that wanted by SetBlocksNotSent
1611 std::map<v3s16, MapBlock*> modified_blocks2;
1612 for(std::set<v3s16>::iterator
1613 i = event->modified_blocks.begin();
1614 i != event->modified_blocks.end(); ++i)
1616 modified_blocks2[*i] =
1617 m_env->getMap().getBlockNoCreateNoEx(*i);
1619 // Set blocks not sent
1620 for(std::list<u16>::iterator
1621 i = far_players.begin();
1622 i != far_players.end(); ++i)
1625 RemoteClient *client = getClient(peer_id);
1628 client->SetBlocksNotSent(modified_blocks2);
1634 /*// Don't send too many at a time
1636 if(count >= 1 && m_unsent_map_edit_queue.size() < 100)
1640 if(event_count >= 5){
1641 infostream<<"Server: MapEditEvents:"<<std::endl;
1642 prof.print(infostream);
1643 } else if(event_count != 0){
1644 verbosestream<<"Server: MapEditEvents:"<<std::endl;
1645 prof.print(verbosestream);
1651 Trigger emergethread (it somehow gets to a non-triggered but
1652 bysy state sometimes)
1655 float &counter = m_emergethread_trigger_timer;
1661 for (unsigned int i = 0; i != m_emerge->emergethread.size(); i++)
1662 m_emerge->emergethread[i]->trigger();
1664 // Update m_enable_rollback_recording here too
1665 m_enable_rollback_recording =
1666 g_settings->getBool("enable_rollback_recording");
1670 // Save map, players and auth stuff
1672 float &counter = m_savemap_timer;
1674 if(counter >= g_settings->getFloat("server_map_save_interval"))
1677 JMutexAutoLock lock(m_env_mutex);
1679 ScopeProfiler sp(g_profiler, "Server: saving stuff");
1682 if(m_banmanager.isModified())
1683 m_banmanager.save();
1685 // Save changed parts of map
1686 m_env->getMap().save(MOD_STATE_WRITE_NEEDED);
1689 m_env->serializePlayers(m_path_world);
1691 // Save environment metadata
1692 m_env->saveMeta(m_path_world);
1697 void Server::Receive()
1699 DSTACK(__FUNCTION_NAME);
1700 SharedBuffer<u8> data;
1705 JMutexAutoLock conlock(m_con_mutex);
1706 datasize = m_con.Receive(peer_id, data);
1709 // This has to be called so that the client list gets synced
1710 // with the peer list of the connection
1711 handlePeerChanges();
1713 ProcessData(*data, datasize, peer_id);
1715 catch(con::InvalidIncomingDataException &e)
1717 infostream<<"Server::Receive(): "
1718 "InvalidIncomingDataException: what()="
1719 <<e.what()<<std::endl;
1721 catch(con::PeerNotFoundException &e)
1723 //NOTE: This is not needed anymore
1725 // The peer has been disconnected.
1726 // Find the associated player and remove it.
1728 /*JMutexAutoLock envlock(m_env_mutex);
1730 infostream<<"ServerThread: peer_id="<<peer_id
1731 <<" has apparently closed connection. "
1732 <<"Removing player."<<std::endl;
1734 m_env->removePlayer(peer_id);*/
1738 void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
1740 DSTACK(__FUNCTION_NAME);
1741 // Environment is locked first.
1742 JMutexAutoLock envlock(m_env_mutex);
1743 JMutexAutoLock conlock(m_con_mutex);
1745 ScopeProfiler sp(g_profiler, "Server::ProcessData");
1748 Address address = m_con.GetPeerAddress(peer_id);
1749 std::string addr_s = address.serializeString();
1751 // drop player if is ip is banned
1752 if(m_banmanager.isIpBanned(addr_s)){
1753 infostream<<"Server: A banned client tried to connect from "
1754 <<addr_s<<"; banned name was "
1755 <<m_banmanager.getBanName(addr_s)<<std::endl;
1756 // This actually doesn't seem to transfer to the client
1757 SendAccessDenied(m_con, peer_id,
1758 L"Your ip is banned. Banned name was "
1759 +narrow_to_wide(m_banmanager.getBanName(addr_s)));
1760 m_con.DeletePeer(peer_id);
1764 catch(con::PeerNotFoundException &e)
1766 infostream<<"Server::ProcessData(): Cancelling: peer "
1767 <<peer_id<<" not found"<<std::endl;
1771 std::string addr_s = m_con.GetPeerAddress(peer_id).serializeString();
1773 u8 peer_ser_ver = getClient(peer_id)->serialization_version;
1781 ToServerCommand command = (ToServerCommand)readU16(&data[0]);
1783 if(command == TOSERVER_INIT)
1785 // [0] u16 TOSERVER_INIT
1786 // [2] u8 SER_FMT_VER_HIGHEST
1787 // [3] u8[20] player_name
1788 // [23] u8[28] password <--- can be sent without this, from old versions
1790 if(datasize < 2+1+PLAYERNAME_SIZE)
1793 verbosestream<<"Server: Got TOSERVER_INIT from "
1794 <<peer_id<<std::endl;
1796 // First byte after command is maximum supported
1797 // serialization version
1798 u8 client_max = data[2];
1799 u8 our_max = SER_FMT_VER_HIGHEST;
1800 // Use the highest version supported by both
1801 u8 deployed = std::min(client_max, our_max);
1802 // If it's lower than the lowest supported, give up.
1803 if(deployed < SER_FMT_VER_LOWEST)
1804 deployed = SER_FMT_VER_INVALID;
1806 //peer->serialization_version = deployed;
1807 getClient(peer_id)->pending_serialization_version = deployed;
1809 if(deployed == SER_FMT_VER_INVALID)
1811 actionstream<<"Server: A mismatched client tried to connect from "
1812 <<addr_s<<std::endl;
1813 infostream<<"Server: Cannot negotiate "
1814 "serialization version with peer "
1815 <<peer_id<<std::endl;
1816 SendAccessDenied(m_con, peer_id, std::wstring(
1817 L"Your client's version is not supported.\n"
1818 L"Server version is ")
1819 + narrow_to_wide(VERSION_STRING) + L"."
1825 Read and check network protocol version
1828 u16 min_net_proto_version = 0;
1829 if(datasize >= 2+1+PLAYERNAME_SIZE+PASSWORD_SIZE+2)
1830 min_net_proto_version = readU16(&data[2+1+PLAYERNAME_SIZE+PASSWORD_SIZE]);
1832 // Use same version as minimum and maximum if maximum version field
1833 // doesn't exist (backwards compatibility)
1834 u16 max_net_proto_version = min_net_proto_version;
1835 if(datasize >= 2+1+PLAYERNAME_SIZE+PASSWORD_SIZE+2+2)
1836 max_net_proto_version = readU16(&data[2+1+PLAYERNAME_SIZE+PASSWORD_SIZE+2]);
1838 // Start with client's maximum version
1839 u16 net_proto_version = max_net_proto_version;
1841 // Figure out a working version if it is possible at all
1842 if(max_net_proto_version >= SERVER_PROTOCOL_VERSION_MIN ||
1843 min_net_proto_version <= SERVER_PROTOCOL_VERSION_MAX)
1845 // If maximum is larger than our maximum, go with our maximum
1846 if(max_net_proto_version > SERVER_PROTOCOL_VERSION_MAX)
1847 net_proto_version = SERVER_PROTOCOL_VERSION_MAX;
1848 // Else go with client's maximum
1850 net_proto_version = max_net_proto_version;
1853 verbosestream<<"Server: "<<peer_id<<" Protocol version: min: "
1854 <<min_net_proto_version<<", max: "<<max_net_proto_version
1855 <<", chosen: "<<net_proto_version<<std::endl;
1857 getClient(peer_id)->net_proto_version = net_proto_version;
1859 if(net_proto_version < SERVER_PROTOCOL_VERSION_MIN ||
1860 net_proto_version > SERVER_PROTOCOL_VERSION_MAX)
1862 actionstream<<"Server: A mismatched client tried to connect from "<<addr_s
1864 SendAccessDenied(m_con, peer_id, std::wstring(
1865 L"Your client's version is not supported.\n"
1866 L"Server version is ")
1867 + narrow_to_wide(VERSION_STRING) + L",\n"
1868 + L"server's PROTOCOL_VERSION is "
1869 + narrow_to_wide(itos(SERVER_PROTOCOL_VERSION_MIN))
1871 + narrow_to_wide(itos(SERVER_PROTOCOL_VERSION_MAX))
1872 + L", client's PROTOCOL_VERSION is "
1873 + narrow_to_wide(itos(min_net_proto_version))
1875 + narrow_to_wide(itos(max_net_proto_version))
1880 if(g_settings->getBool("strict_protocol_version_checking"))
1882 if(net_proto_version != LATEST_PROTOCOL_VERSION)
1884 actionstream<<"Server: A mismatched (strict) client tried to "
1885 <<"connect from "<<addr_s<<std::endl;
1886 SendAccessDenied(m_con, peer_id, std::wstring(
1887 L"Your client's version is not supported.\n"
1888 L"Server version is ")
1889 + narrow_to_wide(VERSION_STRING) + L",\n"
1890 + L"server's PROTOCOL_VERSION (strict) is "
1891 + narrow_to_wide(itos(LATEST_PROTOCOL_VERSION))
1892 + L", client's PROTOCOL_VERSION is "
1893 + narrow_to_wide(itos(min_net_proto_version))
1895 + narrow_to_wide(itos(max_net_proto_version))
1906 char playername[PLAYERNAME_SIZE];
1907 for(u32 i=0; i<PLAYERNAME_SIZE-1; i++)
1909 playername[i] = data[3+i];
1911 playername[PLAYERNAME_SIZE-1] = 0;
1913 if(playername[0]=='\0')
1915 actionstream<<"Server: Player with an empty name "
1916 <<"tried to connect from "<<addr_s<<std::endl;
1917 SendAccessDenied(m_con, peer_id,
1922 if(string_allowed(playername, PLAYERNAME_ALLOWED_CHARS)==false)
1924 actionstream<<"Server: Player with an invalid name "
1925 <<"tried to connect from "<<addr_s<<std::endl;
1926 SendAccessDenied(m_con, peer_id,
1927 L"Name contains unallowed characters");
1931 infostream<<"Server: New connection: \""<<playername<<"\" from "
1932 <<m_con.GetPeerAddress(peer_id).serializeString()<<std::endl;
1935 char given_password[PASSWORD_SIZE];
1936 if(datasize < 2+1+PLAYERNAME_SIZE+PASSWORD_SIZE)
1938 // old version - assume blank password
1939 given_password[0] = 0;
1943 for(u32 i=0; i<PASSWORD_SIZE-1; i++)
1945 given_password[i] = data[23+i];
1947 given_password[PASSWORD_SIZE-1] = 0;
1950 if(!base64_is_valid(given_password)){
1951 infostream<<"Server: "<<playername
1952 <<" supplied invalid password hash"<<std::endl;
1953 SendAccessDenied(m_con, peer_id, L"Invalid password hash");
1957 std::string checkpwd; // Password hash to check against
1958 bool has_auth = scriptapi_get_auth(m_lua, playername, &checkpwd, NULL);
1960 // If no authentication info exists for user, create it
1962 if(!isSingleplayer() &&
1963 g_settings->getBool("disallow_empty_password") &&
1964 std::string(given_password) == ""){
1965 SendAccessDenied(m_con, peer_id, L"Empty passwords are "
1966 L"disallowed. Set a password and try again.");
1969 std::wstring raw_default_password =
1970 narrow_to_wide(g_settings->get("default_password"));
1971 std::string initial_password =
1972 translatePassword(playername, raw_default_password);
1974 // If default_password is empty, allow any initial password
1975 if (raw_default_password.length() == 0)
1976 initial_password = given_password;
1978 scriptapi_create_auth(m_lua, playername, initial_password);
1981 has_auth = scriptapi_get_auth(m_lua, playername, &checkpwd, NULL);
1984 SendAccessDenied(m_con, peer_id, L"Not allowed to login");
1988 if(given_password != checkpwd){
1989 infostream<<"Server: peer_id="<<peer_id
1990 <<": supplied invalid password for "
1991 <<playername<<std::endl;
1992 SendAccessDenied(m_con, peer_id, L"Invalid password");
1996 // Do not allow multiple players in simple singleplayer mode.
1997 // This isn't a perfect way to do it, but will suffice for now.
1998 if(m_simple_singleplayer_mode && m_clients.size() > 1){
1999 infostream<<"Server: Not allowing another client to connect in"
2000 <<" simple singleplayer mode"<<std::endl;
2001 SendAccessDenied(m_con, peer_id,
2002 L"Running in simple singleplayer mode.");
2006 // Enforce user limit.
2007 // Don't enforce for users that have some admin right
2008 if(m_clients.size() >= g_settings->getU16("max_users") &&
2009 !checkPriv(playername, "server") &&
2010 !checkPriv(playername, "ban") &&
2011 !checkPriv(playername, "privs") &&
2012 !checkPriv(playername, "password") &&
2013 playername != g_settings->get("name"))
2015 actionstream<<"Server: "<<playername<<" tried to join, but there"
2016 <<" are already max_users="
2017 <<g_settings->getU16("max_users")<<" players."<<std::endl;
2018 SendAccessDenied(m_con, peer_id, L"Too many users.");
2023 PlayerSAO *playersao = emergePlayer(playername, peer_id);
2025 // If failed, cancel
2026 if(playersao == NULL)
2028 errorstream<<"Server: peer_id="<<peer_id
2029 <<": failed to emerge player"<<std::endl;
2034 Answer with a TOCLIENT_INIT
2037 SharedBuffer<u8> reply(2+1+6+8+4);
2038 writeU16(&reply[0], TOCLIENT_INIT);
2039 writeU8(&reply[2], deployed);
2040 writeV3S16(&reply[2+1], floatToInt(playersao->getPlayer()->getPosition()+v3f(0,BS/2,0), BS));
2041 writeU64(&reply[2+1+6], m_env->getServerMap().getSeed());
2042 writeF1000(&reply[2+1+6+8], g_settings->getFloat("dedicated_server_step"));
2045 m_con.Send(peer_id, 0, reply, true);
2049 Send complete position information
2051 SendMovePlayer(peer_id);
2056 if(command == TOSERVER_INIT2)
2058 verbosestream<<"Server: Got TOSERVER_INIT2 from "
2059 <<peer_id<<std::endl;
2061 Player *player = m_env->getPlayer(peer_id);
2063 verbosestream<<"Server: TOSERVER_INIT2: "
2064 <<"Player not found; ignoring."<<std::endl;
2068 RemoteClient *client = getClient(peer_id);
2069 client->serialization_version =
2070 getClient(peer_id)->pending_serialization_version;
2073 Send some initialization data
2076 infostream<<"Server: Sending content to "
2077 <<getPlayerName(peer_id)<<std::endl;
2079 // Send player movement settings
2080 SendMovement(m_con, peer_id);
2082 // Send item definitions
2083 SendItemDef(m_con, peer_id, m_itemdef, client->net_proto_version);
2085 // Send node definitions
2086 SendNodeDef(m_con, peer_id, m_nodedef, client->net_proto_version);
2088 // Send media announcement
2089 sendMediaAnnouncement(peer_id);
2092 SendPlayerPrivileges(peer_id);
2094 // Send inventory formspec
2095 SendPlayerInventoryFormspec(peer_id);
2098 UpdateCrafting(peer_id);
2099 SendInventory(peer_id);
2102 if(g_settings->getBool("enable_damage"))
2103 SendPlayerHP(peer_id);
2105 // Send detached inventories
2106 sendDetachedInventories(peer_id);
2108 // Show death screen if necessary
2110 SendDeathscreen(m_con, peer_id, false, v3f(0,0,0));
2114 SharedBuffer<u8> data = makePacket_TOCLIENT_TIME_OF_DAY(
2115 m_env->getTimeOfDay(), g_settings->getFloat("time_speed"));
2116 m_con.Send(peer_id, 0, data, true);
2119 // Note things in chat if not in simple singleplayer mode
2120 if(!m_simple_singleplayer_mode)
2122 // Send information about server to player in chat
2123 SendChatMessage(peer_id, getStatusString());
2125 // Send information about joining in chat
2127 std::wstring name = L"unknown";
2128 Player *player = m_env->getPlayer(peer_id);
2130 name = narrow_to_wide(player->getName());
2132 std::wstring message;
2135 message += L" joined the game.";
2136 BroadcastChatMessage(message);
2140 // Warnings about protocol version can be issued here
2141 if(getClient(peer_id)->net_proto_version < LATEST_PROTOCOL_VERSION)
2143 SendChatMessage(peer_id, L"# Server: WARNING: YOUR CLIENT'S "
2144 L"VERSION MAY NOT BE FULLY COMPATIBLE WITH THIS SERVER!");
2151 std::ostringstream os(std::ios_base::binary);
2152 for(std::map<u16, RemoteClient*>::iterator
2153 i = m_clients.begin();
2154 i != m_clients.end(); ++i)
2156 RemoteClient *client = i->second;
2157 assert(client->peer_id == i->first);
2158 if(client->serialization_version == SER_FMT_VER_INVALID)
2161 Player *player = m_env->getPlayer(client->peer_id);
2164 // Get name of player
2165 os<<player->getName()<<" ";
2168 actionstream<<player->getName()<<" joins game. List of players: "
2169 <<os.str()<<std::endl;
2175 if(peer_ser_ver == SER_FMT_VER_INVALID)
2177 infostream<<"Server::ProcessData(): Cancelling: Peer"
2178 " serialization format invalid or not initialized."
2179 " Skipping incoming command="<<command<<std::endl;
2183 Player *player = m_env->getPlayer(peer_id);
2185 infostream<<"Server::ProcessData(): Cancelling: "
2186 "No player for peer_id="<<peer_id
2191 PlayerSAO *playersao = player->getPlayerSAO();
2192 if(playersao == NULL){
2193 infostream<<"Server::ProcessData(): Cancelling: "
2194 "No player object for peer_id="<<peer_id
2199 if(command == TOSERVER_PLAYERPOS)
2201 if(datasize < 2+12+12+4+4)
2205 v3s32 ps = readV3S32(&data[start+2]);
2206 v3s32 ss = readV3S32(&data[start+2+12]);
2207 f32 pitch = (f32)readS32(&data[2+12+12]) / 100.0;
2208 f32 yaw = (f32)readS32(&data[2+12+12+4]) / 100.0;
2210 if(datasize >= 2+12+12+4+4+4)
2211 keyPressed = (u32)readU32(&data[2+12+12+4+4]);
2212 v3f position((f32)ps.X/100., (f32)ps.Y/100., (f32)ps.Z/100.);
2213 v3f speed((f32)ss.X/100., (f32)ss.Y/100., (f32)ss.Z/100.);
2214 pitch = wrapDegrees(pitch);
2215 yaw = wrapDegrees(yaw);
2217 player->setPosition(position);
2218 player->setSpeed(speed);
2219 player->setPitch(pitch);
2220 player->setYaw(yaw);
2221 player->keyPressed=keyPressed;
2222 player->control.up = (bool)(keyPressed&1);
2223 player->control.down = (bool)(keyPressed&2);
2224 player->control.left = (bool)(keyPressed&4);
2225 player->control.right = (bool)(keyPressed&8);
2226 player->control.jump = (bool)(keyPressed&16);
2227 player->control.aux1 = (bool)(keyPressed&32);
2228 player->control.sneak = (bool)(keyPressed&64);
2229 player->control.LMB = (bool)(keyPressed&128);
2230 player->control.RMB = (bool)(keyPressed&256);
2232 /*infostream<<"Server::ProcessData(): Moved player "<<peer_id<<" to "
2233 <<"("<<position.X<<","<<position.Y<<","<<position.Z<<")"
2234 <<" pitch="<<pitch<<" yaw="<<yaw<<std::endl;*/
2236 else if(command == TOSERVER_GOTBLOCKS)
2249 u16 count = data[2];
2250 for(u16 i=0; i<count; i++)
2252 if((s16)datasize < 2+1+(i+1)*6)
2253 throw con::InvalidIncomingDataException
2254 ("GOTBLOCKS length is too short");
2255 v3s16 p = readV3S16(&data[2+1+i*6]);
2256 /*infostream<<"Server: GOTBLOCKS ("
2257 <<p.X<<","<<p.Y<<","<<p.Z<<")"<<std::endl;*/
2258 RemoteClient *client = getClient(peer_id);
2259 client->GotBlock(p);
2262 else if(command == TOSERVER_DELETEDBLOCKS)
2275 u16 count = data[2];
2276 for(u16 i=0; i<count; i++)
2278 if((s16)datasize < 2+1+(i+1)*6)
2279 throw con::InvalidIncomingDataException
2280 ("DELETEDBLOCKS length is too short");
2281 v3s16 p = readV3S16(&data[2+1+i*6]);
2282 /*infostream<<"Server: DELETEDBLOCKS ("
2283 <<p.X<<","<<p.Y<<","<<p.Z<<")"<<std::endl;*/
2284 RemoteClient *client = getClient(peer_id);
2285 client->SetBlockNotSent(p);
2288 else if(command == TOSERVER_CLICK_OBJECT)
2290 infostream<<"Server: CLICK_OBJECT not supported anymore"<<std::endl;
2293 else if(command == TOSERVER_CLICK_ACTIVEOBJECT)
2295 infostream<<"Server: CLICK_ACTIVEOBJECT not supported anymore"<<std::endl;
2298 else if(command == TOSERVER_GROUND_ACTION)
2300 infostream<<"Server: GROUND_ACTION not supported anymore"<<std::endl;
2304 else if(command == TOSERVER_RELEASE)
2306 infostream<<"Server: RELEASE not supported anymore"<<std::endl;
2309 else if(command == TOSERVER_SIGNTEXT)
2311 infostream<<"Server: SIGNTEXT not supported anymore"
2315 else if(command == TOSERVER_SIGNNODETEXT)
2317 infostream<<"Server: SIGNNODETEXT not supported anymore"
2321 else if(command == TOSERVER_INVENTORY_ACTION)
2323 // Strip command and create a stream
2324 std::string datastring((char*)&data[2], datasize-2);
2325 verbosestream<<"TOSERVER_INVENTORY_ACTION: data="<<datastring<<std::endl;
2326 std::istringstream is(datastring, std::ios_base::binary);
2328 InventoryAction *a = InventoryAction::deSerialize(is);
2331 infostream<<"TOSERVER_INVENTORY_ACTION: "
2332 <<"InventoryAction::deSerialize() returned NULL"
2337 // If something goes wrong, this player is to blame
2338 RollbackScopeActor rollback_scope(m_rollback,
2339 std::string("player:")+player->getName());
2342 Note: Always set inventory not sent, to repair cases
2343 where the client made a bad prediction.
2347 Handle restrictions and special cases of the move action
2349 if(a->getType() == IACTION_MOVE)
2351 IMoveAction *ma = (IMoveAction*)a;
2353 ma->from_inv.applyCurrentPlayer(player->getName());
2354 ma->to_inv.applyCurrentPlayer(player->getName());
2356 setInventoryModified(ma->from_inv);
2357 setInventoryModified(ma->to_inv);
2359 bool from_inv_is_current_player =
2360 (ma->from_inv.type == InventoryLocation::PLAYER) &&
2361 (ma->from_inv.name == player->getName());
2363 bool to_inv_is_current_player =
2364 (ma->to_inv.type == InventoryLocation::PLAYER) &&
2365 (ma->to_inv.name == player->getName());
2368 Disable moving items out of craftpreview
2370 if(ma->from_list == "craftpreview")
2372 infostream<<"Ignoring IMoveAction from "
2373 <<(ma->from_inv.dump())<<":"<<ma->from_list
2374 <<" to "<<(ma->to_inv.dump())<<":"<<ma->to_list
2375 <<" because src is "<<ma->from_list<<std::endl;
2381 Disable moving items into craftresult and craftpreview
2383 if(ma->to_list == "craftpreview" || ma->to_list == "craftresult")
2385 infostream<<"Ignoring IMoveAction from "
2386 <<(ma->from_inv.dump())<<":"<<ma->from_list
2387 <<" to "<<(ma->to_inv.dump())<<":"<<ma->to_list
2388 <<" because dst is "<<ma->to_list<<std::endl;
2393 // Disallow moving items in elsewhere than player's inventory
2394 // if not allowed to interact
2395 if(!checkPriv(player->getName(), "interact") &&
2396 (!from_inv_is_current_player ||
2397 !to_inv_is_current_player))
2399 infostream<<"Cannot move outside of player's inventory: "
2400 <<"No interact privilege"<<std::endl;
2406 Handle restrictions and special cases of the drop action
2408 else if(a->getType() == IACTION_DROP)
2410 IDropAction *da = (IDropAction*)a;
2412 da->from_inv.applyCurrentPlayer(player->getName());
2414 setInventoryModified(da->from_inv);
2416 // Disallow dropping items if not allowed to interact
2417 if(!checkPriv(player->getName(), "interact"))
2424 Handle restrictions and special cases of the craft action
2426 else if(a->getType() == IACTION_CRAFT)
2428 ICraftAction *ca = (ICraftAction*)a;
2430 ca->craft_inv.applyCurrentPlayer(player->getName());
2432 setInventoryModified(ca->craft_inv);
2434 //bool craft_inv_is_current_player =
2435 // (ca->craft_inv.type == InventoryLocation::PLAYER) &&
2436 // (ca->craft_inv.name == player->getName());
2438 // Disallow crafting if not allowed to interact
2439 if(!checkPriv(player->getName(), "interact"))
2441 infostream<<"Cannot craft: "
2442 <<"No interact privilege"<<std::endl;
2449 a->apply(this, playersao, this);
2453 else if(command == TOSERVER_CHAT_MESSAGE)
2461 std::string datastring((char*)&data[2], datasize-2);
2462 std::istringstream is(datastring, std::ios_base::binary);
2465 is.read((char*)buf, 2);
2466 u16 len = readU16(buf);
2468 std::wstring message;
2469 for(u16 i=0; i<len; i++)
2471 is.read((char*)buf, 2);
2472 message += (wchar_t)readU16(buf);
2475 // If something goes wrong, this player is to blame
2476 RollbackScopeActor rollback_scope(m_rollback,
2477 std::string("player:")+player->getName());
2479 // Get player name of this client
2480 std::wstring name = narrow_to_wide(player->getName());
2483 bool ate = scriptapi_on_chat_message(m_lua, player->getName(),
2484 wide_to_narrow(message));
2485 // If script ate the message, don't proceed
2489 // Line to send to players
2491 // Whether to send to the player that sent the line
2492 bool send_to_sender = false;
2493 // Whether to send to other players
2494 bool send_to_others = false;
2496 // Commands are implemented in Lua, so only catch invalid
2497 // commands that were not "eaten" and send an error back
2498 if(message[0] == L'/')
2500 message = message.substr(1);
2501 send_to_sender = true;
2502 if(message.length() == 0)
2503 line += L"-!- Empty command";
2505 line += L"-!- Invalid command: " + str_split(message, L' ')[0];
2509 if(checkPriv(player->getName(), "shout")){
2514 send_to_others = true;
2516 line += L"-!- You don't have permission to shout.";
2517 send_to_sender = true;
2524 actionstream<<"CHAT: "<<wide_to_narrow(line)<<std::endl;
2527 Send the message to clients
2529 for(std::map<u16, RemoteClient*>::iterator
2530 i = m_clients.begin();
2531 i != m_clients.end(); ++i)
2533 // Get client and check that it is valid
2534 RemoteClient *client = i->second;
2535 assert(client->peer_id == i->first);
2536 if(client->serialization_version == SER_FMT_VER_INVALID)
2540 bool sender_selected = (peer_id == client->peer_id);
2541 if(sender_selected == true && send_to_sender == false)
2543 if(sender_selected == false && send_to_others == false)
2546 SendChatMessage(client->peer_id, line);
2550 else if(command == TOSERVER_DAMAGE)
2552 std::string datastring((char*)&data[2], datasize-2);
2553 std::istringstream is(datastring, std::ios_base::binary);
2554 u8 damage = readU8(is);
2556 if(g_settings->getBool("enable_damage"))
2558 actionstream<<player->getName()<<" damaged by "
2559 <<(int)damage<<" hp at "<<PP(player->getPosition()/BS)
2562 playersao->setHP(playersao->getHP() - damage);
2564 if(playersao->getHP() == 0 && playersao->m_hp_not_sent)
2567 if(playersao->m_hp_not_sent)
2568 SendPlayerHP(peer_id);
2571 else if(command == TOSERVER_PASSWORD)
2574 [0] u16 TOSERVER_PASSWORD
2575 [2] u8[28] old password
2576 [30] u8[28] new password
2579 if(datasize != 2+PASSWORD_SIZE*2)
2581 /*char password[PASSWORD_SIZE];
2582 for(u32 i=0; i<PASSWORD_SIZE-1; i++)
2583 password[i] = data[2+i];
2584 password[PASSWORD_SIZE-1] = 0;*/
2586 for(u32 i=0; i<PASSWORD_SIZE-1; i++)
2594 for(u32 i=0; i<PASSWORD_SIZE-1; i++)
2596 char c = data[2+PASSWORD_SIZE+i];
2602 if(!base64_is_valid(newpwd)){
2603 infostream<<"Server: "<<player->getName()<<" supplied invalid password hash"<<std::endl;
2604 // Wrong old password supplied!!
2605 SendChatMessage(peer_id, L"Invalid new password hash supplied. Password NOT changed.");
2609 infostream<<"Server: Client requests a password change from "
2610 <<"'"<<oldpwd<<"' to '"<<newpwd<<"'"<<std::endl;
2612 std::string playername = player->getName();
2614 std::string checkpwd;
2615 scriptapi_get_auth(m_lua, playername, &checkpwd, NULL);
2617 if(oldpwd != checkpwd)
2619 infostream<<"Server: invalid old password"<<std::endl;
2620 // Wrong old password supplied!!
2621 SendChatMessage(peer_id, L"Invalid old password supplied. Password NOT changed.");
2625 bool success = scriptapi_set_password(m_lua, playername, newpwd);
2627 actionstream<<player->getName()<<" changes password"<<std::endl;
2628 SendChatMessage(peer_id, L"Password change successful.");
2630 actionstream<<player->getName()<<" tries to change password but "
2631 <<"it fails"<<std::endl;
2632 SendChatMessage(peer_id, L"Password change failed or inavailable.");
2635 else if(command == TOSERVER_PLAYERITEM)
2640 u16 item = readU16(&data[2]);
2641 playersao->setWieldIndex(item);
2643 else if(command == TOSERVER_RESPAWN)
2645 if(player->hp != 0 || !g_settings->getBool("enable_damage"))
2648 RespawnPlayer(peer_id);
2650 actionstream<<player->getName()<<" respawns at "
2651 <<PP(player->getPosition()/BS)<<std::endl;
2653 // ActiveObject is added to environment in AsyncRunStep after
2654 // the previous addition has been succesfully removed
2656 else if(command == TOSERVER_REQUEST_MEDIA) {
2657 std::string datastring((char*)&data[2], datasize-2);
2658 std::istringstream is(datastring, std::ios_base::binary);
2660 std::list<MediaRequest> tosend;
2661 u16 numfiles = readU16(is);
2663 infostream<<"Sending "<<numfiles<<" files to "
2664 <<getPlayerName(peer_id)<<std::endl;
2665 verbosestream<<"TOSERVER_REQUEST_MEDIA: "<<std::endl;
2667 for(int i = 0; i < numfiles; i++) {
2668 std::string name = deSerializeString(is);
2669 tosend.push_back(MediaRequest(name));
2670 verbosestream<<"TOSERVER_REQUEST_MEDIA: requested file "
2674 sendRequestedMedia(peer_id, tosend);
2676 // Now the client should know about everything
2677 // (definitions and files)
2678 getClient(peer_id)->definitions_sent = true;
2680 else if(command == TOSERVER_RECEIVED_MEDIA) {
2681 getClient(peer_id)->definitions_sent = true;
2683 else if(command == TOSERVER_INTERACT)
2685 std::string datastring((char*)&data[2], datasize-2);
2686 std::istringstream is(datastring, std::ios_base::binary);
2692 [5] u32 length of the next item
2693 [9] serialized PointedThing
2695 0: start digging (from undersurface) or use
2696 1: stop digging (all parameters ignored)
2697 2: digging completed
2698 3: place block or item (to abovesurface)
2701 u8 action = readU8(is);
2702 u16 item_i = readU16(is);
2703 std::istringstream tmp_is(deSerializeLongString(is), std::ios::binary);
2704 PointedThing pointed;
2705 pointed.deSerialize(tmp_is);
2707 verbosestream<<"TOSERVER_INTERACT: action="<<(int)action<<", item="
2708 <<item_i<<", pointed="<<pointed.dump()<<std::endl;
2712 verbosestream<<"TOSERVER_INTERACT: "<<player->getName()
2713 <<" tried to interact, but is dead!"<<std::endl;
2717 v3f player_pos = playersao->getLastGoodPosition();
2719 // Update wielded item
2720 playersao->setWieldIndex(item_i);
2722 // Get pointed to node (undefined if not POINTEDTYPE_NODE)
2723 v3s16 p_under = pointed.node_undersurface;
2724 v3s16 p_above = pointed.node_abovesurface;
2726 // Get pointed to object (NULL if not POINTEDTYPE_OBJECT)
2727 ServerActiveObject *pointed_object = NULL;
2728 if(pointed.type == POINTEDTHING_OBJECT)
2730 pointed_object = m_env->getActiveObject(pointed.object_id);
2731 if(pointed_object == NULL)
2733 verbosestream<<"TOSERVER_INTERACT: "
2734 "pointed object is NULL"<<std::endl;
2740 v3f pointed_pos_under = player_pos;
2741 v3f pointed_pos_above = player_pos;
2742 if(pointed.type == POINTEDTHING_NODE)
2744 pointed_pos_under = intToFloat(p_under, BS);
2745 pointed_pos_above = intToFloat(p_above, BS);
2747 else if(pointed.type == POINTEDTHING_OBJECT)
2749 pointed_pos_under = pointed_object->getBasePosition();
2750 pointed_pos_above = pointed_pos_under;
2754 Check that target is reasonably close
2755 (only when digging or placing things)
2757 if(action == 0 || action == 2 || action == 3)
2759 float d = player_pos.getDistanceFrom(pointed_pos_under);
2760 float max_d = BS * 14; // Just some large enough value
2762 actionstream<<"Player "<<player->getName()
2763 <<" tried to access "<<pointed.dump()
2765 <<"d="<<d<<", max_d="<<max_d
2766 <<". ignoring."<<std::endl;
2767 // Re-send block to revert change on client-side
2768 RemoteClient *client = getClient(peer_id);
2769 v3s16 blockpos = getNodeBlockPos(floatToInt(pointed_pos_under, BS));
2770 client->SetBlockNotSent(blockpos);
2777 Make sure the player is allowed to do it
2779 if(!checkPriv(player->getName(), "interact"))
2781 actionstream<<player->getName()<<" attempted to interact with "
2782 <<pointed.dump()<<" without 'interact' privilege"
2784 // Re-send block to revert change on client-side
2785 RemoteClient *client = getClient(peer_id);
2786 // Digging completed -> under
2788 v3s16 blockpos = getNodeBlockPos(floatToInt(pointed_pos_under, BS));
2789 client->SetBlockNotSent(blockpos);
2791 // Placement -> above
2793 v3s16 blockpos = getNodeBlockPos(floatToInt(pointed_pos_above, BS));
2794 client->SetBlockNotSent(blockpos);
2800 If something goes wrong, this player is to blame
2802 RollbackScopeActor rollback_scope(m_rollback,
2803 std::string("player:")+player->getName());
2806 0: start digging or punch object
2810 if(pointed.type == POINTEDTHING_NODE)
2813 NOTE: This can be used in the future to check if
2814 somebody is cheating, by checking the timing.
2816 MapNode n(CONTENT_IGNORE);
2819 n = m_env->getMap().getNode(p_under);
2821 catch(InvalidPositionException &e)
2823 infostream<<"Server: Not punching: Node not found."
2824 <<" Adding block to emerge queue."
2826 m_emerge->enqueueBlockEmerge(peer_id, getNodeBlockPos(p_above), false);
2828 if(n.getContent() != CONTENT_IGNORE)
2829 scriptapi_node_on_punch(m_lua, p_under, n, playersao);
2831 playersao->noCheatDigStart(p_under);
2833 else if(pointed.type == POINTEDTHING_OBJECT)
2835 // Skip if object has been removed
2836 if(pointed_object->m_removed)
2839 actionstream<<player->getName()<<" punches object "
2840 <<pointed.object_id<<": "
2841 <<pointed_object->getDescription()<<std::endl;
2843 ItemStack punchitem = playersao->getWieldedItem();
2844 ToolCapabilities toolcap =
2845 punchitem.getToolCapabilities(m_itemdef);
2846 v3f dir = (pointed_object->getBasePosition() -
2847 (player->getPosition() + player->getEyeOffset())
2849 float time_from_last_punch =
2850 playersao->resetTimeFromLastPunch();
2851 pointed_object->punch(dir, &toolcap, playersao,
2852 time_from_last_punch);
2860 else if(action == 1)
2865 2: Digging completed
2867 else if(action == 2)
2869 // Only digging of nodes
2870 if(pointed.type == POINTEDTHING_NODE)
2872 MapNode n(CONTENT_IGNORE);
2875 n = m_env->getMap().getNode(p_under);
2877 catch(InvalidPositionException &e)
2879 infostream<<"Server: Not finishing digging: Node not found."
2880 <<" Adding block to emerge queue."
2882 m_emerge->enqueueBlockEmerge(peer_id, getNodeBlockPos(p_above), false);
2885 /* Cheat prevention */
2886 bool is_valid_dig = true;
2887 if(!isSingleplayer() && !g_settings->getBool("disable_anticheat"))
2889 v3s16 nocheat_p = playersao->getNoCheatDigPos();
2890 float nocheat_t = playersao->getNoCheatDigTime();
2891 playersao->noCheatDigEnd();
2892 // If player didn't start digging this, ignore dig
2893 if(nocheat_p != p_under){
2894 infostream<<"Server: NoCheat: "<<player->getName()
2895 <<" started digging "
2896 <<PP(nocheat_p)<<" and completed digging "
2897 <<PP(p_under)<<"; not digging."<<std::endl;
2898 is_valid_dig = false;
2900 // Get player's wielded item
2901 ItemStack playeritem;
2902 InventoryList *mlist = playersao->getInventory()->getList("main");
2904 playeritem = mlist->getItem(playersao->getWieldIndex());
2905 ToolCapabilities playeritem_toolcap =
2906 playeritem.getToolCapabilities(m_itemdef);
2907 // Get diggability and expected digging time
2908 DigParams params = getDigParams(m_nodedef->get(n).groups,
2909 &playeritem_toolcap);
2910 // If can't dig, try hand
2911 if(!params.diggable){
2912 const ItemDefinition &hand = m_itemdef->get("");
2913 const ToolCapabilities *tp = hand.tool_capabilities;
2915 params = getDigParams(m_nodedef->get(n).groups, tp);
2917 // If can't dig, ignore dig
2918 if(!params.diggable){
2919 infostream<<"Server: NoCheat: "<<player->getName()
2920 <<" completed digging "<<PP(p_under)
2921 <<", which is not diggable with tool. not digging."
2923 is_valid_dig = false;
2925 // If time is considerably too short, ignore dig
2926 // Check time only for medium and slow timed digs
2927 if(params.diggable && params.time > 0.3 && nocheat_t < 0.5 * params.time){
2928 infostream<<"Server: NoCheat: "<<player->getName()
2929 <<" completed digging "
2930 <<PP(p_under)<<" in "<<nocheat_t<<"s; expected "
2931 <<params.time<<"s; not digging."<<std::endl;
2932 is_valid_dig = false;
2936 /* Actually dig node */
2938 if(is_valid_dig && n.getContent() != CONTENT_IGNORE)
2939 scriptapi_node_on_dig(m_lua, p_under, n, playersao);
2941 // Send unusual result (that is, node not being removed)
2942 if(m_env->getMap().getNodeNoEx(p_under).getContent() != CONTENT_AIR)
2944 // Re-send block to revert change on client-side
2945 RemoteClient *client = getClient(peer_id);
2946 v3s16 blockpos = getNodeBlockPos(floatToInt(pointed_pos_under, BS));
2947 client->SetBlockNotSent(blockpos);
2953 3: place block or right-click object
2955 else if(action == 3)
2957 ItemStack item = playersao->getWieldedItem();
2959 // Reset build time counter
2960 if(pointed.type == POINTEDTHING_NODE &&
2961 item.getDefinition(m_itemdef).type == ITEM_NODE)
2962 getClient(peer_id)->m_time_from_building = 0.0;
2964 if(pointed.type == POINTEDTHING_OBJECT)
2966 // Right click object
2968 // Skip if object has been removed
2969 if(pointed_object->m_removed)
2972 actionstream<<player->getName()<<" right-clicks object "
2973 <<pointed.object_id<<": "
2974 <<pointed_object->getDescription()<<std::endl;
2977 pointed_object->rightClick(playersao);
2979 else if(scriptapi_item_on_place(m_lua,
2980 item, playersao, pointed))
2982 // Placement was handled in lua
2984 // Apply returned ItemStack
2985 playersao->setWieldedItem(item);
2988 // If item has node placement prediction, always send the above
2989 // node to make sure the client knows what exactly happened
2990 if(item.getDefinition(m_itemdef).node_placement_prediction != ""){
2991 RemoteClient *client = getClient(peer_id);
2992 v3s16 blockpos = getNodeBlockPos(floatToInt(pointed_pos_above, BS));
2993 client->SetBlockNotSent(blockpos);
3000 else if(action == 4)
3002 ItemStack item = playersao->getWieldedItem();
3004 actionstream<<player->getName()<<" uses "<<item.name
3005 <<", pointing at "<<pointed.dump()<<std::endl;
3007 if(scriptapi_item_on_use(m_lua,
3008 item, playersao, pointed))
3010 // Apply returned ItemStack
3011 playersao->setWieldedItem(item);
3018 Catch invalid actions
3022 infostream<<"WARNING: Server: Invalid action "
3023 <<action<<std::endl;
3026 else if(command == TOSERVER_REMOVED_SOUNDS)
3028 std::string datastring((char*)&data[2], datasize-2);
3029 std::istringstream is(datastring, std::ios_base::binary);
3031 int num = readU16(is);
3032 for(int k=0; k<num; k++){
3033 s32 id = readS32(is);
3034 std::map<s32, ServerPlayingSound>::iterator i =
3035 m_playing_sounds.find(id);
3036 if(i == m_playing_sounds.end())
3038 ServerPlayingSound &psound = i->second;
3039 psound.clients.erase(peer_id);
3040 if(psound.clients.size() == 0)
3041 m_playing_sounds.erase(i++);
3044 else if(command == TOSERVER_NODEMETA_FIELDS)
3046 std::string datastring((char*)&data[2], datasize-2);
3047 std::istringstream is(datastring, std::ios_base::binary);
3049 v3s16 p = readV3S16(is);
3050 std::string formname = deSerializeString(is);
3051 int num = readU16(is);
3052 std::map<std::string, std::string> fields;
3053 for(int k=0; k<num; k++){
3054 std::string fieldname = deSerializeString(is);
3055 std::string fieldvalue = deSerializeLongString(is);
3056 fields[fieldname] = fieldvalue;
3059 // If something goes wrong, this player is to blame
3060 RollbackScopeActor rollback_scope(m_rollback,
3061 std::string("player:")+player->getName());
3063 // Check the target node for rollback data; leave others unnoticed
3064 RollbackNode rn_old(&m_env->getMap(), p, this);
3066 scriptapi_node_on_receive_fields(m_lua, p, formname, fields,
3069 // Report rollback data
3070 RollbackNode rn_new(&m_env->getMap(), p, this);
3071 if(rollback() && rn_new != rn_old){
3072 RollbackAction action;
3073 action.setSetNode(p, rn_old, rn_new);
3074 rollback()->reportAction(action);
3077 else if(command == TOSERVER_INVENTORY_FIELDS)
3079 std::string datastring((char*)&data[2], datasize-2);
3080 std::istringstream is(datastring, std::ios_base::binary);
3082 std::string formname = deSerializeString(is);
3083 int num = readU16(is);
3084 std::map<std::string, std::string> fields;
3085 for(int k=0; k<num; k++){
3086 std::string fieldname = deSerializeString(is);
3087 std::string fieldvalue = deSerializeLongString(is);
3088 fields[fieldname] = fieldvalue;
3091 scriptapi_on_player_receive_fields(m_lua, playersao, formname, fields);
3095 infostream<<"Server::ProcessData(): Ignoring "
3096 "unknown command "<<command<<std::endl;
3100 catch(SendFailedException &e)
3102 errorstream<<"Server::ProcessData(): SendFailedException: "
3108 void Server::onMapEditEvent(MapEditEvent *event)
3110 //infostream<<"Server::onMapEditEvent()"<<std::endl;
3111 if(m_ignore_map_edit_events)
3113 if(m_ignore_map_edit_events_area.contains(event->getArea()))
3115 MapEditEvent *e = event->clone();
3116 m_unsent_map_edit_queue.push_back(e);
3119 Inventory* Server::getInventory(const InventoryLocation &loc)
3122 case InventoryLocation::UNDEFINED:
3125 case InventoryLocation::CURRENT_PLAYER:
3128 case InventoryLocation::PLAYER:
3130 Player *player = m_env->getPlayer(loc.name.c_str());
3133 PlayerSAO *playersao = player->getPlayerSAO();
3136 return playersao->getInventory();
3139 case InventoryLocation::NODEMETA:
3141 NodeMetadata *meta = m_env->getMap().getNodeMetadata(loc.p);
3144 return meta->getInventory();
3147 case InventoryLocation::DETACHED:
3149 if(m_detached_inventories.count(loc.name) == 0)
3151 return m_detached_inventories[loc.name];
3159 void Server::setInventoryModified(const InventoryLocation &loc)
3162 case InventoryLocation::UNDEFINED:
3165 case InventoryLocation::PLAYER:
3167 Player *player = m_env->getPlayer(loc.name.c_str());
3170 PlayerSAO *playersao = player->getPlayerSAO();
3173 playersao->m_inventory_not_sent = true;
3174 playersao->m_wielded_item_not_sent = true;
3177 case InventoryLocation::NODEMETA:
3179 v3s16 blockpos = getNodeBlockPos(loc.p);
3181 MapBlock *block = m_env->getMap().getBlockNoCreateNoEx(blockpos);
3183 block->raiseModified(MOD_STATE_WRITE_NEEDED);
3185 setBlockNotSent(blockpos);
3188 case InventoryLocation::DETACHED:
3190 sendDetachedInventoryToAll(loc.name);
3198 std::list<PlayerInfo> Server::getPlayerInfo()
3200 DSTACK(__FUNCTION_NAME);
3201 JMutexAutoLock envlock(m_env_mutex);
3202 JMutexAutoLock conlock(m_con_mutex);
3204 std::list<PlayerInfo> list;
3206 std::list<Player*> players = m_env->getPlayers();
3208 std::list<Player*>::iterator i;
3209 for(i = players.begin();
3210 i != players.end(); ++i)
3214 Player *player = *i;
3217 // Copy info from connection to info struct
3218 info.id = player->peer_id;
3219 info.address = m_con.GetPeerAddress(player->peer_id);
3220 info.avg_rtt = m_con.GetPeerAvgRTT(player->peer_id);
3222 catch(con::PeerNotFoundException &e)
3224 // Set dummy peer info
3226 info.address = Address(0,0,0,0,0);
3230 snprintf(info.name, PLAYERNAME_SIZE, "%s", player->getName());
3231 info.position = player->getPosition();
3233 list.push_back(info);
3240 void Server::peerAdded(con::Peer *peer)
3242 DSTACK(__FUNCTION_NAME);
3243 verbosestream<<"Server::peerAdded(): peer->id="
3244 <<peer->id<<std::endl;
3247 c.type = PEER_ADDED;
3248 c.peer_id = peer->id;
3250 m_peer_change_queue.push_back(c);
3253 void Server::deletingPeer(con::Peer *peer, bool timeout)
3255 DSTACK(__FUNCTION_NAME);
3256 verbosestream<<"Server::deletingPeer(): peer->id="
3257 <<peer->id<<", timeout="<<timeout<<std::endl;
3260 c.type = PEER_REMOVED;
3261 c.peer_id = peer->id;
3262 c.timeout = timeout;
3263 m_peer_change_queue.push_back(c);
3270 void Server::SendMovement(con::Connection &con, u16 peer_id)
3272 DSTACK(__FUNCTION_NAME);
3273 std::ostringstream os(std::ios_base::binary);
3275 writeU16(os, TOCLIENT_MOVEMENT);
3276 writeF1000(os, g_settings->getFloat("movement_acceleration_default"));
3277 writeF1000(os, g_settings->getFloat("movement_acceleration_air"));
3278 writeF1000(os, g_settings->getFloat("movement_acceleration_fast"));
3279 writeF1000(os, g_settings->getFloat("movement_speed_walk"));
3280 writeF1000(os, g_settings->getFloat("movement_speed_crouch"));
3281 writeF1000(os, g_settings->getFloat("movement_speed_fast"));
3282 writeF1000(os, g_settings->getFloat("movement_speed_climb"));
3283 writeF1000(os, g_settings->getFloat("movement_speed_jump"));
3284 writeF1000(os, g_settings->getFloat("movement_liquid_fluidity"));
3285 writeF1000(os, g_settings->getFloat("movement_liquid_fluidity_smooth"));
3286 writeF1000(os, g_settings->getFloat("movement_liquid_sink"));
3287 writeF1000(os, g_settings->getFloat("movement_gravity"));
3290 std::string s = os.str();
3291 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3293 con.Send(peer_id, 0, data, true);
3296 void Server::SendHP(con::Connection &con, u16 peer_id, u8 hp)
3298 DSTACK(__FUNCTION_NAME);
3299 std::ostringstream os(std::ios_base::binary);
3301 writeU16(os, TOCLIENT_HP);
3305 std::string s = os.str();
3306 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3308 con.Send(peer_id, 0, data, true);
3311 void Server::SendAccessDenied(con::Connection &con, u16 peer_id,
3312 const std::wstring &reason)
3314 DSTACK(__FUNCTION_NAME);
3315 std::ostringstream os(std::ios_base::binary);
3317 writeU16(os, TOCLIENT_ACCESS_DENIED);
3318 os<<serializeWideString(reason);
3321 std::string s = os.str();
3322 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3324 con.Send(peer_id, 0, data, true);
3327 void Server::SendDeathscreen(con::Connection &con, u16 peer_id,
3328 bool set_camera_point_target, v3f camera_point_target)
3330 DSTACK(__FUNCTION_NAME);
3331 std::ostringstream os(std::ios_base::binary);
3333 writeU16(os, TOCLIENT_DEATHSCREEN);
3334 writeU8(os, set_camera_point_target);
3335 writeV3F1000(os, camera_point_target);
3338 std::string s = os.str();
3339 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3341 con.Send(peer_id, 0, data, true);
3344 void Server::SendItemDef(con::Connection &con, u16 peer_id,
3345 IItemDefManager *itemdef, u16 protocol_version)
3347 DSTACK(__FUNCTION_NAME);
3348 std::ostringstream os(std::ios_base::binary);
3352 u32 length of the next item
3353 zlib-compressed serialized ItemDefManager
3355 writeU16(os, TOCLIENT_ITEMDEF);
3356 std::ostringstream tmp_os(std::ios::binary);
3357 itemdef->serialize(tmp_os, protocol_version);
3358 std::ostringstream tmp_os2(std::ios::binary);
3359 compressZlib(tmp_os.str(), tmp_os2);
3360 os<<serializeLongString(tmp_os2.str());
3363 std::string s = os.str();
3364 verbosestream<<"Server: Sending item definitions to id("<<peer_id
3365 <<"): size="<<s.size()<<std::endl;
3366 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3368 con.Send(peer_id, 0, data, true);
3371 void Server::SendNodeDef(con::Connection &con, u16 peer_id,
3372 INodeDefManager *nodedef, u16 protocol_version)
3374 DSTACK(__FUNCTION_NAME);
3375 std::ostringstream os(std::ios_base::binary);
3379 u32 length of the next item
3380 zlib-compressed serialized NodeDefManager
3382 writeU16(os, TOCLIENT_NODEDEF);
3383 std::ostringstream tmp_os(std::ios::binary);
3384 nodedef->serialize(tmp_os, protocol_version);
3385 std::ostringstream tmp_os2(std::ios::binary);
3386 compressZlib(tmp_os.str(), tmp_os2);
3387 os<<serializeLongString(tmp_os2.str());
3390 std::string s = os.str();
3391 verbosestream<<"Server: Sending node definitions to id("<<peer_id
3392 <<"): size="<<s.size()<<std::endl;
3393 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3395 con.Send(peer_id, 0, data, true);
3399 Non-static send methods
3402 void Server::SendInventory(u16 peer_id)
3404 DSTACK(__FUNCTION_NAME);
3406 PlayerSAO *playersao = getPlayerSAO(peer_id);
3409 playersao->m_inventory_not_sent = false;
3415 std::ostringstream os;
3416 playersao->getInventory()->serialize(os);
3418 std::string s = os.str();
3420 SharedBuffer<u8> data(s.size()+2);
3421 writeU16(&data[0], TOCLIENT_INVENTORY);
3422 memcpy(&data[2], s.c_str(), s.size());
3425 m_con.Send(peer_id, 0, data, true);
3428 void Server::SendChatMessage(u16 peer_id, const std::wstring &message)
3430 DSTACK(__FUNCTION_NAME);
3432 std::ostringstream os(std::ios_base::binary);
3436 writeU16(buf, TOCLIENT_CHAT_MESSAGE);
3437 os.write((char*)buf, 2);
3440 writeU16(buf, message.size());
3441 os.write((char*)buf, 2);
3444 for(u32 i=0; i<message.size(); i++)
3448 os.write((char*)buf, 2);
3452 std::string s = os.str();
3453 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3455 m_con.Send(peer_id, 0, data, true);
3457 void Server::SendShowFormspecMessage(u16 peer_id, const std::string formspec, const std::string formname)
3459 DSTACK(__FUNCTION_NAME);
3461 std::ostringstream os(std::ios_base::binary);
3465 writeU16(buf, TOCLIENT_SHOW_FORMSPEC);
3466 os.write((char*)buf, 2);
3467 os<<serializeLongString(formspec);
3468 os<<serializeString(formname);
3471 std::string s = os.str();
3472 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3474 m_con.Send(peer_id, 0, data, true);
3477 // Spawns a particle on peer with peer_id
3478 void Server::SendSpawnParticle(u16 peer_id, v3f pos, v3f velocity, v3f acceleration, float expirationtime, float size, bool collisiondetection, std::string texture)
3480 DSTACK(__FUNCTION_NAME);
3482 std::ostringstream os(std::ios_base::binary);
3483 writeU16(os, TOCLIENT_SPAWN_PARTICLE);
3484 writeV3F1000(os, pos);
3485 writeV3F1000(os, velocity);
3486 writeV3F1000(os, acceleration);
3487 writeF1000(os, expirationtime);
3488 writeF1000(os, size);
3489 writeU8(os, collisiondetection);
3490 os<<serializeLongString(texture);
3493 std::string s = os.str();
3494 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3496 m_con.Send(peer_id, 0, data, true);
3499 // Spawns a particle on all peers
3500 void Server::SendSpawnParticleAll(v3f pos, v3f velocity, v3f acceleration, float expirationtime, float size, bool collisiondetection, std::string texture)
3502 for(std::map<u16, RemoteClient*>::iterator
3503 i = m_clients.begin();
3504 i != m_clients.end(); i++)
3506 // Get client and check that it is valid
3507 RemoteClient *client = i->second;
3508 assert(client->peer_id == i->first);
3509 if(client->serialization_version == SER_FMT_VER_INVALID)
3512 SendSpawnParticle(client->peer_id, pos, velocity, acceleration,
3513 expirationtime, size, collisiondetection, texture);
3517 // Adds a ParticleSpawner on peer with peer_id
3518 void Server::SendAddParticleSpawner(u16 peer_id, u16 amount, float spawntime, v3f minpos, v3f maxpos,
3519 v3f minvel, v3f maxvel, v3f minacc, v3f maxacc, float minexptime, float maxexptime,
3520 float minsize, float maxsize, bool collisiondetection, std::string texture, u32 id)
3522 DSTACK(__FUNCTION_NAME);
3524 std::ostringstream os(std::ios_base::binary);
3525 writeU16(os, TOCLIENT_ADD_PARTICLESPAWNER);
3527 writeU16(os, amount);
3528 writeF1000(os, spawntime);
3529 writeV3F1000(os, minpos);
3530 writeV3F1000(os, maxpos);
3531 writeV3F1000(os, minvel);
3532 writeV3F1000(os, maxvel);
3533 writeV3F1000(os, minacc);
3534 writeV3F1000(os, maxacc);
3535 writeF1000(os, minexptime);
3536 writeF1000(os, maxexptime);
3537 writeF1000(os, minsize);
3538 writeF1000(os, maxsize);
3539 writeU8(os, collisiondetection);
3540 os<<serializeLongString(texture);
3544 std::string s = os.str();
3545 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3547 m_con.Send(peer_id, 0, data, true);
3550 // Adds a ParticleSpawner on all peers
3551 void Server::SendAddParticleSpawnerAll(u16 amount, float spawntime, v3f minpos, v3f maxpos,
3552 v3f minvel, v3f maxvel, v3f minacc, v3f maxacc, float minexptime, float maxexptime,
3553 float minsize, float maxsize, bool collisiondetection, std::string texture, u32 id)
3555 for(std::map<u16, RemoteClient*>::iterator
3556 i = m_clients.begin();
3557 i != m_clients.end(); i++)
3559 // Get client and check that it is valid
3560 RemoteClient *client = i->second;
3561 assert(client->peer_id == i->first);
3562 if(client->serialization_version == SER_FMT_VER_INVALID)
3565 SendAddParticleSpawner(client->peer_id, amount, spawntime,
3566 minpos, maxpos, minvel, maxvel, minacc, maxacc,
3567 minexptime, maxexptime, minsize, maxsize, collisiondetection, texture, id);
3571 void Server::SendDeleteParticleSpawner(u16 peer_id, u32 id)
3573 DSTACK(__FUNCTION_NAME);
3575 std::ostringstream os(std::ios_base::binary);
3576 writeU16(os, TOCLIENT_DELETE_PARTICLESPAWNER);
3581 std::string s = os.str();
3582 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3584 m_con.Send(peer_id, 0, data, true);
3587 void Server::SendDeleteParticleSpawnerAll(u32 id)
3589 for(std::map<u16, RemoteClient*>::iterator
3590 i = m_clients.begin();
3591 i != m_clients.end(); i++)
3593 // Get client and check that it is valid
3594 RemoteClient *client = i->second;
3595 assert(client->peer_id == i->first);
3596 if(client->serialization_version == SER_FMT_VER_INVALID)
3599 SendDeleteParticleSpawner(client->peer_id, id);
3603 void Server::BroadcastChatMessage(const std::wstring &message)
3605 for(std::map<u16, RemoteClient*>::iterator
3606 i = m_clients.begin();
3607 i != m_clients.end(); ++i)
3609 // Get client and check that it is valid
3610 RemoteClient *client = i->second;
3611 assert(client->peer_id == i->first);
3612 if(client->serialization_version == SER_FMT_VER_INVALID)
3615 SendChatMessage(client->peer_id, message);
3619 void Server::SendPlayerHP(u16 peer_id)
3621 DSTACK(__FUNCTION_NAME);
3622 PlayerSAO *playersao = getPlayerSAO(peer_id);
3624 playersao->m_hp_not_sent = false;
3625 SendHP(m_con, peer_id, playersao->getHP());
3628 void Server::SendMovePlayer(u16 peer_id)
3630 DSTACK(__FUNCTION_NAME);
3631 Player *player = m_env->getPlayer(peer_id);
3634 std::ostringstream os(std::ios_base::binary);
3635 writeU16(os, TOCLIENT_MOVE_PLAYER);
3636 writeV3F1000(os, player->getPosition());
3637 writeF1000(os, player->getPitch());
3638 writeF1000(os, player->getYaw());
3641 v3f pos = player->getPosition();
3642 f32 pitch = player->getPitch();
3643 f32 yaw = player->getYaw();
3644 verbosestream<<"Server: Sending TOCLIENT_MOVE_PLAYER"
3645 <<" pos=("<<pos.X<<","<<pos.Y<<","<<pos.Z<<")"
3652 std::string s = os.str();
3653 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3655 m_con.Send(peer_id, 0, data, true);
3658 void Server::SendPlayerPrivileges(u16 peer_id)
3660 Player *player = m_env->getPlayer(peer_id);
3662 if(player->peer_id == PEER_ID_INEXISTENT)
3665 std::set<std::string> privs;
3666 scriptapi_get_auth(m_lua, player->getName(), NULL, &privs);
3668 std::ostringstream os(std::ios_base::binary);
3669 writeU16(os, TOCLIENT_PRIVILEGES);
3670 writeU16(os, privs.size());
3671 for(std::set<std::string>::const_iterator i = privs.begin();
3672 i != privs.end(); i++){
3673 os<<serializeString(*i);
3677 std::string s = os.str();
3678 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3680 m_con.Send(peer_id, 0, data, true);
3683 void Server::SendPlayerInventoryFormspec(u16 peer_id)
3685 Player *player = m_env->getPlayer(peer_id);
3687 if(player->peer_id == PEER_ID_INEXISTENT)
3690 std::ostringstream os(std::ios_base::binary);
3691 writeU16(os, TOCLIENT_INVENTORY_FORMSPEC);
3692 os<<serializeLongString(player->inventory_formspec);
3695 std::string s = os.str();
3696 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3698 m_con.Send(peer_id, 0, data, true);
3701 s32 Server::playSound(const SimpleSoundSpec &spec,
3702 const ServerSoundParams ¶ms)
3704 // Find out initial position of sound
3705 bool pos_exists = false;
3706 v3f pos = params.getPos(m_env, &pos_exists);
3707 // If position is not found while it should be, cancel sound
3708 if(pos_exists != (params.type != ServerSoundParams::SSP_LOCAL))
3710 // Filter destination clients
3711 std::set<RemoteClient*> dst_clients;
3712 if(params.to_player != "")
3714 Player *player = m_env->getPlayer(params.to_player.c_str());
3716 infostream<<"Server::playSound: Player \""<<params.to_player
3717 <<"\" not found"<<std::endl;
3720 if(player->peer_id == PEER_ID_INEXISTENT){
3721 infostream<<"Server::playSound: Player \""<<params.to_player
3722 <<"\" not connected"<<std::endl;
3725 RemoteClient *client = getClient(player->peer_id);
3726 dst_clients.insert(client);
3730 for(std::map<u16, RemoteClient*>::iterator
3731 i = m_clients.begin(); i != m_clients.end(); ++i)
3733 RemoteClient *client = i->second;
3734 Player *player = m_env->getPlayer(client->peer_id);
3738 if(player->getPosition().getDistanceFrom(pos) >
3739 params.max_hear_distance)
3742 dst_clients.insert(client);
3745 if(dst_clients.size() == 0)
3748 s32 id = m_next_sound_id++;
3749 // The sound will exist as a reference in m_playing_sounds
3750 m_playing_sounds[id] = ServerPlayingSound();
3751 ServerPlayingSound &psound = m_playing_sounds[id];
3752 psound.params = params;
3753 for(std::set<RemoteClient*>::iterator i = dst_clients.begin();
3754 i != dst_clients.end(); i++)
3755 psound.clients.insert((*i)->peer_id);
3757 std::ostringstream os(std::ios_base::binary);
3758 writeU16(os, TOCLIENT_PLAY_SOUND);
3760 os<<serializeString(spec.name);
3761 writeF1000(os, spec.gain * params.gain);
3762 writeU8(os, params.type);
3763 writeV3F1000(os, pos);
3764 writeU16(os, params.object);
3765 writeU8(os, params.loop);
3767 std::string s = os.str();
3768 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3770 for(std::set<RemoteClient*>::iterator i = dst_clients.begin();
3771 i != dst_clients.end(); i++){
3773 m_con.Send((*i)->peer_id, 0, data, true);
3777 void Server::stopSound(s32 handle)
3779 // Get sound reference
3780 std::map<s32, ServerPlayingSound>::iterator i =
3781 m_playing_sounds.find(handle);
3782 if(i == m_playing_sounds.end())
3784 ServerPlayingSound &psound = i->second;
3786 std::ostringstream os(std::ios_base::binary);
3787 writeU16(os, TOCLIENT_STOP_SOUND);
3788 writeS32(os, handle);
3790 std::string s = os.str();
3791 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3793 for(std::set<u16>::iterator i = psound.clients.begin();
3794 i != psound.clients.end(); i++){
3796 m_con.Send(*i, 0, data, true);
3798 // Remove sound reference
3799 m_playing_sounds.erase(i);
3802 void Server::sendRemoveNode(v3s16 p, u16 ignore_id,
3803 std::list<u16> *far_players, float far_d_nodes)
3805 float maxd = far_d_nodes*BS;
3806 v3f p_f = intToFloat(p, BS);
3810 SharedBuffer<u8> reply(replysize);
3811 writeU16(&reply[0], TOCLIENT_REMOVENODE);
3812 writeS16(&reply[2], p.X);
3813 writeS16(&reply[4], p.Y);
3814 writeS16(&reply[6], p.Z);
3816 for(std::map<u16, RemoteClient*>::iterator
3817 i = m_clients.begin();
3818 i != m_clients.end(); ++i)
3820 // Get client and check that it is valid
3821 RemoteClient *client = i->second;
3822 assert(client->peer_id == i->first);
3823 if(client->serialization_version == SER_FMT_VER_INVALID)
3826 // Don't send if it's the same one
3827 if(client->peer_id == ignore_id)
3833 Player *player = m_env->getPlayer(client->peer_id);
3836 // If player is far away, only set modified blocks not sent
3837 v3f player_pos = player->getPosition();
3838 if(player_pos.getDistanceFrom(p_f) > maxd)
3840 far_players->push_back(client->peer_id);
3847 m_con.Send(client->peer_id, 0, reply, true);
3851 void Server::sendAddNode(v3s16 p, MapNode n, u16 ignore_id,
3852 std::list<u16> *far_players, float far_d_nodes)
3854 float maxd = far_d_nodes*BS;
3855 v3f p_f = intToFloat(p, BS);
3857 for(std::map<u16, RemoteClient*>::iterator
3858 i = m_clients.begin();
3859 i != m_clients.end(); ++i)
3861 // Get client and check that it is valid
3862 RemoteClient *client = i->second;
3863 assert(client->peer_id == i->first);
3864 if(client->serialization_version == SER_FMT_VER_INVALID)
3867 // Don't send if it's the same one
3868 if(client->peer_id == ignore_id)
3874 Player *player = m_env->getPlayer(client->peer_id);
3877 // If player is far away, only set modified blocks not sent
3878 v3f player_pos = player->getPosition();
3879 if(player_pos.getDistanceFrom(p_f) > maxd)
3881 far_players->push_back(client->peer_id);
3888 u32 replysize = 8 + MapNode::serializedLength(client->serialization_version);
3889 SharedBuffer<u8> reply(replysize);
3890 writeU16(&reply[0], TOCLIENT_ADDNODE);
3891 writeS16(&reply[2], p.X);
3892 writeS16(&reply[4], p.Y);
3893 writeS16(&reply[6], p.Z);
3894 n.serialize(&reply[8], client->serialization_version);
3897 m_con.Send(client->peer_id, 0, reply, true);
3901 void Server::setBlockNotSent(v3s16 p)
3903 for(std::map<u16, RemoteClient*>::iterator
3904 i = m_clients.begin();
3905 i != m_clients.end(); ++i)
3907 RemoteClient *client = i->second;
3908 client->SetBlockNotSent(p);
3912 void Server::SendBlockNoLock(u16 peer_id, MapBlock *block, u8 ver)
3914 DSTACK(__FUNCTION_NAME);
3916 v3s16 p = block->getPos();
3920 bool completely_air = true;
3921 for(s16 z0=0; z0<MAP_BLOCKSIZE; z0++)
3922 for(s16 x0=0; x0<MAP_BLOCKSIZE; x0++)
3923 for(s16 y0=0; y0<MAP_BLOCKSIZE; y0++)
3925 if(block->getNodeNoEx(v3s16(x0,y0,z0)).d != CONTENT_AIR)
3927 completely_air = false;
3928 x0 = y0 = z0 = MAP_BLOCKSIZE; // Break out
3933 infostream<<"Server: Sending block ("<<p.X<<","<<p.Y<<","<<p.Z<<"): ";
3935 infostream<<"[completely air] ";
3936 infostream<<std::endl;
3940 Create a packet with the block in the right format
3943 std::ostringstream os(std::ios_base::binary);
3944 block->serialize(os, ver, false);
3945 std::string s = os.str();
3946 SharedBuffer<u8> blockdata((u8*)s.c_str(), s.size());
3948 u32 replysize = 8 + blockdata.getSize();
3949 SharedBuffer<u8> reply(replysize);
3950 writeU16(&reply[0], TOCLIENT_BLOCKDATA);
3951 writeS16(&reply[2], p.X);
3952 writeS16(&reply[4], p.Y);
3953 writeS16(&reply[6], p.Z);
3954 memcpy(&reply[8], *blockdata, blockdata.getSize());
3956 /*infostream<<"Server: Sending block ("<<p.X<<","<<p.Y<<","<<p.Z<<")"
3957 <<": \tpacket size: "<<replysize<<std::endl;*/
3962 m_con.Send(peer_id, 1, reply, true);
3965 void Server::SendBlocks(float dtime)
3967 DSTACK(__FUNCTION_NAME);
3969 JMutexAutoLock envlock(m_env_mutex);
3970 JMutexAutoLock conlock(m_con_mutex);
3972 ScopeProfiler sp(g_profiler, "Server: sel and send blocks to clients");
3974 std::vector<PrioritySortedBlockTransfer> queue;
3976 s32 total_sending = 0;
3979 ScopeProfiler sp(g_profiler, "Server: selecting blocks for sending");
3981 for(std::map<u16, RemoteClient*>::iterator
3982 i = m_clients.begin();
3983 i != m_clients.end(); ++i)
3985 RemoteClient *client = i->second;
3986 assert(client->peer_id == i->first);
3988 // If definitions and textures have not been sent, don't
3989 // send MapBlocks either
3990 if(!client->definitions_sent)
3993 total_sending += client->SendingCount();
3995 if(client->serialization_version == SER_FMT_VER_INVALID)
3998 client->GetNextBlocks(this, dtime, queue);
4003 // Lowest priority number comes first.
4004 // Lowest is most important.
4005 std::sort(queue.begin(), queue.end());
4007 for(u32 i=0; i<queue.size(); i++)
4009 //TODO: Calculate limit dynamically
4010 if(total_sending >= g_settings->getS32
4011 ("max_simultaneous_block_sends_server_total"))
4014 PrioritySortedBlockTransfer q = queue[i];
4016 MapBlock *block = NULL;
4019 block = m_env->getMap().getBlockNoCreate(q.pos);
4021 catch(InvalidPositionException &e)
4026 RemoteClient *client = getClient(q.peer_id);
4028 SendBlockNoLock(q.peer_id, block, client->serialization_version);
4030 client->SentBlock(q.pos);
4036 void Server::fillMediaCache()
4038 DSTACK(__FUNCTION_NAME);
4040 infostream<<"Server: Calculating media file checksums"<<std::endl;
4042 // Collect all media file paths
4043 std::list<std::string> paths;
4044 for(std::vector<ModSpec>::iterator i = m_mods.begin();
4045 i != m_mods.end(); i++){
4046 const ModSpec &mod = *i;
4047 paths.push_back(mod.path + DIR_DELIM + "textures");
4048 paths.push_back(mod.path + DIR_DELIM + "sounds");
4049 paths.push_back(mod.path + DIR_DELIM + "media");
4050 paths.push_back(mod.path + DIR_DELIM + "models");
4052 std::string path_all = "textures";
4053 paths.push_back(path_all + DIR_DELIM + "all");
4055 // Collect media file information from paths into cache
4056 for(std::list<std::string>::iterator i = paths.begin();
4057 i != paths.end(); i++)
4059 std::string mediapath = *i;
4060 std::vector<fs::DirListNode> dirlist = fs::GetDirListing(mediapath);
4061 for(u32 j=0; j<dirlist.size(); j++){
4062 if(dirlist[j].dir) // Ignode dirs
4064 std::string filename = dirlist[j].name;
4065 // If name contains illegal characters, ignore the file
4066 if(!string_allowed(filename, TEXTURENAME_ALLOWED_CHARS)){
4067 infostream<<"Server: ignoring illegal file name: \""
4068 <<filename<<"\""<<std::endl;
4071 // If name is not in a supported format, ignore it
4072 const char *supported_ext[] = {
4073 ".png", ".jpg", ".bmp", ".tga",
4074 ".pcx", ".ppm", ".psd", ".wal", ".rgb",
4076 ".x", ".b3d", ".md2", ".obj",
4079 if(removeStringEnd(filename, supported_ext) == ""){
4080 infostream<<"Server: ignoring unsupported file extension: \""
4081 <<filename<<"\""<<std::endl;
4084 // Ok, attempt to load the file and add to cache
4085 std::string filepath = mediapath + DIR_DELIM + filename;
4087 std::ifstream fis(filepath.c_str(), std::ios_base::binary);
4088 if(fis.good() == false){
4089 errorstream<<"Server::fillMediaCache(): Could not open \""
4090 <<filename<<"\" for reading"<<std::endl;
4093 std::ostringstream tmp_os(std::ios_base::binary);
4097 fis.read(buf, 1024);
4098 std::streamsize len = fis.gcount();
4099 tmp_os.write(buf, len);
4108 errorstream<<"Server::fillMediaCache(): Failed to read \""
4109 <<filename<<"\""<<std::endl;
4112 if(tmp_os.str().length() == 0){
4113 errorstream<<"Server::fillMediaCache(): Empty file \""
4114 <<filepath<<"\""<<std::endl;
4119 sha1.addBytes(tmp_os.str().c_str(), tmp_os.str().length());
4121 unsigned char *digest = sha1.getDigest();
4122 std::string sha1_base64 = base64_encode(digest, 20);
4123 std::string sha1_hex = hex_encode((char*)digest, 20);
4127 this->m_media[filename] = MediaInfo(filepath, sha1_base64);
4128 verbosestream<<"Server: "<<sha1_hex<<" is "<<filename<<std::endl;
4133 struct SendableMediaAnnouncement
4136 std::string sha1_digest;
4138 SendableMediaAnnouncement(const std::string name_="",
4139 const std::string sha1_digest_=""):
4141 sha1_digest(sha1_digest_)
4145 void Server::sendMediaAnnouncement(u16 peer_id)
4147 DSTACK(__FUNCTION_NAME);
4149 verbosestream<<"Server: Announcing files to id("<<peer_id<<")"
4152 std::list<SendableMediaAnnouncement> file_announcements;
4154 for(std::map<std::string, MediaInfo>::iterator i = m_media.begin();
4155 i != m_media.end(); i++){
4157 file_announcements.push_back(
4158 SendableMediaAnnouncement(i->first, i->second.sha1_digest));
4162 std::ostringstream os(std::ios_base::binary);
4170 u16 length of sha1_digest
4175 writeU16(os, TOCLIENT_ANNOUNCE_MEDIA);
4176 writeU16(os, file_announcements.size());
4178 for(std::list<SendableMediaAnnouncement>::iterator
4179 j = file_announcements.begin();
4180 j != file_announcements.end(); ++j){
4181 os<<serializeString(j->name);
4182 os<<serializeString(j->sha1_digest);
4184 os<<serializeString(g_settings->get("remote_media"));
4187 std::string s = os.str();
4188 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
4191 m_con.Send(peer_id, 0, data, true);
4194 struct SendableMedia
4200 SendableMedia(const std::string &name_="", const std::string path_="",
4201 const std::string &data_=""):
4208 void Server::sendRequestedMedia(u16 peer_id,
4209 const std::list<MediaRequest> &tosend)
4211 DSTACK(__FUNCTION_NAME);
4213 verbosestream<<"Server::sendRequestedMedia(): "
4214 <<"Sending files to client"<<std::endl;
4218 // Put 5kB in one bunch (this is not accurate)
4219 u32 bytes_per_bunch = 5000;
4221 std::vector< std::list<SendableMedia> > file_bunches;
4222 file_bunches.push_back(std::list<SendableMedia>());
4224 u32 file_size_bunch_total = 0;
4226 for(std::list<MediaRequest>::const_iterator i = tosend.begin();
4227 i != tosend.end(); ++i)
4229 if(m_media.find(i->name) == m_media.end()){
4230 errorstream<<"Server::sendRequestedMedia(): Client asked for "
4231 <<"unknown file \""<<(i->name)<<"\""<<std::endl;
4235 //TODO get path + name
4236 std::string tpath = m_media[(*i).name].path;
4239 std::ifstream fis(tpath.c_str(), std::ios_base::binary);
4240 if(fis.good() == false){
4241 errorstream<<"Server::sendRequestedMedia(): Could not open \""
4242 <<tpath<<"\" for reading"<<std::endl;
4245 std::ostringstream tmp_os(std::ios_base::binary);
4249 fis.read(buf, 1024);
4250 std::streamsize len = fis.gcount();
4251 tmp_os.write(buf, len);
4252 file_size_bunch_total += len;
4261 errorstream<<"Server::sendRequestedMedia(): Failed to read \""
4262 <<(*i).name<<"\""<<std::endl;
4265 /*infostream<<"Server::sendRequestedMedia(): Loaded \""
4266 <<tname<<"\""<<std::endl;*/
4268 file_bunches[file_bunches.size()-1].push_back(
4269 SendableMedia((*i).name, tpath, tmp_os.str()));
4271 // Start next bunch if got enough data
4272 if(file_size_bunch_total >= bytes_per_bunch){
4273 file_bunches.push_back(std::list<SendableMedia>());
4274 file_size_bunch_total = 0;
4279 /* Create and send packets */
4281 u32 num_bunches = file_bunches.size();
4282 for(u32 i=0; i<num_bunches; i++)
4284 std::ostringstream os(std::ios_base::binary);
4288 u16 total number of texture bunches
4289 u16 index of this bunch
4290 u32 number of files in this bunch
4299 writeU16(os, TOCLIENT_MEDIA);
4300 writeU16(os, num_bunches);
4302 writeU32(os, file_bunches[i].size());
4304 for(std::list<SendableMedia>::iterator
4305 j = file_bunches[i].begin();
4306 j != file_bunches[i].end(); ++j){
4307 os<<serializeString(j->name);
4308 os<<serializeLongString(j->data);
4312 std::string s = os.str();
4313 verbosestream<<"Server::sendRequestedMedia(): bunch "
4314 <<i<<"/"<<num_bunches
4315 <<" files="<<file_bunches[i].size()
4316 <<" size=" <<s.size()<<std::endl;
4317 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
4319 m_con.Send(peer_id, 0, data, true);
4323 void Server::sendDetachedInventory(const std::string &name, u16 peer_id)
4325 if(m_detached_inventories.count(name) == 0){
4326 errorstream<<__FUNCTION_NAME<<": \""<<name<<"\" not found"<<std::endl;
4329 Inventory *inv = m_detached_inventories[name];
4331 std::ostringstream os(std::ios_base::binary);
4332 writeU16(os, TOCLIENT_DETACHED_INVENTORY);
4333 os<<serializeString(name);
4337 std::string s = os.str();
4338 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
4340 m_con.Send(peer_id, 0, data, true);
4343 void Server::sendDetachedInventoryToAll(const std::string &name)
4345 DSTACK(__FUNCTION_NAME);
4347 for(std::map<u16, RemoteClient*>::iterator
4348 i = m_clients.begin();
4349 i != m_clients.end(); ++i){
4350 RemoteClient *client = i->second;
4351 sendDetachedInventory(name, client->peer_id);
4355 void Server::sendDetachedInventories(u16 peer_id)
4357 DSTACK(__FUNCTION_NAME);
4359 for(std::map<std::string, Inventory*>::iterator
4360 i = m_detached_inventories.begin();
4361 i != m_detached_inventories.end(); i++){
4362 const std::string &name = i->first;
4363 //Inventory *inv = i->second;
4364 sendDetachedInventory(name, peer_id);
4372 void Server::DiePlayer(u16 peer_id)
4374 DSTACK(__FUNCTION_NAME);
4376 PlayerSAO *playersao = getPlayerSAO(peer_id);
4379 infostream<<"Server::DiePlayer(): Player "
4380 <<playersao->getPlayer()->getName()
4381 <<" dies"<<std::endl;
4383 playersao->setHP(0);
4385 // Trigger scripted stuff
4386 scriptapi_on_dieplayer(m_lua, playersao);
4388 SendPlayerHP(peer_id);
4389 SendDeathscreen(m_con, peer_id, false, v3f(0,0,0));
4392 void Server::RespawnPlayer(u16 peer_id)
4394 DSTACK(__FUNCTION_NAME);
4396 PlayerSAO *playersao = getPlayerSAO(peer_id);
4399 infostream<<"Server::RespawnPlayer(): Player "
4400 <<playersao->getPlayer()->getName()
4401 <<" respawns"<<std::endl;
4403 playersao->setHP(PLAYER_MAX_HP);
4405 bool repositioned = scriptapi_on_respawnplayer(m_lua, playersao);
4407 v3f pos = findSpawnPos(m_env->getServerMap());
4408 playersao->setPos(pos);
4412 void Server::UpdateCrafting(u16 peer_id)
4414 DSTACK(__FUNCTION_NAME);
4416 Player* player = m_env->getPlayer(peer_id);
4419 // Get a preview for crafting
4421 getCraftingResult(&player->inventory, preview, false, this);
4423 // Put the new preview in
4424 InventoryList *plist = player->inventory.getList("craftpreview");
4426 assert(plist->getSize() >= 1);
4427 plist->changeItem(0, preview);
4430 RemoteClient* Server::getClient(u16 peer_id)
4432 DSTACK(__FUNCTION_NAME);
4433 //JMutexAutoLock lock(m_con_mutex);
4434 std::map<u16, RemoteClient*>::iterator n;
4435 n = m_clients.find(peer_id);
4436 // A client should exist for all peers
4437 assert(n != m_clients.end());
4441 std::wstring Server::getStatusString()
4443 std::wostringstream os(std::ios_base::binary);
4446 os<<L"version="<<narrow_to_wide(VERSION_STRING);
4448 os<<L", uptime="<<m_uptime.get();
4449 // Information about clients
4450 std::map<u16, RemoteClient*>::iterator i;
4453 for(i = m_clients.begin(), first = true;
4454 i != m_clients.end(); ++i)
4456 // Get client and check that it is valid
4457 RemoteClient *client = i->second;
4458 assert(client->peer_id == i->first);
4459 if(client->serialization_version == SER_FMT_VER_INVALID)
4462 Player *player = m_env->getPlayer(client->peer_id);
4463 // Get name of player
4464 std::wstring name = L"unknown";
4466 name = narrow_to_wide(player->getName());
4467 // Add name to information string
4475 if(((ServerMap*)(&m_env->getMap()))->isSavingEnabled() == false)
4476 os<<std::endl<<L"# Server: "<<" WARNING: Map saving is disabled.";
4477 if(g_settings->get("motd") != "")
4478 os<<std::endl<<L"# Server: "<<narrow_to_wide(g_settings->get("motd"));
4482 std::set<std::string> Server::getPlayerEffectivePrivs(const std::string &name)
4484 std::set<std::string> privs;
4485 scriptapi_get_auth(m_lua, name, NULL, &privs);
4489 bool Server::checkPriv(const std::string &name, const std::string &priv)
4491 std::set<std::string> privs = getPlayerEffectivePrivs(name);
4492 return (privs.count(priv) != 0);
4495 void Server::reportPrivsModified(const std::string &name)
4498 for(std::map<u16, RemoteClient*>::iterator
4499 i = m_clients.begin();
4500 i != m_clients.end(); ++i){
4501 RemoteClient *client = i->second;
4502 Player *player = m_env->getPlayer(client->peer_id);
4503 reportPrivsModified(player->getName());
4506 Player *player = m_env->getPlayer(name.c_str());
4509 SendPlayerPrivileges(player->peer_id);
4510 PlayerSAO *sao = player->getPlayerSAO();
4513 sao->updatePrivileges(
4514 getPlayerEffectivePrivs(name),
4519 void Server::reportInventoryFormspecModified(const std::string &name)
4521 Player *player = m_env->getPlayer(name.c_str());
4524 SendPlayerInventoryFormspec(player->peer_id);
4527 // Saves g_settings to configpath given at initialization
4528 void Server::saveConfig()
4530 if(m_path_config != "")
4531 g_settings->updateConfigFile(m_path_config.c_str());
4534 void Server::notifyPlayer(const char *name, const std::wstring msg)
4536 Player *player = m_env->getPlayer(name);
4539 SendChatMessage(player->peer_id, std::wstring(L"Server: -!- ")+msg);
4542 bool Server::showFormspec(const char *playername, const std::string &formspec, const std::string &formname)
4544 Player *player = m_env->getPlayer(playername);
4548 infostream<<"showFormspec: couldn't find player:"<<playername<<std::endl;
4552 SendShowFormspecMessage(player->peer_id, formspec, formname);
4556 void Server::notifyPlayers(const std::wstring msg)
4558 BroadcastChatMessage(msg);
4561 void Server::spawnParticle(const char *playername, v3f pos,
4562 v3f velocity, v3f acceleration,
4563 float expirationtime, float size, bool
4564 collisiondetection, std::string texture)
4566 Player *player = m_env->getPlayer(playername);
4569 SendSpawnParticle(player->peer_id, pos, velocity, acceleration,
4570 expirationtime, size, collisiondetection, texture);
4573 void Server::spawnParticleAll(v3f pos, v3f velocity, v3f acceleration,
4574 float expirationtime, float size,
4575 bool collisiondetection, std::string texture)
4577 SendSpawnParticleAll(pos, velocity, acceleration,
4578 expirationtime, size, collisiondetection, texture);
4581 u32 Server::addParticleSpawner(const char *playername,
4582 u16 amount, float spawntime,
4583 v3f minpos, v3f maxpos,
4584 v3f minvel, v3f maxvel,
4585 v3f minacc, v3f maxacc,
4586 float minexptime, float maxexptime,
4587 float minsize, float maxsize,
4588 bool collisiondetection, std::string texture)
4590 Player *player = m_env->getPlayer(playername);
4595 for(;;) // look for unused particlespawner id
4598 if (std::find(m_particlespawner_ids.begin(),
4599 m_particlespawner_ids.end(), id)
4600 == m_particlespawner_ids.end())
4602 m_particlespawner_ids.push_back(id);
4607 SendAddParticleSpawner(player->peer_id, amount, spawntime,
4608 minpos, maxpos, minvel, maxvel, minacc, maxacc,
4609 minexptime, maxexptime, minsize, maxsize,
4610 collisiondetection, texture, id);
4615 u32 Server::addParticleSpawnerAll(u16 amount, float spawntime,
4616 v3f minpos, v3f maxpos,
4617 v3f minvel, v3f maxvel,
4618 v3f minacc, v3f maxacc,
4619 float minexptime, float maxexptime,
4620 float minsize, float maxsize,
4621 bool collisiondetection, std::string texture)
4624 for(;;) // look for unused particlespawner id
4627 if (std::find(m_particlespawner_ids.begin(),
4628 m_particlespawner_ids.end(), id)
4629 == m_particlespawner_ids.end())
4631 m_particlespawner_ids.push_back(id);
4636 SendAddParticleSpawnerAll(amount, spawntime,
4637 minpos, maxpos, minvel, maxvel, minacc, maxacc,
4638 minexptime, maxexptime, minsize, maxsize,
4639 collisiondetection, texture, id);
4644 void Server::deleteParticleSpawner(const char *playername, u32 id)
4646 Player *player = m_env->getPlayer(playername);
4650 m_particlespawner_ids.erase(
4651 std::remove(m_particlespawner_ids.begin(),
4652 m_particlespawner_ids.end(), id),
4653 m_particlespawner_ids.end());
4654 SendDeleteParticleSpawner(player->peer_id, id);
4657 void Server::deleteParticleSpawnerAll(u32 id)
4659 m_particlespawner_ids.erase(
4660 std::remove(m_particlespawner_ids.begin(),
4661 m_particlespawner_ids.end(), id),
4662 m_particlespawner_ids.end());
4663 SendDeleteParticleSpawnerAll(id);
4666 void Server::queueBlockEmerge(v3s16 blockpos, bool allow_generate)
4668 m_emerge->enqueueBlockEmerge(PEER_ID_INEXISTENT, blockpos, allow_generate);
4671 Inventory* Server::createDetachedInventory(const std::string &name)
4673 if(m_detached_inventories.count(name) > 0){
4674 infostream<<"Server clearing detached inventory \""<<name<<"\""<<std::endl;
4675 delete m_detached_inventories[name];
4677 infostream<<"Server creating detached inventory \""<<name<<"\""<<std::endl;
4679 Inventory *inv = new Inventory(m_itemdef);
4681 m_detached_inventories[name] = inv;
4682 sendDetachedInventoryToAll(name);
4689 BoolScopeSet(bool *dst, bool val):
4692 m_orig_state = *m_dst;
4697 *m_dst = m_orig_state;
4704 // actions: time-reversed list
4705 // Return value: success/failure
4706 bool Server::rollbackRevertActions(const std::list<RollbackAction> &actions,
4707 std::list<std::string> *log)
4709 infostream<<"Server::rollbackRevertActions(len="<<actions.size()<<")"<<std::endl;
4710 ServerMap *map = (ServerMap*)(&m_env->getMap());
4711 // Disable rollback report sink while reverting
4712 BoolScopeSet rollback_scope_disable(&m_rollback_sink_enabled, false);
4714 // Fail if no actions to handle
4715 if(actions.empty()){
4716 log->push_back("Nothing to do.");
4723 for(std::list<RollbackAction>::const_iterator
4724 i = actions.begin();
4725 i != actions.end(); i++)
4727 const RollbackAction &action = *i;
4729 bool success = action.applyRevert(map, this, this);
4732 std::ostringstream os;
4733 os<<"Revert of step ("<<num_tried<<") "<<action.toString()<<" failed";
4734 infostream<<"Map::rollbackRevertActions(): "<<os.str()<<std::endl;
4736 log->push_back(os.str());
4738 std::ostringstream os;
4739 os<<"Successfully reverted step ("<<num_tried<<") "<<action.toString();
4740 infostream<<"Map::rollbackRevertActions(): "<<os.str()<<std::endl;
4742 log->push_back(os.str());
4746 infostream<<"Map::rollbackRevertActions(): "<<num_failed<<"/"<<num_tried
4747 <<" failed"<<std::endl;
4749 // Call it done if less than half failed
4750 return num_failed <= num_tried/2;
4753 // IGameDef interface
4755 IItemDefManager* Server::getItemDefManager()
4759 INodeDefManager* Server::getNodeDefManager()
4763 ICraftDefManager* Server::getCraftDefManager()
4767 ITextureSource* Server::getTextureSource()
4771 IShaderSource* Server::getShaderSource()
4775 u16 Server::allocateUnknownNodeId(const std::string &name)
4777 return m_nodedef->allocateDummy(name);
4779 ISoundManager* Server::getSoundManager()
4781 return &dummySoundManager;
4783 MtEventManager* Server::getEventManager()
4787 IRollbackReportSink* Server::getRollbackReportSink()
4789 if(!m_enable_rollback_recording)
4791 if(!m_rollback_sink_enabled)
4796 IWritableItemDefManager* Server::getWritableItemDefManager()
4800 IWritableNodeDefManager* Server::getWritableNodeDefManager()
4804 IWritableCraftDefManager* Server::getWritableCraftDefManager()
4809 const ModSpec* Server::getModSpec(const std::string &modname)
4811 for(std::vector<ModSpec>::iterator i = m_mods.begin();
4812 i != m_mods.end(); i++){
4813 const ModSpec &mod = *i;
4814 if(mod.name == modname)
4819 void Server::getModNames(std::list<std::string> &modlist)
4821 for(std::vector<ModSpec>::iterator i = m_mods.begin(); i != m_mods.end(); i++)
4823 modlist.push_back(i->name);
4826 std::string Server::getBuiltinLuaPath()
4828 return porting::path_share + DIR_DELIM + "builtin";
4831 v3f findSpawnPos(ServerMap &map)
4833 //return v3f(50,50,50)*BS;
4838 nodepos = v2s16(0,0);
4843 s16 water_level = map.m_mgparams->water_level;
4845 // Try to find a good place a few times
4846 for(s32 i=0; i<1000; i++)
4849 // We're going to try to throw the player to this position
4850 v2s16 nodepos2d = v2s16(-range + (myrand()%(range*2)),
4851 -range + (myrand()%(range*2)));
4852 //v2s16 sectorpos = getNodeSectorPos(nodepos2d);
4853 // Get ground height at point (fallbacks to heightmap function)
4854 s16 groundheight = map.findGroundLevel(nodepos2d);
4855 // Don't go underwater
4856 if(groundheight <= water_level)
4858 //infostream<<"-> Underwater"<<std::endl;
4861 // Don't go to high places
4862 if(groundheight > water_level + 6)
4864 //infostream<<"-> Underwater"<<std::endl;
4868 nodepos = v3s16(nodepos2d.X, groundheight-2, nodepos2d.Y);
4869 bool is_good = false;
4871 for(s32 i=0; i<10; i++){
4872 v3s16 blockpos = getNodeBlockPos(nodepos);
4873 map.emergeBlock(blockpos, true);
4874 MapNode n = map.getNodeNoEx(nodepos);
4875 if(n.getContent() == CONTENT_AIR){
4886 // Found a good place
4887 //infostream<<"Searched through "<<i<<" places."<<std::endl;
4893 return intToFloat(nodepos, BS);
4896 PlayerSAO* Server::emergePlayer(const char *name, u16 peer_id)
4898 RemotePlayer *player = NULL;
4899 bool newplayer = false;
4902 Try to get an existing player
4904 player = static_cast<RemotePlayer*>(m_env->getPlayer(name));
4906 // If player is already connected, cancel
4907 if(player != NULL && player->peer_id != 0)
4909 infostream<<"emergePlayer(): Player already connected"<<std::endl;
4914 If player with the wanted peer_id already exists, cancel.
4916 if(m_env->getPlayer(peer_id) != NULL)
4918 infostream<<"emergePlayer(): Player with wrong name but same"
4919 " peer_id already exists"<<std::endl;
4924 Create a new player if it doesn't exist yet
4929 player = new RemotePlayer(this);
4930 player->updateName(name);
4932 /* Set player position */
4933 infostream<<"Server: Finding spawn place for player \""
4934 <<name<<"\""<<std::endl;
4935 v3f pos = findSpawnPos(m_env->getServerMap());
4936 player->setPosition(pos);
4938 /* Add player to environment */
4939 m_env->addPlayer(player);
4943 Create a new player active object
4945 PlayerSAO *playersao = new PlayerSAO(m_env, player, peer_id,
4946 getPlayerEffectivePrivs(player->getName()),
4949 /* Add object to environment */
4950 m_env->addActiveObject(playersao);
4954 scriptapi_on_newplayer(m_lua, playersao);
4956 scriptapi_on_joinplayer(m_lua, playersao);
4961 void Server::handlePeerChange(PeerChange &c)
4963 JMutexAutoLock envlock(m_env_mutex);
4964 JMutexAutoLock conlock(m_con_mutex);
4966 if(c.type == PEER_ADDED)
4973 std::map<u16, RemoteClient*>::iterator n;
4974 n = m_clients.find(c.peer_id);
4975 // The client shouldn't already exist
4976 assert(n == m_clients.end());
4979 RemoteClient *client = new RemoteClient();
4980 client->peer_id = c.peer_id;
4981 m_clients[client->peer_id] = client;
4984 else if(c.type == PEER_REMOVED)
4991 std::map<u16, RemoteClient*>::iterator n;
4992 n = m_clients.find(c.peer_id);
4993 // The client should exist
4994 assert(n != m_clients.end());
4997 Mark objects to be not known by the client
4999 RemoteClient *client = n->second;
5001 for(std::set<u16>::iterator
5002 i = client->m_known_objects.begin();
5003 i != client->m_known_objects.end(); ++i)
5007 ServerActiveObject* obj = m_env->getActiveObject(id);
5009 if(obj && obj->m_known_by_count > 0)
5010 obj->m_known_by_count--;
5014 Clear references to playing sounds
5016 for(std::map<s32, ServerPlayingSound>::iterator
5017 i = m_playing_sounds.begin();
5018 i != m_playing_sounds.end();)
5020 ServerPlayingSound &psound = i->second;
5021 psound.clients.erase(c.peer_id);
5022 if(psound.clients.size() == 0)
5023 m_playing_sounds.erase(i++);
5028 Player *player = m_env->getPlayer(c.peer_id);
5030 // Collect information about leaving in chat
5031 std::wstring message;
5035 std::wstring name = narrow_to_wide(player->getName());
5038 message += L" left the game.";
5040 message += L" (timed out)";
5044 /* Run scripts and remove from environment */
5048 PlayerSAO *playersao = player->getPlayerSAO();
5051 scriptapi_on_leaveplayer(m_lua, playersao);
5053 playersao->disconnected();
5063 std::ostringstream os(std::ios_base::binary);
5064 for(std::map<u16, RemoteClient*>::iterator
5065 i = m_clients.begin();
5066 i != m_clients.end(); ++i)
5068 RemoteClient *client = i->second;
5069 assert(client->peer_id == i->first);
5070 if(client->serialization_version == SER_FMT_VER_INVALID)
5073 Player *player = m_env->getPlayer(client->peer_id);
5076 // Get name of player
5077 os<<player->getName()<<" ";
5080 actionstream<<player->getName()<<" "
5081 <<(c.timeout?"times out.":"leaves game.")
5082 <<" List of players: "
5083 <<os.str()<<std::endl;
5088 delete m_clients[c.peer_id];
5089 m_clients.erase(c.peer_id);
5091 // Send player info to all remaining clients
5092 //SendPlayerInfos();
5094 // Send leave chat message to all remaining clients
5095 if(message.length() != 0)
5096 BroadcastChatMessage(message);
5105 void Server::handlePeerChanges()
5107 while(m_peer_change_queue.size() > 0)
5109 PeerChange c = m_peer_change_queue.pop_front();
5111 verbosestream<<"Server: Handling peer change: "
5112 <<"id="<<c.peer_id<<", timeout="<<c.timeout
5115 handlePeerChange(c);
5119 void dedicated_server_loop(Server &server, bool &kill)
5121 DSTACK(__FUNCTION_NAME);
5123 verbosestream<<"dedicated_server_loop()"<<std::endl;
5125 IntervalLimiter m_profiler_interval;
5129 float steplen = g_settings->getFloat("dedicated_server_step");
5130 // This is kind of a hack but can be done like this
5131 // because server.step() is very light
5133 ScopeProfiler sp(g_profiler, "dedicated server sleep");
5134 sleep_ms((int)(steplen*1000.0));
5136 server.step(steplen);
5138 if(server.getShutdownRequested() || kill)
5140 infostream<<"Dedicated server quitting"<<std::endl;
5142 if(g_settings->getBool("server_announce") == true)
5143 ServerList::sendAnnounce("delete");
5151 float profiler_print_interval =
5152 g_settings->getFloat("profiler_print_interval");
5153 if(profiler_print_interval != 0)
5155 if(m_profiler_interval.step(steplen, profiler_print_interval))
5157 infostream<<"Profiler:"<<std::endl;
5158 g_profiler->print(infostream);
5159 g_profiler->clear();