3 Copyright (C) 2010-2011 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.
23 #include "clientserver.h"
25 #include "jmutexautolock.h"
27 #include "constants.h"
30 #include "servercommand.h"
33 #include "serverobject.h"
38 #include "scriptapi.h"
43 #include "content_mapnode.h"
44 #include "content_nodemeta.h"
45 #include "content_abm.h"
46 #include "content_sao.h"
51 #include "sound.h" // dummySoundManager
52 #include "event_manager.h"
54 #include "util/string.h"
55 #include "util/pointedthing.h"
57 #define PP(x) "("<<(x).X<<","<<(x).Y<<","<<(x).Z<<")"
59 #define BLOCK_EMERGE_FLAG_FROMDISK (1<<0)
61 class MapEditEventIgnorer
64 MapEditEventIgnorer(bool *flag):
73 ~MapEditEventIgnorer()
86 class MapEditEventAreaIgnorer
89 MapEditEventAreaIgnorer(VoxelArea *ignorevariable, const VoxelArea &a):
90 m_ignorevariable(ignorevariable)
92 if(m_ignorevariable->getVolume() == 0)
93 *m_ignorevariable = a;
95 m_ignorevariable = NULL;
98 ~MapEditEventAreaIgnorer()
102 assert(m_ignorevariable->getVolume() != 0);
103 *m_ignorevariable = VoxelArea();
108 VoxelArea *m_ignorevariable;
111 void * ServerThread::Thread()
115 log_register_thread("ServerThread");
117 DSTACK(__FUNCTION_NAME);
119 BEGIN_DEBUG_EXCEPTION_HANDLER
124 //TimeTaker timer("AsyncRunStep() + Receive()");
127 //TimeTaker timer("AsyncRunStep()");
128 m_server->AsyncRunStep();
131 //infostream<<"Running m_server->Receive()"<<std::endl;
134 catch(con::NoIncomingDataException &e)
137 catch(con::PeerNotFoundException &e)
139 infostream<<"Server: PeerNotFoundException"<<std::endl;
141 catch(con::ConnectionBindFailed &e)
143 m_server->setAsyncFatalError(e.what());
147 m_server->setAsyncFatalError(e.what());
151 END_DEBUG_EXCEPTION_HANDLER(errorstream)
156 void * EmergeThread::Thread()
160 log_register_thread("EmergeThread");
162 DSTACK(__FUNCTION_NAME);
164 BEGIN_DEBUG_EXCEPTION_HANDLER
166 bool enable_mapgen_debug_info = g_settings->getBool("enable_mapgen_debug_info");
168 v3s16 last_tried_pos(-32768,-32768,-32768); // For error output
171 Get block info from queue, emerge them and send them
174 After queue is empty, exit.
178 QueuedBlockEmerge *qptr = m_server->m_emerge_queue.pop();
182 SharedPtr<QueuedBlockEmerge> q(qptr);
190 Do not generate over-limit
192 if(blockpos_over_limit(p))
195 //infostream<<"EmergeThread::Thread(): running"<<std::endl;
197 //TimeTaker timer("block emerge");
200 Try to emerge it from somewhere.
202 If it is only wanted as optional, only loading from disk
207 Check if any peer wants it as non-optional. In that case it
210 Also decrement the emerge queue count in clients.
213 bool only_from_disk = true;
216 core::map<u16, u8>::Iterator i;
217 for(i=q->peer_ids.getIterator(); i.atEnd()==false; i++)
219 //u16 peer_id = i.getNode()->getKey();
222 u8 flags = i.getNode()->getValue();
223 if((flags & BLOCK_EMERGE_FLAG_FROMDISK) == false)
224 only_from_disk = false;
229 if(enable_mapgen_debug_info)
230 infostream<<"EmergeThread: p="
231 <<"("<<p.X<<","<<p.Y<<","<<p.Z<<") "
232 <<"only_from_disk="<<only_from_disk<<std::endl;
234 ServerMap &map = ((ServerMap&)m_server->m_env->getMap());
236 MapBlock *block = NULL;
237 bool got_block = true;
238 core::map<v3s16, MapBlock*> modified_blocks;
241 Try to fetch block from memory or disk.
242 If not found and asked to generate, initialize generator.
245 bool started_generate = false;
246 mapgen::BlockMakeData data;
249 JMutexAutoLock envlock(m_server->m_env_mutex);
251 // Load sector if it isn't loaded
252 if(map.getSectorNoGenerateNoEx(p2d) == NULL)
253 map.loadSectorMeta(p2d);
255 // Attempt to load block
256 block = map.getBlockNoCreateNoEx(p);
257 if(!block || block->isDummy() || !block->isGenerated())
259 if(enable_mapgen_debug_info)
260 infostream<<"EmergeThread: not in memory, "
261 <<"attempting to load from disk"<<std::endl;
263 block = map.loadBlock(p);
266 // If could not load and allowed to generate, start generation
267 // inside this same envlock
268 if(only_from_disk == false &&
269 (block == NULL || block->isGenerated() == false)){
270 if(enable_mapgen_debug_info)
271 infostream<<"EmergeThread: generating"<<std::endl;
272 started_generate = true;
274 map.initBlockMake(&data, p);
279 If generator was initialized, generate now when envlock is free.
284 ScopeProfiler sp(g_profiler, "EmergeThread: mapgen::make_block",
286 TimeTaker t("mapgen::make_block()");
288 mapgen::make_block(&data);
290 if(enable_mapgen_debug_info == false)
291 t.stop(true); // Hide output
295 // Lock environment again to access the map
296 JMutexAutoLock envlock(m_server->m_env_mutex);
298 ScopeProfiler sp(g_profiler, "EmergeThread: after "
299 "mapgen::make_block (envlock)", SPT_AVG);
301 // Blit data back on map, update lighting, add mobs and
302 // whatever this does
303 map.finishBlockMake(&data, modified_blocks);
306 block = map.getBlockNoCreateNoEx(p);
308 // If block doesn't exist, don't try doing anything with it
309 // This happens if the block is not in generation boundaries
314 Do some post-generate stuff
317 v3s16 minp = data.blockpos_min*MAP_BLOCKSIZE;
318 v3s16 maxp = data.blockpos_max*MAP_BLOCKSIZE +
319 v3s16(1,1,1)*(MAP_BLOCKSIZE-1);
322 Ignore map edit events, they will not need to be
323 sent to anybody because the block hasn't been sent
326 //MapEditEventIgnorer ign(&m_server->m_ignore_map_edit_events);
327 MapEditEventAreaIgnorer ign(
328 &m_server->m_ignore_map_edit_events_area,
329 VoxelArea(minp, maxp));
331 TimeTaker timer("on_generated");
332 scriptapi_environment_on_generated(m_server->m_lua,
333 minp, maxp, mapgen::get_blockseed(data.seed, minp));
334 /*int t = timer.stop(true);
335 dstream<<"on_generated took "<<t<<"ms"<<std::endl;*/
338 if(enable_mapgen_debug_info)
339 infostream<<"EmergeThread: ended up with: "
340 <<analyze_block(block)<<std::endl;
342 // Activate objects and stuff
343 m_server->m_env->activateBlock(block, 0);
351 Set sent status of modified blocks on clients
354 // NOTE: Server's clients are also behind the connection mutex
355 JMutexAutoLock lock(m_server->m_con_mutex);
358 Add the originally fetched block to the modified list
362 modified_blocks.insert(p, block);
366 Set the modified blocks unsent for all the clients
369 for(core::map<u16, RemoteClient*>::Iterator
370 i = m_server->m_clients.getIterator();
371 i.atEnd() == false; i++)
373 RemoteClient *client = i.getNode()->getValue();
375 if(modified_blocks.size() > 0)
377 // Remove block from sent history
378 client->SetBlocksNotSent(modified_blocks);
382 catch(VersionMismatchException &e)
384 std::ostringstream err;
385 err<<"World data version mismatch in MapBlock "<<PP(last_tried_pos)<<std::endl;
386 err<<"----"<<std::endl;
387 err<<"\""<<e.what()<<"\""<<std::endl;
388 err<<"See debug.txt."<<std::endl;
389 err<<"World probably saved by a newer version of Minetest."<<std::endl;
390 m_server->setAsyncFatalError(err.str());
392 catch(SerializationError &e)
394 std::ostringstream err;
395 err<<"Invalid data in MapBlock "<<PP(last_tried_pos)<<std::endl;
396 err<<"----"<<std::endl;
397 err<<"\""<<e.what()<<"\""<<std::endl;
398 err<<"See debug.txt."<<std::endl;
399 err<<"You can ignore this using [ignore_world_load_errors = true]."<<std::endl;
400 m_server->setAsyncFatalError(err.str());
403 END_DEBUG_EXCEPTION_HANDLER(errorstream)
405 log_deregister_thread();
410 v3f ServerSoundParams::getPos(ServerEnvironment *env, bool *pos_exists) const
412 if(pos_exists) *pos_exists = false;
417 if(pos_exists) *pos_exists = true;
422 ServerActiveObject *sao = env->getActiveObject(object);
425 if(pos_exists) *pos_exists = true;
426 return sao->getBasePosition(); }
431 void RemoteClient::GetNextBlocks(Server *server, float dtime,
432 core::array<PrioritySortedBlockTransfer> &dest)
434 DSTACK(__FUNCTION_NAME);
437 TimeTaker timer("RemoteClient::GetNextBlocks", &timer_result);*/
440 m_nothing_to_send_pause_timer -= dtime;
441 m_nearest_unsent_reset_timer += dtime;
443 if(m_nothing_to_send_pause_timer >= 0)
448 // Won't send anything if already sending
449 if(m_blocks_sending.size() >= g_settings->getU16
450 ("max_simultaneous_block_sends_per_client"))
452 //infostream<<"Not sending any blocks, Queue full."<<std::endl;
456 //TimeTaker timer("RemoteClient::GetNextBlocks");
458 Player *player = server->m_env->getPlayer(peer_id);
460 assert(player != NULL);
462 v3f playerpos = player->getPosition();
463 v3f playerspeed = player->getSpeed();
464 v3f playerspeeddir(0,0,0);
465 if(playerspeed.getLength() > 1.0*BS)
466 playerspeeddir = playerspeed / playerspeed.getLength();
467 // Predict to next block
468 v3f playerpos_predicted = playerpos + playerspeeddir*MAP_BLOCKSIZE*BS;
470 v3s16 center_nodepos = floatToInt(playerpos_predicted, BS);
472 v3s16 center = getNodeBlockPos(center_nodepos);
474 // Camera position and direction
475 v3f camera_pos = player->getEyePosition();
476 v3f camera_dir = v3f(0,0,1);
477 camera_dir.rotateYZBy(player->getPitch());
478 camera_dir.rotateXZBy(player->getYaw());
480 /*infostream<<"camera_dir=("<<camera_dir.X<<","<<camera_dir.Y<<","
481 <<camera_dir.Z<<")"<<std::endl;*/
484 Get the starting value of the block finder radius.
487 if(m_last_center != center)
489 m_nearest_unsent_d = 0;
490 m_last_center = center;
493 /*infostream<<"m_nearest_unsent_reset_timer="
494 <<m_nearest_unsent_reset_timer<<std::endl;*/
496 // Reset periodically to workaround for some bugs or stuff
497 if(m_nearest_unsent_reset_timer > 20.0)
499 m_nearest_unsent_reset_timer = 0;
500 m_nearest_unsent_d = 0;
501 //infostream<<"Resetting m_nearest_unsent_d for "
502 // <<server->getPlayerName(peer_id)<<std::endl;
505 //s16 last_nearest_unsent_d = m_nearest_unsent_d;
506 s16 d_start = m_nearest_unsent_d;
508 //infostream<<"d_start="<<d_start<<std::endl;
510 u16 max_simul_sends_setting = g_settings->getU16
511 ("max_simultaneous_block_sends_per_client");
512 u16 max_simul_sends_usually = max_simul_sends_setting;
515 Check the time from last addNode/removeNode.
517 Decrease send rate if player is building stuff.
519 m_time_from_building += dtime;
520 if(m_time_from_building < g_settings->getFloat(
521 "full_block_send_enable_min_time_from_building"))
523 max_simul_sends_usually
524 = LIMITED_MAX_SIMULTANEOUS_BLOCK_SENDS;
528 Number of blocks sending + number of blocks selected for sending
530 u32 num_blocks_selected = m_blocks_sending.size();
533 next time d will be continued from the d from which the nearest
534 unsent block was found this time.
536 This is because not necessarily any of the blocks found this
537 time are actually sent.
539 s32 new_nearest_unsent_d = -1;
541 s16 d_max = g_settings->getS16("max_block_send_distance");
542 s16 d_max_gen = g_settings->getS16("max_block_generate_distance");
544 // Don't loop very much at a time
545 s16 max_d_increment_at_time = 2;
546 if(d_max > d_start + max_d_increment_at_time)
547 d_max = d_start + max_d_increment_at_time;
548 /*if(d_max_gen > d_start+2)
549 d_max_gen = d_start+2;*/
551 //infostream<<"Starting from "<<d_start<<std::endl;
553 s32 nearest_emerged_d = -1;
554 s32 nearest_emergefull_d = -1;
555 s32 nearest_sent_d = -1;
556 bool queue_is_full = false;
559 for(d = d_start; d <= d_max; d++)
561 /*errorstream<<"checking d="<<d<<" for "
562 <<server->getPlayerName(peer_id)<<std::endl;*/
563 //infostream<<"RemoteClient::SendBlocks(): d="<<d<<std::endl;
566 If m_nearest_unsent_d was changed by the EmergeThread
567 (it can change it to 0 through SetBlockNotSent),
569 Else update m_nearest_unsent_d
571 /*if(m_nearest_unsent_d != last_nearest_unsent_d)
573 d = m_nearest_unsent_d;
574 last_nearest_unsent_d = m_nearest_unsent_d;
578 Get the border/face dot coordinates of a "d-radiused"
581 core::list<v3s16> list;
582 getFacePositions(list, d);
584 core::list<v3s16>::Iterator li;
585 for(li=list.begin(); li!=list.end(); li++)
587 v3s16 p = *li + center;
591 - Don't allow too many simultaneous transfers
592 - EXCEPT when the blocks are very close
594 Also, don't send blocks that are already flying.
597 // Start with the usual maximum
598 u16 max_simul_dynamic = max_simul_sends_usually;
600 // If block is very close, allow full maximum
601 if(d <= BLOCK_SEND_DISABLE_LIMITS_MAX_D)
602 max_simul_dynamic = max_simul_sends_setting;
604 // Don't select too many blocks for sending
605 if(num_blocks_selected >= max_simul_dynamic)
607 queue_is_full = true;
608 goto queue_full_break;
611 // Don't send blocks that are currently being transferred
612 if(m_blocks_sending.find(p) != NULL)
618 if(p.X < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
619 || p.X > MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
620 || p.Y < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
621 || p.Y > MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
622 || p.Z < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
623 || p.Z > MAP_GENERATION_LIMIT / MAP_BLOCKSIZE)
626 // If this is true, inexistent block will be made from scratch
627 bool generate = d <= d_max_gen;
630 /*// Limit the generating area vertically to 2/3
631 if(abs(p.Y - center.Y) > d_max_gen - d_max_gen / 3)
634 // Limit the send area vertically to 1/2
635 if(abs(p.Y - center.Y) > d_max / 2)
641 If block is far away, don't generate it unless it is
647 // Block center y in nodes
648 f32 y = (f32)(p.Y * MAP_BLOCKSIZE + MAP_BLOCKSIZE/2);
649 // Don't generate if it's very high or very low
650 if(y < -64 || y > 64)
654 v2s16 p2d_nodes_center(
658 // Get ground height in nodes
659 s16 gh = server->m_env->getServerMap().findGroundLevel(
662 // If differs a lot, don't generate
663 if(fabs(gh - y) > MAP_BLOCKSIZE*2)
665 // Actually, don't even send it
671 //infostream<<"d="<<d<<std::endl;
674 Don't generate or send if not in sight
675 FIXME This only works if the client uses a small enough
676 FOV setting. The default of 72 degrees is fine.
679 float camera_fov = (72.0*M_PI/180) * 4./3.;
680 if(isBlockInSight(p, camera_pos, camera_dir, camera_fov, 10000*BS) == false)
686 Don't send already sent blocks
689 if(m_blocks_sent.find(p) != NULL)
696 Check if map has this block
698 MapBlock *block = server->m_env->getMap().getBlockNoCreateNoEx(p);
700 bool surely_not_found_on_disk = false;
701 bool block_is_invalid = false;
704 // Reset usage timer, this block will be of use in the future.
705 block->resetUsageTimer();
707 // Block is dummy if data doesn't exist.
708 // It means it has been not found from disk and not generated
711 surely_not_found_on_disk = true;
714 // Block is valid if lighting is up-to-date and data exists
715 if(block->isValid() == false)
717 block_is_invalid = true;
720 /*if(block->isFullyGenerated() == false)
722 block_is_invalid = true;
727 ServerMap *map = (ServerMap*)(&server->m_env->getMap());
728 v2s16 chunkpos = map->sector_to_chunk(p2d);
729 if(map->chunkNonVolatile(chunkpos) == false)
730 block_is_invalid = true;
732 if(block->isGenerated() == false)
733 block_is_invalid = true;
736 If block is not close, don't send it unless it is near
739 Block is near ground level if night-time mesh
740 differs from day-time mesh.
744 if(block->getDayNightDiff() == false)
751 If block has been marked to not exist on disk (dummy)
752 and generating new ones is not wanted, skip block.
754 if(generate == false && surely_not_found_on_disk == true)
761 Add inexistent block to emerge queue.
763 if(block == NULL || surely_not_found_on_disk || block_is_invalid)
765 //TODO: Get value from somewhere
766 // Allow only one block in emerge queue
767 //if(server->m_emerge_queue.peerItemCount(peer_id) < 1)
768 // Allow two blocks in queue per client
769 //if(server->m_emerge_queue.peerItemCount(peer_id) < 2)
771 // Make it more responsive when needing to generate stuff
772 if(surely_not_found_on_disk)
774 if(server->m_emerge_queue.peerItemCount(peer_id) < max_emerge)
776 //infostream<<"Adding block to emerge queue"<<std::endl;
778 // Add it to the emerge queue and trigger the thread
781 if(generate == false)
782 flags |= BLOCK_EMERGE_FLAG_FROMDISK;
784 server->m_emerge_queue.addBlock(peer_id, p, flags);
785 server->m_emergethread.trigger();
787 if(nearest_emerged_d == -1)
788 nearest_emerged_d = d;
790 if(nearest_emergefull_d == -1)
791 nearest_emergefull_d = d;
798 if(nearest_sent_d == -1)
802 Add block to send queue
805 /*errorstream<<"sending from d="<<d<<" to "
806 <<server->getPlayerName(peer_id)<<std::endl;*/
808 PrioritySortedBlockTransfer q((float)d, p, peer_id);
812 num_blocks_selected += 1;
817 //infostream<<"Stopped at "<<d<<std::endl;
819 // If nothing was found for sending and nothing was queued for
820 // emerging, continue next time browsing from here
821 if(nearest_emerged_d != -1){
822 new_nearest_unsent_d = nearest_emerged_d;
823 } else if(nearest_emergefull_d != -1){
824 new_nearest_unsent_d = nearest_emergefull_d;
826 if(d > g_settings->getS16("max_block_send_distance")){
827 new_nearest_unsent_d = 0;
828 m_nothing_to_send_pause_timer = 2.0;
829 /*infostream<<"GetNextBlocks(): d wrapped around for "
830 <<server->getPlayerName(peer_id)
831 <<"; setting to 0 and pausing"<<std::endl;*/
833 if(nearest_sent_d != -1)
834 new_nearest_unsent_d = nearest_sent_d;
836 new_nearest_unsent_d = d;
840 if(new_nearest_unsent_d != -1)
841 m_nearest_unsent_d = new_nearest_unsent_d;
843 /*timer_result = timer.stop(true);
844 if(timer_result != 0)
845 infostream<<"GetNextBlocks duration: "<<timer_result<<" (!=0)"<<std::endl;*/
848 void RemoteClient::GotBlock(v3s16 p)
850 if(m_blocks_sending.find(p) != NULL)
851 m_blocks_sending.remove(p);
854 /*infostream<<"RemoteClient::GotBlock(): Didn't find in"
855 " m_blocks_sending"<<std::endl;*/
856 m_excess_gotblocks++;
858 m_blocks_sent.insert(p, true);
861 void RemoteClient::SentBlock(v3s16 p)
863 if(m_blocks_sending.find(p) == NULL)
864 m_blocks_sending.insert(p, 0.0);
866 infostream<<"RemoteClient::SentBlock(): Sent block"
867 " already in m_blocks_sending"<<std::endl;
870 void RemoteClient::SetBlockNotSent(v3s16 p)
872 m_nearest_unsent_d = 0;
874 if(m_blocks_sending.find(p) != NULL)
875 m_blocks_sending.remove(p);
876 if(m_blocks_sent.find(p) != NULL)
877 m_blocks_sent.remove(p);
880 void RemoteClient::SetBlocksNotSent(core::map<v3s16, MapBlock*> &blocks)
882 m_nearest_unsent_d = 0;
884 for(core::map<v3s16, MapBlock*>::Iterator
885 i = blocks.getIterator();
886 i.atEnd()==false; i++)
888 v3s16 p = i.getNode()->getKey();
890 if(m_blocks_sending.find(p) != NULL)
891 m_blocks_sending.remove(p);
892 if(m_blocks_sent.find(p) != NULL)
893 m_blocks_sent.remove(p);
901 PlayerInfo::PlayerInfo()
907 void PlayerInfo::PrintLine(std::ostream *s)
910 (*s)<<"\""<<name<<"\" ("
911 <<(position.X/10)<<","<<(position.Y/10)
912 <<","<<(position.Z/10)<<") ";
914 (*s)<<" avg_rtt="<<avg_rtt;
923 const std::string &path_world,
924 const std::string &path_config,
925 const SubgameSpec &gamespec,
926 bool simple_singleplayer_mode
928 m_path_world(path_world),
929 m_path_config(path_config),
930 m_gamespec(gamespec),
931 m_simple_singleplayer_mode(simple_singleplayer_mode),
932 m_async_fatal_error(""),
934 m_con(PROTOCOL_ID, 512, CONNECTION_TIMEOUT, this),
935 m_banmanager(path_world+DIR_DELIM+"ipban.txt"),
937 m_itemdef(createItemDefManager()),
938 m_nodedef(createNodeDefManager()),
939 m_craftdef(createCraftDefManager()),
940 m_event(new EventManager()),
942 m_emergethread(this),
943 m_time_of_day_send_timer(0),
945 m_shutdown_requested(false),
946 m_ignore_map_edit_events(false),
947 m_ignore_map_edit_events_peer_id(0)
949 m_liquid_transform_timer = 0.0;
950 m_print_info_timer = 0.0;
951 m_objectdata_timer = 0.0;
952 m_emergethread_trigger_timer = 0.0;
953 m_savemap_timer = 0.0;
957 m_step_dtime_mutex.Init();
961 throw ServerError("Supplied empty world path");
963 if(!gamespec.isValid())
964 throw ServerError("Supplied invalid gamespec");
966 infostream<<"Server created for gameid \""<<m_gamespec.id<<"\"";
967 if(m_simple_singleplayer_mode)
968 infostream<<" in simple singleplayer mode"<<std::endl;
970 infostream<<std::endl;
971 infostream<<"- world: "<<m_path_world<<std::endl;
972 infostream<<"- config: "<<m_path_config<<std::endl;
973 infostream<<"- game: "<<m_gamespec.path<<std::endl;
975 // Add world mod search path
976 m_modspaths.push_front(m_path_world + DIR_DELIM + "worldmods");
977 // Add addon mod search path
978 for(std::set<std::string>::const_iterator i = m_gamespec.mods_paths.begin();
979 i != m_gamespec.mods_paths.end(); i++)
980 m_modspaths.push_front((*i));
982 // Print out mod search paths
983 for(core::list<std::string>::Iterator i = m_modspaths.begin();
984 i != m_modspaths.end(); i++){
985 std::string modspath = *i;
986 infostream<<"- mods: "<<modspath<<std::endl;
989 // Path to builtin.lua
990 std::string builtinpath = getBuiltinLuaPath() + DIR_DELIM + "builtin.lua";
992 // Create world if it doesn't exist
993 if(!initializeWorld(m_path_world, m_gamespec.id))
994 throw ServerError("Failed to initialize world");
997 JMutexAutoLock envlock(m_env_mutex);
998 JMutexAutoLock conlock(m_con_mutex);
1000 // Initialize scripting
1002 infostream<<"Server: Initializing Lua"<<std::endl;
1003 m_lua = script_init();
1006 scriptapi_export(m_lua, this);
1007 // Load and run builtin.lua
1008 infostream<<"Server: Loading builtin.lua [\""
1009 <<builtinpath<<"\"]"<<std::endl;
1010 bool success = scriptapi_loadmod(m_lua, builtinpath, "__builtin");
1012 errorstream<<"Server: Failed to load and run "
1013 <<builtinpath<<std::endl;
1014 throw ModError("Failed to load and run "+builtinpath);
1016 // Find mods in mod search paths
1017 m_mods = getMods(m_modspaths);
1019 infostream<<"Server: Loading mods: ";
1020 for(core::list<ModSpec>::Iterator i = m_mods.begin();
1021 i != m_mods.end(); i++){
1022 const ModSpec &mod = *i;
1023 infostream<<mod.name<<" ";
1025 infostream<<std::endl;
1026 // Load and run "mod" scripts
1027 for(core::list<ModSpec>::Iterator i = m_mods.begin();
1028 i != m_mods.end(); i++){
1029 const ModSpec &mod = *i;
1030 std::string scriptpath = mod.path + DIR_DELIM + "init.lua";
1031 infostream<<" ["<<padStringRight(mod.name, 12)<<"] [\""
1032 <<scriptpath<<"\"]"<<std::endl;
1033 bool success = scriptapi_loadmod(m_lua, scriptpath, mod.name);
1035 errorstream<<"Server: Failed to load and run "
1036 <<scriptpath<<std::endl;
1037 throw ModError("Failed to load and run "+scriptpath);
1041 // Read Textures and calculate sha1 sums
1044 // Apply item aliases in the node definition manager
1045 m_nodedef->updateAliases(m_itemdef);
1047 // Initialize Environment
1049 m_env = new ServerEnvironment(new ServerMap(path_world, this), m_lua,
1052 // Give environment reference to scripting api
1053 scriptapi_add_environment(m_lua, m_env);
1055 // Register us to receive map edit events
1056 m_env->getMap().addEventReceiver(this);
1058 // If file exists, load environment metadata
1059 if(fs::PathExists(m_path_world+DIR_DELIM+"env_meta.txt"))
1061 infostream<<"Server: Loading environment metadata"<<std::endl;
1062 m_env->loadMeta(m_path_world);
1066 infostream<<"Server: Loading players"<<std::endl;
1067 m_env->deSerializePlayers(m_path_world);
1070 Add some test ActiveBlockModifiers to environment
1072 add_legacy_abms(m_env, m_nodedef);
1077 infostream<<"Server destructing"<<std::endl;
1080 Send shutdown message
1083 JMutexAutoLock conlock(m_con_mutex);
1085 std::wstring line = L"*** Server shutting down";
1088 Send the message to clients
1090 for(core::map<u16, RemoteClient*>::Iterator
1091 i = m_clients.getIterator();
1092 i.atEnd() == false; i++)
1094 // Get client and check that it is valid
1095 RemoteClient *client = i.getNode()->getValue();
1096 assert(client->peer_id == i.getNode()->getKey());
1097 if(client->serialization_version == SER_FMT_VER_INVALID)
1101 SendChatMessage(client->peer_id, line);
1103 catch(con::PeerNotFoundException &e)
1109 JMutexAutoLock envlock(m_env_mutex);
1114 infostream<<"Server: Saving players"<<std::endl;
1115 m_env->serializePlayers(m_path_world);
1118 Save environment metadata
1120 infostream<<"Server: Saving environment metadata"<<std::endl;
1121 m_env->saveMeta(m_path_world);
1133 JMutexAutoLock clientslock(m_con_mutex);
1135 for(core::map<u16, RemoteClient*>::Iterator
1136 i = m_clients.getIterator();
1137 i.atEnd() == false; i++)
1140 // NOTE: These are removed by env destructor
1142 u16 peer_id = i.getNode()->getKey();
1143 JMutexAutoLock envlock(m_env_mutex);
1144 m_env->removePlayer(peer_id);
1148 delete i.getNode()->getValue();
1152 // Delete things in the reverse order of creation
1159 // Deinitialize scripting
1160 infostream<<"Server: Deinitializing scripting"<<std::endl;
1161 script_deinit(m_lua);
1164 void Server::start(unsigned short port)
1166 DSTACK(__FUNCTION_NAME);
1167 infostream<<"Starting server on port "<<port<<"..."<<std::endl;
1169 // Stop thread if already running
1172 // Initialize connection
1173 m_con.SetTimeoutMs(30);
1177 m_thread.setRun(true);
1180 // ASCII art for the win!
1182 <<" .__ __ __ "<<std::endl
1183 <<" _____ |__| ____ _____/ |_ ____ _______/ |_ "<<std::endl
1184 <<" / \\| |/ \\_/ __ \\ __\\/ __ \\ / ___/\\ __\\"<<std::endl
1185 <<"| Y Y \\ | | \\ ___/| | \\ ___/ \\___ \\ | | "<<std::endl
1186 <<"|__|_| /__|___| /\\___ >__| \\___ >____ > |__| "<<std::endl
1187 <<" \\/ \\/ \\/ \\/ \\/ "<<std::endl;
1188 actionstream<<"World at ["<<m_path_world<<"]"<<std::endl;
1189 actionstream<<"Server for gameid=\""<<m_gamespec.id
1190 <<"\" listening on port "<<port<<"."<<std::endl;
1195 DSTACK(__FUNCTION_NAME);
1197 infostream<<"Server: Stopping and waiting threads"<<std::endl;
1199 // Stop threads (set run=false first so both start stopping)
1200 m_thread.setRun(false);
1201 m_emergethread.setRun(false);
1203 m_emergethread.stop();
1205 infostream<<"Server: Threads stopped"<<std::endl;
1208 void Server::step(float dtime)
1210 DSTACK(__FUNCTION_NAME);
1215 JMutexAutoLock lock(m_step_dtime_mutex);
1216 m_step_dtime += dtime;
1218 // Throw if fatal error occurred in thread
1219 std::string async_err = m_async_fatal_error.get();
1220 if(async_err != ""){
1221 throw ServerError(async_err);
1225 void Server::AsyncRunStep()
1227 DSTACK(__FUNCTION_NAME);
1229 g_profiler->add("Server::AsyncRunStep (num)", 1);
1233 JMutexAutoLock lock1(m_step_dtime_mutex);
1234 dtime = m_step_dtime;
1238 // Send blocks to clients
1245 g_profiler->add("Server::AsyncRunStep with dtime (num)", 1);
1247 //infostream<<"Server steps "<<dtime<<std::endl;
1248 //infostream<<"Server::AsyncRunStep(): dtime="<<dtime<<std::endl;
1251 JMutexAutoLock lock1(m_step_dtime_mutex);
1252 m_step_dtime -= dtime;
1259 m_uptime.set(m_uptime.get() + dtime);
1263 // Process connection's timeouts
1264 JMutexAutoLock lock2(m_con_mutex);
1265 ScopeProfiler sp(g_profiler, "Server: connection timeout processing");
1266 m_con.RunTimeouts(dtime);
1270 // This has to be called so that the client list gets synced
1271 // with the peer list of the connection
1272 handlePeerChanges();
1276 Update time of day and overall game time
1279 JMutexAutoLock envlock(m_env_mutex);
1281 m_env->setTimeOfDaySpeed(g_settings->getFloat("time_speed"));
1284 Send to clients at constant intervals
1287 m_time_of_day_send_timer -= dtime;
1288 if(m_time_of_day_send_timer < 0.0)
1290 m_time_of_day_send_timer = g_settings->getFloat("time_send_interval");
1292 //JMutexAutoLock envlock(m_env_mutex);
1293 JMutexAutoLock conlock(m_con_mutex);
1295 for(core::map<u16, RemoteClient*>::Iterator
1296 i = m_clients.getIterator();
1297 i.atEnd() == false; i++)
1299 RemoteClient *client = i.getNode()->getValue();
1300 SharedBuffer<u8> data = makePacket_TOCLIENT_TIME_OF_DAY(
1301 m_env->getTimeOfDay(), g_settings->getFloat("time_speed"));
1303 m_con.Send(client->peer_id, 0, data, true);
1309 JMutexAutoLock lock(m_env_mutex);
1311 ScopeProfiler sp(g_profiler, "SEnv step");
1312 ScopeProfiler sp2(g_profiler, "SEnv step avg", SPT_AVG);
1316 const float map_timer_and_unload_dtime = 2.92;
1317 if(m_map_timer_and_unload_interval.step(dtime, map_timer_and_unload_dtime))
1319 JMutexAutoLock lock(m_env_mutex);
1320 // Run Map's timers and unload unused data
1321 ScopeProfiler sp(g_profiler, "Server: map timer and unload");
1322 m_env->getMap().timerUpdate(map_timer_and_unload_dtime,
1323 g_settings->getFloat("server_unload_unused_data_timeout"));
1334 JMutexAutoLock lock(m_env_mutex);
1335 JMutexAutoLock lock2(m_con_mutex);
1337 ScopeProfiler sp(g_profiler, "Server: handle players");
1339 for(core::map<u16, RemoteClient*>::Iterator
1340 i = m_clients.getIterator();
1341 i.atEnd() == false; i++)
1343 RemoteClient *client = i.getNode()->getValue();
1344 PlayerSAO *playersao = getPlayerSAO(client->peer_id);
1345 if(playersao == NULL)
1349 Handle player HPs (die if hp=0)
1351 if(playersao->getHP() == 0 && playersao->m_hp_not_sent)
1352 DiePlayer(client->peer_id);
1355 Send player inventories and HPs if necessary
1357 if(playersao->m_teleported){
1358 SendMovePlayer(client->peer_id);
1359 playersao->m_teleported = false;
1361 if(playersao->m_inventory_not_sent){
1362 UpdateCrafting(client->peer_id);
1363 SendInventory(client->peer_id);
1365 if(playersao->m_hp_not_sent){
1366 SendPlayerHP(client->peer_id);
1371 /* Transform liquids */
1372 m_liquid_transform_timer += dtime;
1373 if(m_liquid_transform_timer >= 1.00)
1375 m_liquid_transform_timer -= 1.00;
1377 JMutexAutoLock lock(m_env_mutex);
1379 ScopeProfiler sp(g_profiler, "Server: liquid transform");
1381 core::map<v3s16, MapBlock*> modified_blocks;
1382 m_env->getMap().transformLiquids(modified_blocks);
1387 core::map<v3s16, MapBlock*> lighting_modified_blocks;
1388 ServerMap &map = ((ServerMap&)m_env->getMap());
1389 map.updateLighting(modified_blocks, lighting_modified_blocks);
1391 // Add blocks modified by lighting to modified_blocks
1392 for(core::map<v3s16, MapBlock*>::Iterator
1393 i = lighting_modified_blocks.getIterator();
1394 i.atEnd() == false; i++)
1396 MapBlock *block = i.getNode()->getValue();
1397 modified_blocks.insert(block->getPos(), block);
1401 Set the modified blocks unsent for all the clients
1404 JMutexAutoLock lock2(m_con_mutex);
1406 for(core::map<u16, RemoteClient*>::Iterator
1407 i = m_clients.getIterator();
1408 i.atEnd() == false; i++)
1410 RemoteClient *client = i.getNode()->getValue();
1412 if(modified_blocks.size() > 0)
1414 // Remove block from sent history
1415 client->SetBlocksNotSent(modified_blocks);
1420 // Periodically print some info
1422 float &counter = m_print_info_timer;
1428 JMutexAutoLock lock2(m_con_mutex);
1430 if(m_clients.size() != 0)
1431 infostream<<"Players:"<<std::endl;
1432 for(core::map<u16, RemoteClient*>::Iterator
1433 i = m_clients.getIterator();
1434 i.atEnd() == false; i++)
1436 //u16 peer_id = i.getNode()->getKey();
1437 RemoteClient *client = i.getNode()->getValue();
1438 Player *player = m_env->getPlayer(client->peer_id);
1441 infostream<<"* "<<player->getName()<<"\t";
1442 client->PrintInfo(infostream);
1447 //if(g_settings->getBool("enable_experimental"))
1451 Check added and deleted active objects
1454 //infostream<<"Server: Checking added and deleted active objects"<<std::endl;
1455 JMutexAutoLock envlock(m_env_mutex);
1456 JMutexAutoLock conlock(m_con_mutex);
1458 ScopeProfiler sp(g_profiler, "Server: checking added and deleted objs");
1460 // Radius inside which objects are active
1461 s16 radius = g_settings->getS16("active_object_send_range_blocks");
1462 radius *= MAP_BLOCKSIZE;
1464 for(core::map<u16, RemoteClient*>::Iterator
1465 i = m_clients.getIterator();
1466 i.atEnd() == false; i++)
1468 RemoteClient *client = i.getNode()->getValue();
1470 // If definitions and textures have not been sent, don't
1471 // send objects either
1472 if(!client->definitions_sent)
1475 Player *player = m_env->getPlayer(client->peer_id);
1478 // This can happen if the client timeouts somehow
1479 /*infostream<<"WARNING: "<<__FUNCTION_NAME<<": Client "
1481 <<" has no associated player"<<std::endl;*/
1484 v3s16 pos = floatToInt(player->getPosition(), BS);
1486 core::map<u16, bool> removed_objects;
1487 core::map<u16, bool> added_objects;
1488 m_env->getRemovedActiveObjects(pos, radius,
1489 client->m_known_objects, removed_objects);
1490 m_env->getAddedActiveObjects(pos, radius,
1491 client->m_known_objects, added_objects);
1493 // Ignore if nothing happened
1494 if(removed_objects.size() == 0 && added_objects.size() == 0)
1496 //infostream<<"active objects: none changed"<<std::endl;
1500 std::string data_buffer;
1504 // Handle removed objects
1505 writeU16((u8*)buf, removed_objects.size());
1506 data_buffer.append(buf, 2);
1507 for(core::map<u16, bool>::Iterator
1508 i = removed_objects.getIterator();
1509 i.atEnd()==false; i++)
1512 u16 id = i.getNode()->getKey();
1513 ServerActiveObject* obj = m_env->getActiveObject(id);
1515 // Add to data buffer for sending
1516 writeU16((u8*)buf, i.getNode()->getKey());
1517 data_buffer.append(buf, 2);
1519 // Remove from known objects
1520 client->m_known_objects.remove(i.getNode()->getKey());
1522 if(obj && obj->m_known_by_count > 0)
1523 obj->m_known_by_count--;
1526 // Handle added objects
1527 writeU16((u8*)buf, added_objects.size());
1528 data_buffer.append(buf, 2);
1529 for(core::map<u16, bool>::Iterator
1530 i = added_objects.getIterator();
1531 i.atEnd()==false; i++)
1534 u16 id = i.getNode()->getKey();
1535 ServerActiveObject* obj = m_env->getActiveObject(id);
1538 u8 type = ACTIVEOBJECT_TYPE_INVALID;
1540 infostream<<"WARNING: "<<__FUNCTION_NAME
1541 <<": NULL object"<<std::endl;
1543 type = obj->getSendType();
1545 // Add to data buffer for sending
1546 writeU16((u8*)buf, id);
1547 data_buffer.append(buf, 2);
1548 writeU8((u8*)buf, type);
1549 data_buffer.append(buf, 1);
1552 data_buffer.append(serializeLongString(
1553 obj->getClientInitializationData()));
1555 data_buffer.append(serializeLongString(""));
1557 // Add to known objects
1558 client->m_known_objects.insert(i.getNode()->getKey(), false);
1561 obj->m_known_by_count++;
1565 SharedBuffer<u8> reply(2 + data_buffer.size());
1566 writeU16(&reply[0], TOCLIENT_ACTIVE_OBJECT_REMOVE_ADD);
1567 memcpy((char*)&reply[2], data_buffer.c_str(),
1568 data_buffer.size());
1570 m_con.Send(client->peer_id, 0, reply, true);
1572 verbosestream<<"Server: Sent object remove/add: "
1573 <<removed_objects.size()<<" removed, "
1574 <<added_objects.size()<<" added, "
1575 <<"packet size is "<<reply.getSize()<<std::endl;
1580 Collect a list of all the objects known by the clients
1581 and report it back to the environment.
1584 core::map<u16, bool> all_known_objects;
1586 for(core::map<u16, RemoteClient*>::Iterator
1587 i = m_clients.getIterator();
1588 i.atEnd() == false; i++)
1590 RemoteClient *client = i.getNode()->getValue();
1591 // Go through all known objects of client
1592 for(core::map<u16, bool>::Iterator
1593 i = client->m_known_objects.getIterator();
1594 i.atEnd()==false; i++)
1596 u16 id = i.getNode()->getKey();
1597 all_known_objects[id] = true;
1601 m_env->setKnownActiveObjects(whatever);
1607 Send object messages
1610 JMutexAutoLock envlock(m_env_mutex);
1611 JMutexAutoLock conlock(m_con_mutex);
1613 ScopeProfiler sp(g_profiler, "Server: sending object messages");
1616 // Value = data sent by object
1617 core::map<u16, core::list<ActiveObjectMessage>* > buffered_messages;
1619 // Get active object messages from environment
1622 ActiveObjectMessage aom = m_env->getActiveObjectMessage();
1626 core::list<ActiveObjectMessage>* message_list = NULL;
1627 core::map<u16, core::list<ActiveObjectMessage>* >::Node *n;
1628 n = buffered_messages.find(aom.id);
1631 message_list = new core::list<ActiveObjectMessage>;
1632 buffered_messages.insert(aom.id, message_list);
1636 message_list = n->getValue();
1638 message_list->push_back(aom);
1641 // Route data to every client
1642 for(core::map<u16, RemoteClient*>::Iterator
1643 i = m_clients.getIterator();
1644 i.atEnd()==false; i++)
1646 RemoteClient *client = i.getNode()->getValue();
1647 std::string reliable_data;
1648 std::string unreliable_data;
1649 // Go through all objects in message buffer
1650 for(core::map<u16, core::list<ActiveObjectMessage>* >::Iterator
1651 j = buffered_messages.getIterator();
1652 j.atEnd()==false; j++)
1654 // If object is not known by client, skip it
1655 u16 id = j.getNode()->getKey();
1656 if(client->m_known_objects.find(id) == NULL)
1658 // Get message list of object
1659 core::list<ActiveObjectMessage>* list = j.getNode()->getValue();
1660 // Go through every message
1661 for(core::list<ActiveObjectMessage>::Iterator
1662 k = list->begin(); k != list->end(); k++)
1664 // Compose the full new data with header
1665 ActiveObjectMessage aom = *k;
1666 std::string new_data;
1669 writeU16((u8*)&buf[0], aom.id);
1670 new_data.append(buf, 2);
1672 new_data += serializeString(aom.datastring);
1673 // Add data to buffer
1675 reliable_data += new_data;
1677 unreliable_data += new_data;
1681 reliable_data and unreliable_data are now ready.
1684 if(reliable_data.size() > 0)
1686 SharedBuffer<u8> reply(2 + reliable_data.size());
1687 writeU16(&reply[0], TOCLIENT_ACTIVE_OBJECT_MESSAGES);
1688 memcpy((char*)&reply[2], reliable_data.c_str(),
1689 reliable_data.size());
1691 m_con.Send(client->peer_id, 0, reply, true);
1693 if(unreliable_data.size() > 0)
1695 SharedBuffer<u8> reply(2 + unreliable_data.size());
1696 writeU16(&reply[0], TOCLIENT_ACTIVE_OBJECT_MESSAGES);
1697 memcpy((char*)&reply[2], unreliable_data.c_str(),
1698 unreliable_data.size());
1699 // Send as unreliable
1700 m_con.Send(client->peer_id, 0, reply, false);
1703 /*if(reliable_data.size() > 0 || unreliable_data.size() > 0)
1705 infostream<<"Server: Size of object message data: "
1706 <<"reliable: "<<reliable_data.size()
1707 <<", unreliable: "<<unreliable_data.size()
1712 // Clear buffered_messages
1713 for(core::map<u16, core::list<ActiveObjectMessage>* >::Iterator
1714 i = buffered_messages.getIterator();
1715 i.atEnd()==false; i++)
1717 delete i.getNode()->getValue();
1721 } // enable_experimental
1724 Send queued-for-sending map edit events.
1727 // We will be accessing the environment and the connection
1728 JMutexAutoLock lock(m_env_mutex);
1729 JMutexAutoLock conlock(m_con_mutex);
1731 // Don't send too many at a time
1734 // Single change sending is disabled if queue size is not small
1735 bool disable_single_change_sending = false;
1736 if(m_unsent_map_edit_queue.size() >= 4)
1737 disable_single_change_sending = true;
1739 int event_count = m_unsent_map_edit_queue.size();
1741 // We'll log the amount of each
1744 while(m_unsent_map_edit_queue.size() != 0)
1746 MapEditEvent* event = m_unsent_map_edit_queue.pop_front();
1748 // Players far away from the change are stored here.
1749 // Instead of sending the changes, MapBlocks are set not sent
1751 core::list<u16> far_players;
1753 if(event->type == MEET_ADDNODE)
1755 //infostream<<"Server: MEET_ADDNODE"<<std::endl;
1756 prof.add("MEET_ADDNODE", 1);
1757 if(disable_single_change_sending)
1758 sendAddNode(event->p, event->n, event->already_known_by_peer,
1761 sendAddNode(event->p, event->n, event->already_known_by_peer,
1764 else if(event->type == MEET_REMOVENODE)
1766 //infostream<<"Server: MEET_REMOVENODE"<<std::endl;
1767 prof.add("MEET_REMOVENODE", 1);
1768 if(disable_single_change_sending)
1769 sendRemoveNode(event->p, event->already_known_by_peer,
1772 sendRemoveNode(event->p, event->already_known_by_peer,
1775 else if(event->type == MEET_BLOCK_NODE_METADATA_CHANGED)
1777 infostream<<"Server: MEET_BLOCK_NODE_METADATA_CHANGED"<<std::endl;
1778 prof.add("MEET_BLOCK_NODE_METADATA_CHANGED", 1);
1779 setBlockNotSent(event->p);
1781 else if(event->type == MEET_OTHER)
1783 infostream<<"Server: MEET_OTHER"<<std::endl;
1784 prof.add("MEET_OTHER", 1);
1785 for(core::map<v3s16, bool>::Iterator
1786 i = event->modified_blocks.getIterator();
1787 i.atEnd()==false; i++)
1789 v3s16 p = i.getNode()->getKey();
1795 prof.add("unknown", 1);
1796 infostream<<"WARNING: Server: Unknown MapEditEvent "
1797 <<((u32)event->type)<<std::endl;
1801 Set blocks not sent to far players
1803 if(far_players.size() > 0)
1805 // Convert list format to that wanted by SetBlocksNotSent
1806 core::map<v3s16, MapBlock*> modified_blocks2;
1807 for(core::map<v3s16, bool>::Iterator
1808 i = event->modified_blocks.getIterator();
1809 i.atEnd()==false; i++)
1811 v3s16 p = i.getNode()->getKey();
1812 modified_blocks2.insert(p,
1813 m_env->getMap().getBlockNoCreateNoEx(p));
1815 // Set blocks not sent
1816 for(core::list<u16>::Iterator
1817 i = far_players.begin();
1818 i != far_players.end(); i++)
1821 RemoteClient *client = getClient(peer_id);
1824 client->SetBlocksNotSent(modified_blocks2);
1830 /*// Don't send too many at a time
1832 if(count >= 1 && m_unsent_map_edit_queue.size() < 100)
1836 if(event_count >= 5){
1837 infostream<<"Server: MapEditEvents:"<<std::endl;
1838 prof.print(infostream);
1839 } else if(event_count != 0){
1840 verbosestream<<"Server: MapEditEvents:"<<std::endl;
1841 prof.print(verbosestream);
1847 Trigger emergethread (it somehow gets to a non-triggered but
1848 bysy state sometimes)
1851 float &counter = m_emergethread_trigger_timer;
1857 m_emergethread.trigger();
1861 // Save map, players and auth stuff
1863 float &counter = m_savemap_timer;
1865 if(counter >= g_settings->getFloat("server_map_save_interval"))
1868 JMutexAutoLock lock(m_env_mutex);
1870 ScopeProfiler sp(g_profiler, "Server: saving stuff");
1873 if(m_banmanager.isModified())
1874 m_banmanager.save();
1876 // Save changed parts of map
1877 m_env->getMap().save(MOD_STATE_WRITE_NEEDED);
1880 m_env->serializePlayers(m_path_world);
1882 // Save environment metadata
1883 m_env->saveMeta(m_path_world);
1888 void Server::Receive()
1890 DSTACK(__FUNCTION_NAME);
1891 SharedBuffer<u8> data;
1896 JMutexAutoLock conlock(m_con_mutex);
1897 datasize = m_con.Receive(peer_id, data);
1900 // This has to be called so that the client list gets synced
1901 // with the peer list of the connection
1902 handlePeerChanges();
1904 ProcessData(*data, datasize, peer_id);
1906 catch(con::InvalidIncomingDataException &e)
1908 infostream<<"Server::Receive(): "
1909 "InvalidIncomingDataException: what()="
1910 <<e.what()<<std::endl;
1912 catch(con::PeerNotFoundException &e)
1914 //NOTE: This is not needed anymore
1916 // The peer has been disconnected.
1917 // Find the associated player and remove it.
1919 /*JMutexAutoLock envlock(m_env_mutex);
1921 infostream<<"ServerThread: peer_id="<<peer_id
1922 <<" has apparently closed connection. "
1923 <<"Removing player."<<std::endl;
1925 m_env->removePlayer(peer_id);*/
1929 void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
1931 DSTACK(__FUNCTION_NAME);
1932 // Environment is locked first.
1933 JMutexAutoLock envlock(m_env_mutex);
1934 JMutexAutoLock conlock(m_con_mutex);
1936 ScopeProfiler sp(g_profiler, "Server::ProcessData");
1939 Address address = m_con.GetPeerAddress(peer_id);
1940 std::string addr_s = address.serializeString();
1942 // drop player if is ip is banned
1943 if(m_banmanager.isIpBanned(addr_s)){
1944 infostream<<"Server: A banned client tried to connect from "
1945 <<addr_s<<"; banned name was "
1946 <<m_banmanager.getBanName(addr_s)<<std::endl;
1947 // This actually doesn't seem to transfer to the client
1948 SendAccessDenied(m_con, peer_id,
1949 L"Your ip is banned. Banned name was "
1950 +narrow_to_wide(m_banmanager.getBanName(addr_s)));
1951 m_con.DeletePeer(peer_id);
1955 catch(con::PeerNotFoundException &e)
1957 infostream<<"Server::ProcessData(): Cancelling: peer "
1958 <<peer_id<<" not found"<<std::endl;
1962 std::string addr_s = m_con.GetPeerAddress(peer_id).serializeString();
1964 u8 peer_ser_ver = getClient(peer_id)->serialization_version;
1972 ToServerCommand command = (ToServerCommand)readU16(&data[0]);
1974 if(command == TOSERVER_INIT)
1976 // [0] u16 TOSERVER_INIT
1977 // [2] u8 SER_FMT_VER_HIGHEST
1978 // [3] u8[20] player_name
1979 // [23] u8[28] password <--- can be sent without this, from old versions
1981 if(datasize < 2+1+PLAYERNAME_SIZE)
1984 verbosestream<<"Server: Got TOSERVER_INIT from "
1985 <<peer_id<<std::endl;
1987 // First byte after command is maximum supported
1988 // serialization version
1989 u8 client_max = data[2];
1990 u8 our_max = SER_FMT_VER_HIGHEST;
1991 // Use the highest version supported by both
1992 u8 deployed = core::min_(client_max, our_max);
1993 // If it's lower than the lowest supported, give up.
1994 if(deployed < SER_FMT_VER_LOWEST)
1995 deployed = SER_FMT_VER_INVALID;
1997 //peer->serialization_version = deployed;
1998 getClient(peer_id)->pending_serialization_version = deployed;
2000 if(deployed == SER_FMT_VER_INVALID)
2002 actionstream<<"Server: A mismatched client tried to connect from "
2003 <<addr_s<<std::endl;
2004 infostream<<"Server: Cannot negotiate "
2005 "serialization version with peer "
2006 <<peer_id<<std::endl;
2007 SendAccessDenied(m_con, peer_id, std::wstring(
2008 L"Your client's version is not supported.\n"
2009 L"Server version is ")
2010 + narrow_to_wide(VERSION_STRING) + L"."
2016 Read and check network protocol version
2019 u16 net_proto_version = 0;
2020 if(datasize >= 2+1+PLAYERNAME_SIZE+PASSWORD_SIZE+2)
2022 net_proto_version = readU16(&data[2+1+PLAYERNAME_SIZE+PASSWORD_SIZE]);
2025 getClient(peer_id)->net_proto_version = net_proto_version;
2027 if(net_proto_version == 0)
2029 actionstream<<"Server: An old tried to connect from "<<addr_s
2031 SendAccessDenied(m_con, peer_id, std::wstring(
2032 L"Your client's version is not supported.\n"
2033 L"Server version is ")
2034 + narrow_to_wide(VERSION_STRING) + L"."
2039 if(g_settings->getBool("strict_protocol_version_checking"))
2041 if(net_proto_version != PROTOCOL_VERSION)
2043 actionstream<<"Server: A mismatched client tried to connect"
2044 <<" from "<<addr_s<<std::endl;
2045 SendAccessDenied(m_con, peer_id, std::wstring(
2046 L"Your client's version is not supported.\n"
2047 L"Server version is ")
2048 + narrow_to_wide(VERSION_STRING) + L",\n"
2049 + L"server's PROTOCOL_VERSION is "
2050 + narrow_to_wide(itos(PROTOCOL_VERSION))
2051 + L", client's PROTOCOL_VERSION is "
2052 + narrow_to_wide(itos(net_proto_version))
2063 char playername[PLAYERNAME_SIZE];
2064 for(u32 i=0; i<PLAYERNAME_SIZE-1; i++)
2066 playername[i] = data[3+i];
2068 playername[PLAYERNAME_SIZE-1] = 0;
2070 if(playername[0]=='\0')
2072 actionstream<<"Server: Player with an empty name "
2073 <<"tried to connect from "<<addr_s<<std::endl;
2074 SendAccessDenied(m_con, peer_id,
2079 if(string_allowed(playername, PLAYERNAME_ALLOWED_CHARS)==false)
2081 actionstream<<"Server: Player with an invalid name "
2082 <<"tried to connect from "<<addr_s<<std::endl;
2083 SendAccessDenied(m_con, peer_id,
2084 L"Name contains unallowed characters");
2088 infostream<<"Server: New connection: \""<<playername<<"\" from "
2089 <<m_con.GetPeerAddress(peer_id).serializeString()<<std::endl;
2092 char given_password[PASSWORD_SIZE];
2093 if(datasize < 2+1+PLAYERNAME_SIZE+PASSWORD_SIZE)
2095 // old version - assume blank password
2096 given_password[0] = 0;
2100 for(u32 i=0; i<PASSWORD_SIZE-1; i++)
2102 given_password[i] = data[23+i];
2104 given_password[PASSWORD_SIZE-1] = 0;
2107 if(!base64_is_valid(given_password)){
2108 infostream<<"Server: "<<playername
2109 <<" supplied invalid password hash"<<std::endl;
2110 SendAccessDenied(m_con, peer_id, L"Invalid password hash");
2114 std::string checkpwd; // Password hash to check against
2115 bool has_auth = scriptapi_get_auth(m_lua, playername, &checkpwd, NULL);
2117 // If no authentication info exists for user, create it
2119 if(!isSingleplayer() &&
2120 g_settings->getBool("disallow_empty_password") &&
2121 std::string(given_password) == ""){
2122 SendAccessDenied(m_con, peer_id, L"Empty passwords are "
2123 L"disallowed. Set a password and try again.");
2126 std::wstring raw_default_password =
2127 narrow_to_wide(g_settings->get("default_password"));
2128 std::string initial_password =
2129 translatePassword(playername, raw_default_password);
2131 // If default_password is empty, allow any initial password
2132 if (raw_default_password.length() == 0)
2133 initial_password = given_password;
2135 scriptapi_create_auth(m_lua, playername, initial_password);
2138 has_auth = scriptapi_get_auth(m_lua, playername, &checkpwd, NULL);
2141 SendAccessDenied(m_con, peer_id, L"Not allowed to login");
2145 if(given_password != checkpwd){
2146 infostream<<"Server: peer_id="<<peer_id
2147 <<": supplied invalid password for "
2148 <<playername<<std::endl;
2149 SendAccessDenied(m_con, peer_id, L"Invalid password");
2153 // Do not allow multiple players in simple singleplayer mode.
2154 // This isn't a perfect way to do it, but will suffice for now.
2155 if(m_simple_singleplayer_mode && m_clients.size() > 1){
2156 infostream<<"Server: Not allowing another client to connect in"
2157 <<" simple singleplayer mode"<<std::endl;
2158 SendAccessDenied(m_con, peer_id,
2159 L"Running in simple singleplayer mode.");
2163 // Enforce user limit.
2164 // Don't enforce for users that have some admin right
2165 if(m_clients.size() >= g_settings->getU16("max_users") &&
2166 !checkPriv(playername, "server") &&
2167 !checkPriv(playername, "ban") &&
2168 !checkPriv(playername, "privs") &&
2169 !checkPriv(playername, "password") &&
2170 playername != g_settings->get("name"))
2172 actionstream<<"Server: "<<playername<<" tried to join, but there"
2173 <<" are already max_users="
2174 <<g_settings->getU16("max_users")<<" players."<<std::endl;
2175 SendAccessDenied(m_con, peer_id, L"Too many users.");
2180 PlayerSAO *playersao = emergePlayer(playername, peer_id);
2182 // If failed, cancel
2183 if(playersao == NULL)
2185 errorstream<<"Server: peer_id="<<peer_id
2186 <<": failed to emerge player"<<std::endl;
2191 Answer with a TOCLIENT_INIT
2194 SharedBuffer<u8> reply(2+1+6+8);
2195 writeU16(&reply[0], TOCLIENT_INIT);
2196 writeU8(&reply[2], deployed);
2197 writeV3S16(&reply[2+1], floatToInt(playersao->getPlayer()->getPosition()+v3f(0,BS/2,0), BS));
2198 writeU64(&reply[2+1+6], m_env->getServerMap().getSeed());
2201 m_con.Send(peer_id, 0, reply, true);
2205 Send complete position information
2207 SendMovePlayer(peer_id);
2212 if(command == TOSERVER_INIT2)
2214 verbosestream<<"Server: Got TOSERVER_INIT2 from "
2215 <<peer_id<<std::endl;
2217 Player *player = m_env->getPlayer(peer_id);
2219 verbosestream<<"Server: TOSERVER_INIT2: "
2220 <<"Player not found; ignoring."<<std::endl;
2224 getClient(peer_id)->serialization_version
2225 = getClient(peer_id)->pending_serialization_version;
2228 Send some initialization data
2231 infostream<<"Server: Sending content to "
2232 <<getPlayerName(peer_id)<<std::endl;
2234 // Send item definitions
2235 SendItemDef(m_con, peer_id, m_itemdef);
2237 // Send node definitions
2238 SendNodeDef(m_con, peer_id, m_nodedef);
2240 // Send media announcement
2241 sendMediaAnnouncement(peer_id);
2244 SendPlayerPrivileges(peer_id);
2246 // Send inventory formspec
2247 SendPlayerInventoryFormspec(peer_id);
2250 UpdateCrafting(peer_id);
2251 SendInventory(peer_id);
2254 SendPlayerHP(peer_id);
2256 // Show death screen if necessary
2258 SendDeathscreen(m_con, peer_id, false, v3f(0,0,0));
2262 SharedBuffer<u8> data = makePacket_TOCLIENT_TIME_OF_DAY(
2263 m_env->getTimeOfDay(), g_settings->getFloat("time_speed"));
2264 m_con.Send(peer_id, 0, data, true);
2267 // Note things in chat if not in simple singleplayer mode
2268 if(!m_simple_singleplayer_mode)
2270 // Send information about server to player in chat
2271 SendChatMessage(peer_id, getStatusString());
2273 // Send information about joining in chat
2275 std::wstring name = L"unknown";
2276 Player *player = m_env->getPlayer(peer_id);
2278 name = narrow_to_wide(player->getName());
2280 std::wstring message;
2283 message += L" joined the game.";
2284 BroadcastChatMessage(message);
2288 // Warnings about protocol version can be issued here
2289 if(getClient(peer_id)->net_proto_version < PROTOCOL_VERSION)
2291 SendChatMessage(peer_id, L"# Server: WARNING: YOUR CLIENT IS OLD AND MAY WORK PROPERLY WITH THIS SERVER!");
2298 std::ostringstream os(std::ios_base::binary);
2299 for(core::map<u16, RemoteClient*>::Iterator
2300 i = m_clients.getIterator();
2301 i.atEnd() == false; i++)
2303 RemoteClient *client = i.getNode()->getValue();
2304 assert(client->peer_id == i.getNode()->getKey());
2305 if(client->serialization_version == SER_FMT_VER_INVALID)
2308 Player *player = m_env->getPlayer(client->peer_id);
2311 // Get name of player
2312 os<<player->getName()<<" ";
2315 actionstream<<player->getName()<<" joins game. List of players: "
2316 <<os.str()<<std::endl;
2322 if(peer_ser_ver == SER_FMT_VER_INVALID)
2324 infostream<<"Server::ProcessData(): Cancelling: Peer"
2325 " serialization format invalid or not initialized."
2326 " Skipping incoming command="<<command<<std::endl;
2330 Player *player = m_env->getPlayer(peer_id);
2332 infostream<<"Server::ProcessData(): Cancelling: "
2333 "No player for peer_id="<<peer_id
2338 PlayerSAO *playersao = player->getPlayerSAO();
2339 if(playersao == NULL){
2340 infostream<<"Server::ProcessData(): Cancelling: "
2341 "No player object for peer_id="<<peer_id
2346 if(command == TOSERVER_PLAYERPOS)
2348 if(datasize < 2+12+12+4+4)
2352 v3s32 ps = readV3S32(&data[start+2]);
2353 v3s32 ss = readV3S32(&data[start+2+12]);
2354 f32 pitch = (f32)readS32(&data[2+12+12]) / 100.0;
2355 f32 yaw = (f32)readS32(&data[2+12+12+4]) / 100.0;
2356 v3f position((f32)ps.X/100., (f32)ps.Y/100., (f32)ps.Z/100.);
2357 v3f speed((f32)ss.X/100., (f32)ss.Y/100., (f32)ss.Z/100.);
2358 pitch = wrapDegrees(pitch);
2359 yaw = wrapDegrees(yaw);
2361 player->setPosition(position);
2362 player->setSpeed(speed);
2363 player->setPitch(pitch);
2364 player->setYaw(yaw);
2366 /*infostream<<"Server::ProcessData(): Moved player "<<peer_id<<" to "
2367 <<"("<<position.X<<","<<position.Y<<","<<position.Z<<")"
2368 <<" pitch="<<pitch<<" yaw="<<yaw<<std::endl;*/
2370 else if(command == TOSERVER_GOTBLOCKS)
2383 u16 count = data[2];
2384 for(u16 i=0; i<count; i++)
2386 if((s16)datasize < 2+1+(i+1)*6)
2387 throw con::InvalidIncomingDataException
2388 ("GOTBLOCKS length is too short");
2389 v3s16 p = readV3S16(&data[2+1+i*6]);
2390 /*infostream<<"Server: GOTBLOCKS ("
2391 <<p.X<<","<<p.Y<<","<<p.Z<<")"<<std::endl;*/
2392 RemoteClient *client = getClient(peer_id);
2393 client->GotBlock(p);
2396 else if(command == TOSERVER_DELETEDBLOCKS)
2409 u16 count = data[2];
2410 for(u16 i=0; i<count; i++)
2412 if((s16)datasize < 2+1+(i+1)*6)
2413 throw con::InvalidIncomingDataException
2414 ("DELETEDBLOCKS length is too short");
2415 v3s16 p = readV3S16(&data[2+1+i*6]);
2416 /*infostream<<"Server: DELETEDBLOCKS ("
2417 <<p.X<<","<<p.Y<<","<<p.Z<<")"<<std::endl;*/
2418 RemoteClient *client = getClient(peer_id);
2419 client->SetBlockNotSent(p);
2422 else if(command == TOSERVER_CLICK_OBJECT)
2424 infostream<<"Server: CLICK_OBJECT not supported anymore"<<std::endl;
2427 else if(command == TOSERVER_CLICK_ACTIVEOBJECT)
2429 infostream<<"Server: CLICK_ACTIVEOBJECT not supported anymore"<<std::endl;
2432 else if(command == TOSERVER_GROUND_ACTION)
2434 infostream<<"Server: GROUND_ACTION not supported anymore"<<std::endl;
2438 else if(command == TOSERVER_RELEASE)
2440 infostream<<"Server: RELEASE not supported anymore"<<std::endl;
2443 else if(command == TOSERVER_SIGNTEXT)
2445 infostream<<"Server: SIGNTEXT not supported anymore"
2449 else if(command == TOSERVER_SIGNNODETEXT)
2451 infostream<<"Server: SIGNNODETEXT not supported anymore"
2455 else if(command == TOSERVER_INVENTORY_ACTION)
2457 // Strip command and create a stream
2458 std::string datastring((char*)&data[2], datasize-2);
2459 verbosestream<<"TOSERVER_INVENTORY_ACTION: data="<<datastring<<std::endl;
2460 std::istringstream is(datastring, std::ios_base::binary);
2462 InventoryAction *a = InventoryAction::deSerialize(is);
2465 infostream<<"TOSERVER_INVENTORY_ACTION: "
2466 <<"InventoryAction::deSerialize() returned NULL"
2472 Note: Always set inventory not sent, to repair cases
2473 where the client made a bad prediction.
2477 Handle restrictions and special cases of the move action
2479 if(a->getType() == IACTION_MOVE)
2481 IMoveAction *ma = (IMoveAction*)a;
2483 ma->from_inv.applyCurrentPlayer(player->getName());
2484 ma->to_inv.applyCurrentPlayer(player->getName());
2486 setInventoryModified(ma->from_inv);
2487 setInventoryModified(ma->to_inv);
2489 bool from_inv_is_current_player =
2490 (ma->from_inv.type == InventoryLocation::PLAYER) &&
2491 (ma->from_inv.name == player->getName());
2493 bool to_inv_is_current_player =
2494 (ma->to_inv.type == InventoryLocation::PLAYER) &&
2495 (ma->to_inv.name == player->getName());
2498 Disable moving items out of craftpreview
2500 if(ma->from_list == "craftpreview")
2502 infostream<<"Ignoring IMoveAction from "
2503 <<(ma->from_inv.dump())<<":"<<ma->from_list
2504 <<" to "<<(ma->to_inv.dump())<<":"<<ma->to_list
2505 <<" because src is "<<ma->from_list<<std::endl;
2511 Disable moving items into craftresult and craftpreview
2513 if(ma->to_list == "craftpreview" || ma->to_list == "craftresult")
2515 infostream<<"Ignoring IMoveAction from "
2516 <<(ma->from_inv.dump())<<":"<<ma->from_list
2517 <<" to "<<(ma->to_inv.dump())<<":"<<ma->to_list
2518 <<" because dst is "<<ma->to_list<<std::endl;
2523 // Disallow moving items in elsewhere than player's inventory
2524 // if not allowed to interact
2525 if(!checkPriv(player->getName(), "interact") &&
2526 (!from_inv_is_current_player ||
2527 !to_inv_is_current_player))
2529 infostream<<"Cannot move outside of player's inventory: "
2530 <<"No interact privilege"<<std::endl;
2535 // If player is not an admin, check for ownership of src and dst
2536 /*if(!checkPriv(player->getName(), "server"))
2538 std::string owner_from = getInventoryOwner(ma->from_inv);
2539 if(owner_from != "" && owner_from != player->getName())
2541 infostream<<"WARNING: "<<player->getName()
2542 <<" tried to access an inventory that"
2543 <<" belongs to "<<owner_from<<std::endl;
2548 std::string owner_to = getInventoryOwner(ma->to_inv);
2549 if(owner_to != "" && owner_to != player->getName())
2551 infostream<<"WARNING: "<<player->getName()
2552 <<" tried to access an inventory that"
2553 <<" belongs to "<<owner_to<<std::endl;
2560 Handle restrictions and special cases of the drop action
2562 else if(a->getType() == IACTION_DROP)
2564 IDropAction *da = (IDropAction*)a;
2566 da->from_inv.applyCurrentPlayer(player->getName());
2568 setInventoryModified(da->from_inv);
2570 // Disallow dropping items if not allowed to interact
2571 if(!checkPriv(player->getName(), "interact"))
2576 // If player is not an admin, check for ownership
2577 /*else if(!checkPriv(player->getName(), "server"))
2579 std::string owner_from = getInventoryOwner(da->from_inv);
2580 if(owner_from != "" && owner_from != player->getName())
2582 infostream<<"WARNING: "<<player->getName()
2583 <<" tried to access an inventory that"
2584 <<" belongs to "<<owner_from<<std::endl;
2591 Handle restrictions and special cases of the craft action
2593 else if(a->getType() == IACTION_CRAFT)
2595 ICraftAction *ca = (ICraftAction*)a;
2597 ca->craft_inv.applyCurrentPlayer(player->getName());
2599 setInventoryModified(ca->craft_inv);
2601 //bool craft_inv_is_current_player =
2602 // (ca->craft_inv.type == InventoryLocation::PLAYER) &&
2603 // (ca->craft_inv.name == player->getName());
2605 // Disallow crafting if not allowed to interact
2606 if(!checkPriv(player->getName(), "interact"))
2608 infostream<<"Cannot craft: "
2609 <<"No interact privilege"<<std::endl;
2614 // If player is not an admin, check for ownership of inventory
2615 /*if(!checkPriv(player->getName(), "server"))
2617 std::string owner_craft = getInventoryOwner(ca->craft_inv);
2618 if(owner_craft != "" && owner_craft != player->getName())
2620 infostream<<"WARNING: "<<player->getName()
2621 <<" tried to access an inventory that"
2622 <<" belongs to "<<owner_craft<<std::endl;
2630 a->apply(this, playersao, this);
2634 else if(command == TOSERVER_CHAT_MESSAGE)
2642 std::string datastring((char*)&data[2], datasize-2);
2643 std::istringstream is(datastring, std::ios_base::binary);
2646 is.read((char*)buf, 2);
2647 u16 len = readU16(buf);
2649 std::wstring message;
2650 for(u16 i=0; i<len; i++)
2652 is.read((char*)buf, 2);
2653 message += (wchar_t)readU16(buf);
2656 // Get player name of this client
2657 std::wstring name = narrow_to_wide(player->getName());
2660 bool ate = scriptapi_on_chat_message(m_lua, player->getName(),
2661 wide_to_narrow(message));
2662 // If script ate the message, don't proceed
2666 // Line to send to players
2668 // Whether to send to the player that sent the line
2669 bool send_to_sender = false;
2670 // Whether to send to other players
2671 bool send_to_others = false;
2674 if(message[0] == L'/')
2676 size_t strip_size = 1;
2677 if (message[1] == L'#') // support old-style commans
2679 message = message.substr(strip_size);
2681 WStrfnd f1(message);
2682 f1.next(L" "); // Skip over /#whatever
2683 std::wstring paramstring = f1.next(L"");
2685 ServerCommandContext *ctx = new ServerCommandContext(
2686 str_split(message, L' '),
2692 std::wstring reply(processServerCommand(ctx));
2693 send_to_sender = ctx->flags & SEND_TO_SENDER;
2694 send_to_others = ctx->flags & SEND_TO_OTHERS;
2696 if (ctx->flags & SEND_NO_PREFIX)
2699 line += L"Server: " + reply;
2706 if(checkPriv(player->getName(), "shout")){
2711 send_to_others = true;
2713 line += L"-!- You don't have permission to shout.";
2714 send_to_sender = true;
2721 actionstream<<"CHAT: "<<wide_to_narrow(line)<<std::endl;
2724 Send the message to clients
2726 for(core::map<u16, RemoteClient*>::Iterator
2727 i = m_clients.getIterator();
2728 i.atEnd() == false; i++)
2730 // Get client and check that it is valid
2731 RemoteClient *client = i.getNode()->getValue();
2732 assert(client->peer_id == i.getNode()->getKey());
2733 if(client->serialization_version == SER_FMT_VER_INVALID)
2737 bool sender_selected = (peer_id == client->peer_id);
2738 if(sender_selected == true && send_to_sender == false)
2740 if(sender_selected == false && send_to_others == false)
2743 SendChatMessage(client->peer_id, line);
2747 else if(command == TOSERVER_DAMAGE)
2749 std::string datastring((char*)&data[2], datasize-2);
2750 std::istringstream is(datastring, std::ios_base::binary);
2751 u8 damage = readU8(is);
2753 actionstream<<player->getName()<<" damaged by "
2754 <<(int)damage<<" hp at "<<PP(player->getPosition()/BS)
2757 playersao->setHP(playersao->getHP() - damage);
2759 if(playersao->getHP() == 0 && playersao->m_hp_not_sent)
2762 if(playersao->m_hp_not_sent)
2763 SendPlayerHP(peer_id);
2765 else if(command == TOSERVER_PASSWORD)
2768 [0] u16 TOSERVER_PASSWORD
2769 [2] u8[28] old password
2770 [30] u8[28] new password
2773 if(datasize != 2+PASSWORD_SIZE*2)
2775 /*char password[PASSWORD_SIZE];
2776 for(u32 i=0; i<PASSWORD_SIZE-1; i++)
2777 password[i] = data[2+i];
2778 password[PASSWORD_SIZE-1] = 0;*/
2780 for(u32 i=0; i<PASSWORD_SIZE-1; i++)
2788 for(u32 i=0; i<PASSWORD_SIZE-1; i++)
2790 char c = data[2+PASSWORD_SIZE+i];
2796 if(!base64_is_valid(newpwd)){
2797 infostream<<"Server: "<<player->getName()<<" supplied invalid password hash"<<std::endl;
2798 // Wrong old password supplied!!
2799 SendChatMessage(peer_id, L"Invalid new password hash supplied. Password NOT changed.");
2803 infostream<<"Server: Client requests a password change from "
2804 <<"'"<<oldpwd<<"' to '"<<newpwd<<"'"<<std::endl;
2806 std::string playername = player->getName();
2808 std::string checkpwd;
2809 scriptapi_get_auth(m_lua, playername, &checkpwd, NULL);
2811 if(oldpwd != checkpwd)
2813 infostream<<"Server: invalid old password"<<std::endl;
2814 // Wrong old password supplied!!
2815 SendChatMessage(peer_id, L"Invalid old password supplied. Password NOT changed.");
2819 bool success = scriptapi_set_password(m_lua, playername, newpwd);
2821 actionstream<<player->getName()<<" changes password"<<std::endl;
2822 SendChatMessage(peer_id, L"Password change successful.");
2824 actionstream<<player->getName()<<" tries to change password but "
2825 <<"it fails"<<std::endl;
2826 SendChatMessage(peer_id, L"Password change failed or inavailable.");
2829 else if(command == TOSERVER_PLAYERITEM)
2834 u16 item = readU16(&data[2]);
2835 playersao->setWieldIndex(item);
2837 else if(command == TOSERVER_RESPAWN)
2842 RespawnPlayer(peer_id);
2844 actionstream<<player->getName()<<" respawns at "
2845 <<PP(player->getPosition()/BS)<<std::endl;
2847 // ActiveObject is added to environment in AsyncRunStep after
2848 // the previous addition has been succesfully removed
2850 else if(command == TOSERVER_REQUEST_MEDIA) {
2851 std::string datastring((char*)&data[2], datasize-2);
2852 std::istringstream is(datastring, std::ios_base::binary);
2854 core::list<MediaRequest> tosend;
2855 u16 numfiles = readU16(is);
2857 infostream<<"Sending "<<numfiles<<" files to "
2858 <<getPlayerName(peer_id)<<std::endl;
2859 verbosestream<<"TOSERVER_REQUEST_MEDIA: "<<std::endl;
2861 for(int i = 0; i < numfiles; i++) {
2862 std::string name = deSerializeString(is);
2863 tosend.push_back(MediaRequest(name));
2864 verbosestream<<"TOSERVER_REQUEST_MEDIA: requested file "
2868 sendRequestedMedia(peer_id, tosend);
2870 // Now the client should know about everything
2871 // (definitions and files)
2872 getClient(peer_id)->definitions_sent = true;
2874 else if(command == TOSERVER_INTERACT)
2876 std::string datastring((char*)&data[2], datasize-2);
2877 std::istringstream is(datastring, std::ios_base::binary);
2883 [5] u32 length of the next item
2884 [9] serialized PointedThing
2886 0: start digging (from undersurface) or use
2887 1: stop digging (all parameters ignored)
2888 2: digging completed
2889 3: place block or item (to abovesurface)
2892 u8 action = readU8(is);
2893 u16 item_i = readU16(is);
2894 std::istringstream tmp_is(deSerializeLongString(is), std::ios::binary);
2895 PointedThing pointed;
2896 pointed.deSerialize(tmp_is);
2898 verbosestream<<"TOSERVER_INTERACT: action="<<(int)action<<", item="
2899 <<item_i<<", pointed="<<pointed.dump()<<std::endl;
2903 verbosestream<<"TOSERVER_INTERACT: "<<player->getName()
2904 <<" tried to interact, but is dead!"<<std::endl;
2908 v3f player_pos = playersao->getLastGoodPosition();
2910 // Update wielded item
2911 playersao->setWieldIndex(item_i);
2913 // Get pointed to node (undefined if not POINTEDTYPE_NODE)
2914 v3s16 p_under = pointed.node_undersurface;
2915 v3s16 p_above = pointed.node_abovesurface;
2917 // Get pointed to object (NULL if not POINTEDTYPE_OBJECT)
2918 ServerActiveObject *pointed_object = NULL;
2919 if(pointed.type == POINTEDTHING_OBJECT)
2921 pointed_object = m_env->getActiveObject(pointed.object_id);
2922 if(pointed_object == NULL)
2924 verbosestream<<"TOSERVER_INTERACT: "
2925 "pointed object is NULL"<<std::endl;
2931 v3f pointed_pos_under = player_pos;
2932 v3f pointed_pos_above = player_pos;
2933 if(pointed.type == POINTEDTHING_NODE)
2935 pointed_pos_under = intToFloat(p_under, BS);
2936 pointed_pos_above = intToFloat(p_above, BS);
2938 else if(pointed.type == POINTEDTHING_OBJECT)
2940 pointed_pos_under = pointed_object->getBasePosition();
2941 pointed_pos_above = pointed_pos_under;
2945 Check that target is reasonably close
2946 (only when digging or placing things)
2948 if(action == 0 || action == 2 || action == 3)
2950 float d = player_pos.getDistanceFrom(pointed_pos_under);
2951 float max_d = BS * 14; // Just some large enough value
2953 actionstream<<"Player "<<player->getName()
2954 <<" tried to access "<<pointed.dump()
2956 <<"d="<<d<<", max_d="<<max_d
2957 <<". ignoring."<<std::endl;
2958 // Re-send block to revert change on client-side
2959 RemoteClient *client = getClient(peer_id);
2960 v3s16 blockpos = getNodeBlockPos(floatToInt(pointed_pos_under, BS));
2961 client->SetBlockNotSent(blockpos);
2968 Make sure the player is allowed to do it
2970 if(!checkPriv(player->getName(), "interact"))
2972 actionstream<<player->getName()<<" attempted to interact with "
2973 <<pointed.dump()<<" without 'interact' privilege"
2975 // Re-send block to revert change on client-side
2976 RemoteClient *client = getClient(peer_id);
2977 // Digging completed -> under
2979 v3s16 blockpos = getNodeBlockPos(floatToInt(pointed_pos_under, BS));
2980 client->SetBlockNotSent(blockpos);
2982 // Placement -> above
2984 v3s16 blockpos = getNodeBlockPos(floatToInt(pointed_pos_above, BS));
2985 client->SetBlockNotSent(blockpos);
2991 0: start digging or punch object
2995 if(pointed.type == POINTEDTHING_NODE)
2998 NOTE: This can be used in the future to check if
2999 somebody is cheating, by checking the timing.
3001 MapNode n(CONTENT_IGNORE);
3004 n = m_env->getMap().getNode(p_under);
3006 catch(InvalidPositionException &e)
3008 infostream<<"Server: Not punching: Node not found."
3009 <<" Adding block to emerge queue."
3011 m_emerge_queue.addBlock(peer_id,
3012 getNodeBlockPos(p_above), BLOCK_EMERGE_FLAG_FROMDISK);
3014 if(n.getContent() != CONTENT_IGNORE)
3015 scriptapi_node_on_punch(m_lua, p_under, n, playersao);
3017 else if(pointed.type == POINTEDTHING_OBJECT)
3019 // Skip if object has been removed
3020 if(pointed_object->m_removed)
3023 actionstream<<player->getName()<<" punches object "
3024 <<pointed.object_id<<": "
3025 <<pointed_object->getDescription()<<std::endl;
3027 ItemStack punchitem = playersao->getWieldedItem();
3028 ToolCapabilities toolcap =
3029 punchitem.getToolCapabilities(m_itemdef);
3030 v3f dir = (pointed_object->getBasePosition() -
3031 (player->getPosition() + player->getEyeOffset())
3033 float time_from_last_punch =
3034 playersao->resetTimeFromLastPunch();
3035 pointed_object->punch(dir, &toolcap, playersao,
3036 time_from_last_punch);
3044 else if(action == 1)
3049 2: Digging completed
3051 else if(action == 2)
3053 // Only complete digging of nodes
3054 if(pointed.type == POINTEDTHING_NODE)
3056 MapNode n(CONTENT_IGNORE);
3059 n = m_env->getMap().getNode(p_under);
3061 catch(InvalidPositionException &e)
3063 infostream<<"Server: Not finishing digging: Node not found."
3064 <<" Adding block to emerge queue."
3066 m_emerge_queue.addBlock(peer_id,
3067 getNodeBlockPos(p_above), BLOCK_EMERGE_FLAG_FROMDISK);
3069 if(n.getContent() != CONTENT_IGNORE)
3070 scriptapi_node_on_dig(m_lua, p_under, n, playersao);
3072 if (m_env->getMap().getNodeNoEx(p_under).getContent() != CONTENT_AIR)
3074 // Re-send block to revert change on client-side
3075 RemoteClient *client = getClient(peer_id);
3076 v3s16 blockpos = getNodeBlockPos(floatToInt(pointed_pos_under, BS));
3077 client->SetBlockNotSent(blockpos);
3083 3: place block or right-click object
3085 else if(action == 3)
3087 ItemStack item = playersao->getWieldedItem();
3089 // Reset build time counter
3090 if(pointed.type == POINTEDTHING_NODE &&
3091 item.getDefinition(m_itemdef).type == ITEM_NODE)
3092 getClient(peer_id)->m_time_from_building = 0.0;
3094 if(pointed.type == POINTEDTHING_OBJECT)
3096 // Right click object
3098 // Skip if object has been removed
3099 if(pointed_object->m_removed)
3102 actionstream<<player->getName()<<" right-clicks object "
3103 <<pointed.object_id<<": "
3104 <<pointed_object->getDescription()<<std::endl;
3107 pointed_object->rightClick(playersao);
3109 else if(scriptapi_item_on_place(m_lua,
3110 item, playersao, pointed))
3112 // Placement was handled in lua
3114 // Apply returned ItemStack
3115 if(g_settings->getBool("creative_mode") == false)
3116 playersao->setWieldedItem(item);
3119 // If item has node placement prediction, always send the above
3120 // node to make sure the client knows what exactly happened
3121 if(item.getDefinition(m_itemdef).node_placement_prediction != ""){
3122 RemoteClient *client = getClient(peer_id);
3123 v3s16 blockpos = getNodeBlockPos(floatToInt(pointed_pos_above, BS));
3124 client->SetBlockNotSent(blockpos);
3131 else if(action == 4)
3133 ItemStack item = playersao->getWieldedItem();
3135 actionstream<<player->getName()<<" uses "<<item.name
3136 <<", pointing at "<<pointed.dump()<<std::endl;
3138 if(scriptapi_item_on_use(m_lua,
3139 item, playersao, pointed))
3141 // Apply returned ItemStack
3142 if(g_settings->getBool("creative_mode") == false)
3143 playersao->setWieldedItem(item);
3149 Catch invalid actions
3153 infostream<<"WARNING: Server: Invalid action "
3154 <<action<<std::endl;
3157 else if(command == TOSERVER_REMOVED_SOUNDS)
3159 std::string datastring((char*)&data[2], datasize-2);
3160 std::istringstream is(datastring, std::ios_base::binary);
3162 int num = readU16(is);
3163 for(int k=0; k<num; k++){
3164 s32 id = readS32(is);
3165 std::map<s32, ServerPlayingSound>::iterator i =
3166 m_playing_sounds.find(id);
3167 if(i == m_playing_sounds.end())
3169 ServerPlayingSound &psound = i->second;
3170 psound.clients.erase(peer_id);
3171 if(psound.clients.size() == 0)
3172 m_playing_sounds.erase(i++);
3175 else if(command == TOSERVER_NODEMETA_FIELDS)
3177 std::string datastring((char*)&data[2], datasize-2);
3178 std::istringstream is(datastring, std::ios_base::binary);
3180 v3s16 p = readV3S16(is);
3181 std::string formname = deSerializeString(is);
3182 int num = readU16(is);
3183 std::map<std::string, std::string> fields;
3184 for(int k=0; k<num; k++){
3185 std::string fieldname = deSerializeString(is);
3186 std::string fieldvalue = deSerializeLongString(is);
3187 fields[fieldname] = fieldvalue;
3190 scriptapi_node_on_receive_fields(m_lua, p, formname, fields,
3195 infostream<<"Server::ProcessData(): Ignoring "
3196 "unknown command "<<command<<std::endl;
3200 catch(SendFailedException &e)
3202 errorstream<<"Server::ProcessData(): SendFailedException: "
3208 void Server::onMapEditEvent(MapEditEvent *event)
3210 //infostream<<"Server::onMapEditEvent()"<<std::endl;
3211 if(m_ignore_map_edit_events)
3213 if(m_ignore_map_edit_events_area.contains(event->getArea()))
3215 MapEditEvent *e = event->clone();
3216 m_unsent_map_edit_queue.push_back(e);
3219 Inventory* Server::getInventory(const InventoryLocation &loc)
3222 case InventoryLocation::UNDEFINED:
3225 case InventoryLocation::CURRENT_PLAYER:
3228 case InventoryLocation::PLAYER:
3230 Player *player = m_env->getPlayer(loc.name.c_str());
3233 PlayerSAO *playersao = player->getPlayerSAO();
3236 return playersao->getInventory();
3239 case InventoryLocation::NODEMETA:
3241 NodeMetadata *meta = m_env->getMap().getNodeMetadata(loc.p);
3244 return meta->getInventory();
3252 void Server::setInventoryModified(const InventoryLocation &loc)
3255 case InventoryLocation::UNDEFINED:
3258 case InventoryLocation::PLAYER:
3260 Player *player = m_env->getPlayer(loc.name.c_str());
3263 PlayerSAO *playersao = player->getPlayerSAO();
3266 playersao->m_inventory_not_sent = true;
3267 playersao->m_wielded_item_not_sent = true;
3270 case InventoryLocation::NODEMETA:
3272 v3s16 blockpos = getNodeBlockPos(loc.p);
3274 MapBlock *block = m_env->getMap().getBlockNoCreateNoEx(blockpos);
3276 block->raiseModified(MOD_STATE_WRITE_NEEDED);
3278 setBlockNotSent(blockpos);
3286 core::list<PlayerInfo> Server::getPlayerInfo()
3288 DSTACK(__FUNCTION_NAME);
3289 JMutexAutoLock envlock(m_env_mutex);
3290 JMutexAutoLock conlock(m_con_mutex);
3292 core::list<PlayerInfo> list;
3294 core::list<Player*> players = m_env->getPlayers();
3296 core::list<Player*>::Iterator i;
3297 for(i = players.begin();
3298 i != players.end(); i++)
3302 Player *player = *i;
3305 // Copy info from connection to info struct
3306 info.id = player->peer_id;
3307 info.address = m_con.GetPeerAddress(player->peer_id);
3308 info.avg_rtt = m_con.GetPeerAvgRTT(player->peer_id);
3310 catch(con::PeerNotFoundException &e)
3312 // Set dummy peer info
3314 info.address = Address(0,0,0,0,0);
3318 snprintf(info.name, PLAYERNAME_SIZE, "%s", player->getName());
3319 info.position = player->getPosition();
3321 list.push_back(info);
3328 void Server::peerAdded(con::Peer *peer)
3330 DSTACK(__FUNCTION_NAME);
3331 verbosestream<<"Server::peerAdded(): peer->id="
3332 <<peer->id<<std::endl;
3335 c.type = PEER_ADDED;
3336 c.peer_id = peer->id;
3338 m_peer_change_queue.push_back(c);
3341 void Server::deletingPeer(con::Peer *peer, bool timeout)
3343 DSTACK(__FUNCTION_NAME);
3344 verbosestream<<"Server::deletingPeer(): peer->id="
3345 <<peer->id<<", timeout="<<timeout<<std::endl;
3348 c.type = PEER_REMOVED;
3349 c.peer_id = peer->id;
3350 c.timeout = timeout;
3351 m_peer_change_queue.push_back(c);
3358 void Server::SendHP(con::Connection &con, u16 peer_id, u8 hp)
3360 DSTACK(__FUNCTION_NAME);
3361 std::ostringstream os(std::ios_base::binary);
3363 writeU16(os, TOCLIENT_HP);
3367 std::string s = os.str();
3368 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3370 con.Send(peer_id, 0, data, true);
3373 void Server::SendAccessDenied(con::Connection &con, u16 peer_id,
3374 const std::wstring &reason)
3376 DSTACK(__FUNCTION_NAME);
3377 std::ostringstream os(std::ios_base::binary);
3379 writeU16(os, TOCLIENT_ACCESS_DENIED);
3380 os<<serializeWideString(reason);
3383 std::string s = os.str();
3384 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3386 con.Send(peer_id, 0, data, true);
3389 void Server::SendDeathscreen(con::Connection &con, u16 peer_id,
3390 bool set_camera_point_target, v3f camera_point_target)
3392 DSTACK(__FUNCTION_NAME);
3393 std::ostringstream os(std::ios_base::binary);
3395 writeU16(os, TOCLIENT_DEATHSCREEN);
3396 writeU8(os, set_camera_point_target);
3397 writeV3F1000(os, camera_point_target);
3400 std::string s = os.str();
3401 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3403 con.Send(peer_id, 0, data, true);
3406 void Server::SendItemDef(con::Connection &con, u16 peer_id,
3407 IItemDefManager *itemdef)
3409 DSTACK(__FUNCTION_NAME);
3410 std::ostringstream os(std::ios_base::binary);
3414 u32 length of the next item
3415 zlib-compressed serialized ItemDefManager
3417 writeU16(os, TOCLIENT_ITEMDEF);
3418 std::ostringstream tmp_os(std::ios::binary);
3419 itemdef->serialize(tmp_os);
3420 std::ostringstream tmp_os2(std::ios::binary);
3421 compressZlib(tmp_os.str(), tmp_os2);
3422 os<<serializeLongString(tmp_os2.str());
3425 std::string s = os.str();
3426 verbosestream<<"Server: Sending item definitions to id("<<peer_id
3427 <<"): size="<<s.size()<<std::endl;
3428 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3430 con.Send(peer_id, 0, data, true);
3433 void Server::SendNodeDef(con::Connection &con, u16 peer_id,
3434 INodeDefManager *nodedef)
3436 DSTACK(__FUNCTION_NAME);
3437 std::ostringstream os(std::ios_base::binary);
3441 u32 length of the next item
3442 zlib-compressed serialized NodeDefManager
3444 writeU16(os, TOCLIENT_NODEDEF);
3445 std::ostringstream tmp_os(std::ios::binary);
3446 nodedef->serialize(tmp_os);
3447 std::ostringstream tmp_os2(std::ios::binary);
3448 compressZlib(tmp_os.str(), tmp_os2);
3449 os<<serializeLongString(tmp_os2.str());
3452 std::string s = os.str();
3453 verbosestream<<"Server: Sending node definitions to id("<<peer_id
3454 <<"): size="<<s.size()<<std::endl;
3455 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3457 con.Send(peer_id, 0, data, true);
3461 Non-static send methods
3464 void Server::SendInventory(u16 peer_id)
3466 DSTACK(__FUNCTION_NAME);
3468 PlayerSAO *playersao = getPlayerSAO(peer_id);
3471 playersao->m_inventory_not_sent = false;
3477 std::ostringstream os;
3478 playersao->getInventory()->serialize(os);
3480 std::string s = os.str();
3482 SharedBuffer<u8> data(s.size()+2);
3483 writeU16(&data[0], TOCLIENT_INVENTORY);
3484 memcpy(&data[2], s.c_str(), s.size());
3487 m_con.Send(peer_id, 0, data, true);
3490 void Server::SendChatMessage(u16 peer_id, const std::wstring &message)
3492 DSTACK(__FUNCTION_NAME);
3494 std::ostringstream os(std::ios_base::binary);
3498 writeU16(buf, TOCLIENT_CHAT_MESSAGE);
3499 os.write((char*)buf, 2);
3502 writeU16(buf, message.size());
3503 os.write((char*)buf, 2);
3506 for(u32 i=0; i<message.size(); i++)
3510 os.write((char*)buf, 2);
3514 std::string s = os.str();
3515 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3517 m_con.Send(peer_id, 0, data, true);
3520 void Server::BroadcastChatMessage(const std::wstring &message)
3522 for(core::map<u16, RemoteClient*>::Iterator
3523 i = m_clients.getIterator();
3524 i.atEnd() == false; i++)
3526 // Get client and check that it is valid
3527 RemoteClient *client = i.getNode()->getValue();
3528 assert(client->peer_id == i.getNode()->getKey());
3529 if(client->serialization_version == SER_FMT_VER_INVALID)
3532 SendChatMessage(client->peer_id, message);
3536 void Server::SendPlayerHP(u16 peer_id)
3538 DSTACK(__FUNCTION_NAME);
3539 PlayerSAO *playersao = getPlayerSAO(peer_id);
3541 playersao->m_hp_not_sent = false;
3542 SendHP(m_con, peer_id, playersao->getHP());
3545 void Server::SendMovePlayer(u16 peer_id)
3547 DSTACK(__FUNCTION_NAME);
3548 Player *player = m_env->getPlayer(peer_id);
3551 std::ostringstream os(std::ios_base::binary);
3552 writeU16(os, TOCLIENT_MOVE_PLAYER);
3553 writeV3F1000(os, player->getPosition());
3554 writeF1000(os, player->getPitch());
3555 writeF1000(os, player->getYaw());
3558 v3f pos = player->getPosition();
3559 f32 pitch = player->getPitch();
3560 f32 yaw = player->getYaw();
3561 verbosestream<<"Server: Sending TOCLIENT_MOVE_PLAYER"
3562 <<" pos=("<<pos.X<<","<<pos.Y<<","<<pos.Z<<")"
3569 std::string s = os.str();
3570 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3572 m_con.Send(peer_id, 0, data, true);
3575 void Server::SendPlayerPrivileges(u16 peer_id)
3577 Player *player = m_env->getPlayer(peer_id);
3579 if(player->peer_id == PEER_ID_INEXISTENT)
3582 std::set<std::string> privs;
3583 scriptapi_get_auth(m_lua, player->getName(), NULL, &privs);
3585 std::ostringstream os(std::ios_base::binary);
3586 writeU16(os, TOCLIENT_PRIVILEGES);
3587 writeU16(os, privs.size());
3588 for(std::set<std::string>::const_iterator i = privs.begin();
3589 i != privs.end(); i++){
3590 os<<serializeString(*i);
3594 std::string s = os.str();
3595 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3597 m_con.Send(peer_id, 0, data, true);
3600 void Server::SendPlayerInventoryFormspec(u16 peer_id)
3602 Player *player = m_env->getPlayer(peer_id);
3604 if(player->peer_id == PEER_ID_INEXISTENT)
3607 std::ostringstream os(std::ios_base::binary);
3608 writeU16(os, TOCLIENT_INVENTORY_FORMSPEC);
3609 os<<serializeLongString(player->inventory_formspec);
3612 std::string s = os.str();
3613 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3615 m_con.Send(peer_id, 0, data, true);
3618 s32 Server::playSound(const SimpleSoundSpec &spec,
3619 const ServerSoundParams ¶ms)
3621 // Find out initial position of sound
3622 bool pos_exists = false;
3623 v3f pos = params.getPos(m_env, &pos_exists);
3624 // If position is not found while it should be, cancel sound
3625 if(pos_exists != (params.type != ServerSoundParams::SSP_LOCAL))
3627 // Filter destination clients
3628 std::set<RemoteClient*> dst_clients;
3629 if(params.to_player != "")
3631 Player *player = m_env->getPlayer(params.to_player.c_str());
3633 infostream<<"Server::playSound: Player \""<<params.to_player
3634 <<"\" not found"<<std::endl;
3637 if(player->peer_id == PEER_ID_INEXISTENT){
3638 infostream<<"Server::playSound: Player \""<<params.to_player
3639 <<"\" not connected"<<std::endl;
3642 RemoteClient *client = getClient(player->peer_id);
3643 dst_clients.insert(client);
3647 for(core::map<u16, RemoteClient*>::Iterator
3648 i = m_clients.getIterator(); i.atEnd() == false; i++)
3650 RemoteClient *client = i.getNode()->getValue();
3651 Player *player = m_env->getPlayer(client->peer_id);
3655 if(player->getPosition().getDistanceFrom(pos) >
3656 params.max_hear_distance)
3659 dst_clients.insert(client);
3662 if(dst_clients.size() == 0)
3665 s32 id = m_next_sound_id++;
3666 // The sound will exist as a reference in m_playing_sounds
3667 m_playing_sounds[id] = ServerPlayingSound();
3668 ServerPlayingSound &psound = m_playing_sounds[id];
3669 psound.params = params;
3670 for(std::set<RemoteClient*>::iterator i = dst_clients.begin();
3671 i != dst_clients.end(); i++)
3672 psound.clients.insert((*i)->peer_id);
3674 std::ostringstream os(std::ios_base::binary);
3675 writeU16(os, TOCLIENT_PLAY_SOUND);
3677 os<<serializeString(spec.name);
3678 writeF1000(os, spec.gain * params.gain);
3679 writeU8(os, params.type);
3680 writeV3F1000(os, pos);
3681 writeU16(os, params.object);
3682 writeU8(os, params.loop);
3684 std::string s = os.str();
3685 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3687 for(std::set<RemoteClient*>::iterator i = dst_clients.begin();
3688 i != dst_clients.end(); i++){
3690 m_con.Send((*i)->peer_id, 0, data, true);
3694 void Server::stopSound(s32 handle)
3696 // Get sound reference
3697 std::map<s32, ServerPlayingSound>::iterator i =
3698 m_playing_sounds.find(handle);
3699 if(i == m_playing_sounds.end())
3701 ServerPlayingSound &psound = i->second;
3703 std::ostringstream os(std::ios_base::binary);
3704 writeU16(os, TOCLIENT_STOP_SOUND);
3705 writeS32(os, handle);
3707 std::string s = os.str();
3708 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3710 for(std::set<u16>::iterator i = psound.clients.begin();
3711 i != psound.clients.end(); i++){
3713 m_con.Send(*i, 0, data, true);
3715 // Remove sound reference
3716 m_playing_sounds.erase(i);
3719 void Server::sendRemoveNode(v3s16 p, u16 ignore_id,
3720 core::list<u16> *far_players, float far_d_nodes)
3722 float maxd = far_d_nodes*BS;
3723 v3f p_f = intToFloat(p, BS);
3727 SharedBuffer<u8> reply(replysize);
3728 writeU16(&reply[0], TOCLIENT_REMOVENODE);
3729 writeS16(&reply[2], p.X);
3730 writeS16(&reply[4], p.Y);
3731 writeS16(&reply[6], p.Z);
3733 for(core::map<u16, RemoteClient*>::Iterator
3734 i = m_clients.getIterator();
3735 i.atEnd() == false; i++)
3737 // Get client and check that it is valid
3738 RemoteClient *client = i.getNode()->getValue();
3739 assert(client->peer_id == i.getNode()->getKey());
3740 if(client->serialization_version == SER_FMT_VER_INVALID)
3743 // Don't send if it's the same one
3744 if(client->peer_id == ignore_id)
3750 Player *player = m_env->getPlayer(client->peer_id);
3753 // If player is far away, only set modified blocks not sent
3754 v3f player_pos = player->getPosition();
3755 if(player_pos.getDistanceFrom(p_f) > maxd)
3757 far_players->push_back(client->peer_id);
3764 m_con.Send(client->peer_id, 0, reply, true);
3768 void Server::sendAddNode(v3s16 p, MapNode n, u16 ignore_id,
3769 core::list<u16> *far_players, float far_d_nodes)
3771 float maxd = far_d_nodes*BS;
3772 v3f p_f = intToFloat(p, BS);
3774 for(core::map<u16, RemoteClient*>::Iterator
3775 i = m_clients.getIterator();
3776 i.atEnd() == false; i++)
3778 // Get client and check that it is valid
3779 RemoteClient *client = i.getNode()->getValue();
3780 assert(client->peer_id == i.getNode()->getKey());
3781 if(client->serialization_version == SER_FMT_VER_INVALID)
3784 // Don't send if it's the same one
3785 if(client->peer_id == ignore_id)
3791 Player *player = m_env->getPlayer(client->peer_id);
3794 // If player is far away, only set modified blocks not sent
3795 v3f player_pos = player->getPosition();
3796 if(player_pos.getDistanceFrom(p_f) > maxd)
3798 far_players->push_back(client->peer_id);
3805 u32 replysize = 8 + MapNode::serializedLength(client->serialization_version);
3806 SharedBuffer<u8> reply(replysize);
3807 writeU16(&reply[0], TOCLIENT_ADDNODE);
3808 writeS16(&reply[2], p.X);
3809 writeS16(&reply[4], p.Y);
3810 writeS16(&reply[6], p.Z);
3811 n.serialize(&reply[8], client->serialization_version);
3814 m_con.Send(client->peer_id, 0, reply, true);
3818 void Server::setBlockNotSent(v3s16 p)
3820 for(core::map<u16, RemoteClient*>::Iterator
3821 i = m_clients.getIterator();
3822 i.atEnd()==false; i++)
3824 RemoteClient *client = i.getNode()->getValue();
3825 client->SetBlockNotSent(p);
3829 void Server::SendBlockNoLock(u16 peer_id, MapBlock *block, u8 ver)
3831 DSTACK(__FUNCTION_NAME);
3833 v3s16 p = block->getPos();
3837 bool completely_air = true;
3838 for(s16 z0=0; z0<MAP_BLOCKSIZE; z0++)
3839 for(s16 x0=0; x0<MAP_BLOCKSIZE; x0++)
3840 for(s16 y0=0; y0<MAP_BLOCKSIZE; y0++)
3842 if(block->getNodeNoEx(v3s16(x0,y0,z0)).d != CONTENT_AIR)
3844 completely_air = false;
3845 x0 = y0 = z0 = MAP_BLOCKSIZE; // Break out
3850 infostream<<"Server: Sending block ("<<p.X<<","<<p.Y<<","<<p.Z<<"): ";
3852 infostream<<"[completely air] ";
3853 infostream<<std::endl;
3857 Create a packet with the block in the right format
3860 std::ostringstream os(std::ios_base::binary);
3861 block->serialize(os, ver, false);
3862 std::string s = os.str();
3863 SharedBuffer<u8> blockdata((u8*)s.c_str(), s.size());
3865 u32 replysize = 8 + blockdata.getSize();
3866 SharedBuffer<u8> reply(replysize);
3867 writeU16(&reply[0], TOCLIENT_BLOCKDATA);
3868 writeS16(&reply[2], p.X);
3869 writeS16(&reply[4], p.Y);
3870 writeS16(&reply[6], p.Z);
3871 memcpy(&reply[8], *blockdata, blockdata.getSize());
3873 /*infostream<<"Server: Sending block ("<<p.X<<","<<p.Y<<","<<p.Z<<")"
3874 <<": \tpacket size: "<<replysize<<std::endl;*/
3879 m_con.Send(peer_id, 1, reply, true);
3882 void Server::SendBlocks(float dtime)
3884 DSTACK(__FUNCTION_NAME);
3886 JMutexAutoLock envlock(m_env_mutex);
3887 JMutexAutoLock conlock(m_con_mutex);
3889 ScopeProfiler sp(g_profiler, "Server: sel and send blocks to clients");
3891 core::array<PrioritySortedBlockTransfer> queue;
3893 s32 total_sending = 0;
3896 ScopeProfiler sp(g_profiler, "Server: selecting blocks for sending");
3898 for(core::map<u16, RemoteClient*>::Iterator
3899 i = m_clients.getIterator();
3900 i.atEnd() == false; i++)
3902 RemoteClient *client = i.getNode()->getValue();
3903 assert(client->peer_id == i.getNode()->getKey());
3905 // If definitions and textures have not been sent, don't
3906 // send MapBlocks either
3907 if(!client->definitions_sent)
3910 total_sending += client->SendingCount();
3912 if(client->serialization_version == SER_FMT_VER_INVALID)
3915 client->GetNextBlocks(this, dtime, queue);
3920 // Lowest priority number comes first.
3921 // Lowest is most important.
3924 for(u32 i=0; i<queue.size(); i++)
3926 //TODO: Calculate limit dynamically
3927 if(total_sending >= g_settings->getS32
3928 ("max_simultaneous_block_sends_server_total"))
3931 PrioritySortedBlockTransfer q = queue[i];
3933 MapBlock *block = NULL;
3936 block = m_env->getMap().getBlockNoCreate(q.pos);
3938 catch(InvalidPositionException &e)
3943 RemoteClient *client = getClient(q.peer_id);
3945 SendBlockNoLock(q.peer_id, block, client->serialization_version);
3947 client->SentBlock(q.pos);
3953 void Server::fillMediaCache()
3955 DSTACK(__FUNCTION_NAME);
3957 infostream<<"Server: Calculating media file checksums"<<std::endl;
3959 // Collect all media file paths
3960 std::list<std::string> paths;
3961 for(core::list<ModSpec>::Iterator i = m_mods.begin();
3962 i != m_mods.end(); i++){
3963 const ModSpec &mod = *i;
3964 paths.push_back(mod.path + DIR_DELIM + "textures");
3965 paths.push_back(mod.path + DIR_DELIM + "sounds");
3966 paths.push_back(mod.path + DIR_DELIM + "media");
3968 std::string path_all = "textures";
3969 paths.push_back(path_all + DIR_DELIM + "all");
3971 // Collect media file information from paths into cache
3972 for(std::list<std::string>::iterator i = paths.begin();
3973 i != paths.end(); i++)
3975 std::string mediapath = *i;
3976 std::vector<fs::DirListNode> dirlist = fs::GetDirListing(mediapath);
3977 for(u32 j=0; j<dirlist.size(); j++){
3978 if(dirlist[j].dir) // Ignode dirs
3980 std::string filename = dirlist[j].name;
3981 // If name contains illegal characters, ignore the file
3982 if(!string_allowed(filename, TEXTURENAME_ALLOWED_CHARS)){
3983 infostream<<"Server: ignoring illegal file name: \""
3984 <<filename<<"\""<<std::endl;
3987 // If name is not in a supported format, ignore it
3988 const char *supported_ext[] = {
3989 ".png", ".jpg", ".bmp", ".tga",
3990 ".pcx", ".ppm", ".psd", ".wal", ".rgb",
3994 if(removeStringEnd(filename, supported_ext) == ""){
3995 infostream<<"Server: ignoring unsupported file extension: \""
3996 <<filename<<"\""<<std::endl;
3999 // Ok, attempt to load the file and add to cache
4000 std::string filepath = mediapath + DIR_DELIM + filename;
4002 std::ifstream fis(filepath.c_str(), std::ios_base::binary);
4003 if(fis.good() == false){
4004 errorstream<<"Server::fillMediaCache(): Could not open \""
4005 <<filename<<"\" for reading"<<std::endl;
4008 std::ostringstream tmp_os(std::ios_base::binary);
4012 fis.read(buf, 1024);
4013 std::streamsize len = fis.gcount();
4014 tmp_os.write(buf, len);
4023 errorstream<<"Server::fillMediaCache(): Failed to read \""
4024 <<filename<<"\""<<std::endl;
4027 if(tmp_os.str().length() == 0){
4028 errorstream<<"Server::fillMediaCache(): Empty file \""
4029 <<filepath<<"\""<<std::endl;
4034 sha1.addBytes(tmp_os.str().c_str(), tmp_os.str().length());
4036 unsigned char *digest = sha1.getDigest();
4037 std::string sha1_base64 = base64_encode(digest, 20);
4038 std::string sha1_hex = hex_encode((char*)digest, 20);
4042 this->m_media[filename] = MediaInfo(filepath, sha1_base64);
4043 verbosestream<<"Server: "<<sha1_hex<<" is "<<filename<<std::endl;
4048 struct SendableMediaAnnouncement
4051 std::string sha1_digest;
4053 SendableMediaAnnouncement(const std::string name_="",
4054 const std::string sha1_digest_=""):
4056 sha1_digest(sha1_digest_)
4060 void Server::sendMediaAnnouncement(u16 peer_id)
4062 DSTACK(__FUNCTION_NAME);
4064 verbosestream<<"Server: Announcing files to id("<<peer_id<<")"
4067 core::list<SendableMediaAnnouncement> file_announcements;
4069 for(std::map<std::string, MediaInfo>::iterator i = m_media.begin();
4070 i != m_media.end(); i++){
4072 file_announcements.push_back(
4073 SendableMediaAnnouncement(i->first, i->second.sha1_digest));
4077 std::ostringstream os(std::ios_base::binary);
4085 u16 length of sha1_digest
4090 writeU16(os, TOCLIENT_ANNOUNCE_MEDIA);
4091 writeU16(os, file_announcements.size());
4093 for(core::list<SendableMediaAnnouncement>::Iterator
4094 j = file_announcements.begin();
4095 j != file_announcements.end(); j++){
4096 os<<serializeString(j->name);
4097 os<<serializeString(j->sha1_digest);
4101 std::string s = os.str();
4102 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
4105 m_con.Send(peer_id, 0, data, true);
4109 struct SendableMedia
4115 SendableMedia(const std::string &name_="", const std::string path_="",
4116 const std::string &data_=""):
4123 void Server::sendRequestedMedia(u16 peer_id,
4124 const core::list<MediaRequest> &tosend)
4126 DSTACK(__FUNCTION_NAME);
4128 verbosestream<<"Server::sendRequestedMedia(): "
4129 <<"Sending files to client"<<std::endl;
4133 // Put 5kB in one bunch (this is not accurate)
4134 u32 bytes_per_bunch = 5000;
4136 core::array< core::list<SendableMedia> > file_bunches;
4137 file_bunches.push_back(core::list<SendableMedia>());
4139 u32 file_size_bunch_total = 0;
4141 for(core::list<MediaRequest>::ConstIterator i = tosend.begin();
4142 i != tosend.end(); i++)
4144 if(m_media.find(i->name) == m_media.end()){
4145 errorstream<<"Server::sendRequestedMedia(): Client asked for "
4146 <<"unknown file \""<<(i->name)<<"\""<<std::endl;
4150 //TODO get path + name
4151 std::string tpath = m_media[(*i).name].path;
4154 std::ifstream fis(tpath.c_str(), std::ios_base::binary);
4155 if(fis.good() == false){
4156 errorstream<<"Server::sendRequestedMedia(): Could not open \""
4157 <<tpath<<"\" for reading"<<std::endl;
4160 std::ostringstream tmp_os(std::ios_base::binary);
4164 fis.read(buf, 1024);
4165 std::streamsize len = fis.gcount();
4166 tmp_os.write(buf, len);
4167 file_size_bunch_total += len;
4176 errorstream<<"Server::sendRequestedMedia(): Failed to read \""
4177 <<(*i).name<<"\""<<std::endl;
4180 /*infostream<<"Server::sendRequestedMedia(): Loaded \""
4181 <<tname<<"\""<<std::endl;*/
4183 file_bunches[file_bunches.size()-1].push_back(
4184 SendableMedia((*i).name, tpath, tmp_os.str()));
4186 // Start next bunch if got enough data
4187 if(file_size_bunch_total >= bytes_per_bunch){
4188 file_bunches.push_back(core::list<SendableMedia>());
4189 file_size_bunch_total = 0;
4194 /* Create and send packets */
4196 u32 num_bunches = file_bunches.size();
4197 for(u32 i=0; i<num_bunches; i++)
4199 std::ostringstream os(std::ios_base::binary);
4203 u16 total number of texture bunches
4204 u16 index of this bunch
4205 u32 number of files in this bunch
4214 writeU16(os, TOCLIENT_MEDIA);
4215 writeU16(os, num_bunches);
4217 writeU32(os, file_bunches[i].size());
4219 for(core::list<SendableMedia>::Iterator
4220 j = file_bunches[i].begin();
4221 j != file_bunches[i].end(); j++){
4222 os<<serializeString(j->name);
4223 os<<serializeLongString(j->data);
4227 std::string s = os.str();
4228 verbosestream<<"Server::sendRequestedMedia(): bunch "
4229 <<i<<"/"<<num_bunches
4230 <<" files="<<file_bunches[i].size()
4231 <<" size=" <<s.size()<<std::endl;
4232 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
4234 m_con.Send(peer_id, 0, data, true);
4242 void Server::DiePlayer(u16 peer_id)
4244 DSTACK(__FUNCTION_NAME);
4246 PlayerSAO *playersao = getPlayerSAO(peer_id);
4249 infostream<<"Server::DiePlayer(): Player "
4250 <<playersao->getPlayer()->getName()
4251 <<" dies"<<std::endl;
4253 playersao->setHP(0);
4255 // Trigger scripted stuff
4256 scriptapi_on_dieplayer(m_lua, playersao);
4258 SendPlayerHP(peer_id);
4259 SendDeathscreen(m_con, peer_id, false, v3f(0,0,0));
4262 void Server::RespawnPlayer(u16 peer_id)
4264 DSTACK(__FUNCTION_NAME);
4266 PlayerSAO *playersao = getPlayerSAO(peer_id);
4269 infostream<<"Server::RespawnPlayer(): Player "
4270 <<playersao->getPlayer()->getName()
4271 <<" respawns"<<std::endl;
4273 playersao->setHP(PLAYER_MAX_HP);
4275 bool repositioned = scriptapi_on_respawnplayer(m_lua, playersao);
4277 v3f pos = findSpawnPos(m_env->getServerMap());
4278 playersao->setPos(pos);
4282 void Server::UpdateCrafting(u16 peer_id)
4284 DSTACK(__FUNCTION_NAME);
4286 Player* player = m_env->getPlayer(peer_id);
4289 // Get a preview for crafting
4291 // No crafting in creative mode
4292 if(g_settings->getBool("creative_mode") == false)
4293 getCraftingResult(&player->inventory, preview, false, this);
4295 // Put the new preview in
4296 InventoryList *plist = player->inventory.getList("craftpreview");
4298 assert(plist->getSize() >= 1);
4299 plist->changeItem(0, preview);
4302 RemoteClient* Server::getClient(u16 peer_id)
4304 DSTACK(__FUNCTION_NAME);
4305 //JMutexAutoLock lock(m_con_mutex);
4306 core::map<u16, RemoteClient*>::Node *n;
4307 n = m_clients.find(peer_id);
4308 // A client should exist for all peers
4310 return n->getValue();
4313 std::wstring Server::getStatusString()
4315 std::wostringstream os(std::ios_base::binary);
4318 os<<L"version="<<narrow_to_wide(VERSION_STRING);
4320 os<<L", uptime="<<m_uptime.get();
4321 // Information about clients
4323 for(core::map<u16, RemoteClient*>::Iterator
4324 i = m_clients.getIterator();
4325 i.atEnd() == false; i++)
4327 // Get client and check that it is valid
4328 RemoteClient *client = i.getNode()->getValue();
4329 assert(client->peer_id == i.getNode()->getKey());
4330 if(client->serialization_version == SER_FMT_VER_INVALID)
4333 Player *player = m_env->getPlayer(client->peer_id);
4334 // Get name of player
4335 std::wstring name = L"unknown";
4337 name = narrow_to_wide(player->getName());
4338 // Add name to information string
4342 if(((ServerMap*)(&m_env->getMap()))->isSavingEnabled() == false)
4343 os<<std::endl<<L"# Server: "<<" WARNING: Map saving is disabled.";
4344 if(g_settings->get("motd") != "")
4345 os<<std::endl<<L"# Server: "<<narrow_to_wide(g_settings->get("motd"));
4349 std::set<std::string> Server::getPlayerEffectivePrivs(const std::string &name)
4351 std::set<std::string> privs;
4352 scriptapi_get_auth(m_lua, name, NULL, &privs);
4356 bool Server::checkPriv(const std::string &name, const std::string &priv)
4358 std::set<std::string> privs = getPlayerEffectivePrivs(name);
4359 return (privs.count(priv) != 0);
4362 void Server::reportPrivsModified(const std::string &name)
4365 for(core::map<u16, RemoteClient*>::Iterator
4366 i = m_clients.getIterator();
4367 i.atEnd() == false; i++){
4368 RemoteClient *client = i.getNode()->getValue();
4369 Player *player = m_env->getPlayer(client->peer_id);
4370 reportPrivsModified(player->getName());
4373 Player *player = m_env->getPlayer(name.c_str());
4376 SendPlayerPrivileges(player->peer_id);
4377 PlayerSAO *sao = player->getPlayerSAO();
4380 sao->updatePrivileges(
4381 getPlayerEffectivePrivs(name),
4386 void Server::reportInventoryFormspecModified(const std::string &name)
4388 Player *player = m_env->getPlayer(name.c_str());
4391 SendPlayerInventoryFormspec(player->peer_id);
4394 // Saves g_settings to configpath given at initialization
4395 void Server::saveConfig()
4397 if(m_path_config != "")
4398 g_settings->updateConfigFile(m_path_config.c_str());
4401 void Server::notifyPlayer(const char *name, const std::wstring msg)
4403 Player *player = m_env->getPlayer(name);
4406 SendChatMessage(player->peer_id, std::wstring(L"Server: -!- ")+msg);
4409 void Server::notifyPlayers(const std::wstring msg)
4411 BroadcastChatMessage(msg);
4414 void Server::queueBlockEmerge(v3s16 blockpos, bool allow_generate)
4418 flags |= BLOCK_EMERGE_FLAG_FROMDISK;
4419 m_emerge_queue.addBlock(PEER_ID_INEXISTENT, blockpos, flags);
4422 // IGameDef interface
4424 IItemDefManager* Server::getItemDefManager()
4428 INodeDefManager* Server::getNodeDefManager()
4432 ICraftDefManager* Server::getCraftDefManager()
4436 ITextureSource* Server::getTextureSource()
4440 u16 Server::allocateUnknownNodeId(const std::string &name)
4442 return m_nodedef->allocateDummy(name);
4444 ISoundManager* Server::getSoundManager()
4446 return &dummySoundManager;
4448 MtEventManager* Server::getEventManager()
4453 IWritableItemDefManager* Server::getWritableItemDefManager()
4457 IWritableNodeDefManager* Server::getWritableNodeDefManager()
4461 IWritableCraftDefManager* Server::getWritableCraftDefManager()
4466 const ModSpec* Server::getModSpec(const std::string &modname)
4468 for(core::list<ModSpec>::Iterator i = m_mods.begin();
4469 i != m_mods.end(); i++){
4470 const ModSpec &mod = *i;
4471 if(mod.name == modname)
4476 std::string Server::getBuiltinLuaPath()
4478 return porting::path_share + DIR_DELIM + "builtin";
4481 v3f findSpawnPos(ServerMap &map)
4483 //return v3f(50,50,50)*BS;
4488 nodepos = v2s16(0,0);
4493 // Try to find a good place a few times
4494 for(s32 i=0; i<1000; i++)
4497 // We're going to try to throw the player to this position
4498 v2s16 nodepos2d = v2s16(-range + (myrand()%(range*2)),
4499 -range + (myrand()%(range*2)));
4500 //v2s16 sectorpos = getNodeSectorPos(nodepos2d);
4501 // Get ground height at point (fallbacks to heightmap function)
4502 s16 groundheight = map.findGroundLevel(nodepos2d);
4503 // Don't go underwater
4504 if(groundheight < WATER_LEVEL)
4506 //infostream<<"-> Underwater"<<std::endl;
4509 // Don't go to high places
4510 if(groundheight > WATER_LEVEL + 4)
4512 //infostream<<"-> Underwater"<<std::endl;
4516 nodepos = v3s16(nodepos2d.X, groundheight-2, nodepos2d.Y);
4517 bool is_good = false;
4519 for(s32 i=0; i<10; i++){
4520 v3s16 blockpos = getNodeBlockPos(nodepos);
4521 map.emergeBlock(blockpos, true);
4522 MapNode n = map.getNodeNoEx(nodepos);
4523 if(n.getContent() == CONTENT_AIR){
4534 // Found a good place
4535 //infostream<<"Searched through "<<i<<" places."<<std::endl;
4541 return intToFloat(nodepos, BS);
4544 PlayerSAO* Server::emergePlayer(const char *name, u16 peer_id)
4546 RemotePlayer *player = NULL;
4547 bool newplayer = false;
4550 Try to get an existing player
4552 player = static_cast<RemotePlayer*>(m_env->getPlayer(name));
4554 // If player is already connected, cancel
4555 if(player != NULL && player->peer_id != 0)
4557 infostream<<"emergePlayer(): Player already connected"<<std::endl;
4562 If player with the wanted peer_id already exists, cancel.
4564 if(m_env->getPlayer(peer_id) != NULL)
4566 infostream<<"emergePlayer(): Player with wrong name but same"
4567 " peer_id already exists"<<std::endl;
4572 Create a new player if it doesn't exist yet
4577 player = new RemotePlayer(this);
4578 player->updateName(name);
4580 /* Set player position */
4581 infostream<<"Server: Finding spawn place for player \""
4582 <<name<<"\""<<std::endl;
4583 v3f pos = findSpawnPos(m_env->getServerMap());
4584 player->setPosition(pos);
4586 /* Add player to environment */
4587 m_env->addPlayer(player);
4591 Create a new player active object
4593 PlayerSAO *playersao = new PlayerSAO(m_env, player, peer_id,
4594 getPlayerEffectivePrivs(player->getName()),
4597 /* Add object to environment */
4598 m_env->addActiveObject(playersao);
4602 scriptapi_on_newplayer(m_lua, playersao);
4604 scriptapi_on_joinplayer(m_lua, playersao);
4607 if(g_settings->getBool("creative_mode"))
4608 playersao->createCreativeInventory();
4613 void Server::handlePeerChange(PeerChange &c)
4615 JMutexAutoLock envlock(m_env_mutex);
4616 JMutexAutoLock conlock(m_con_mutex);
4618 if(c.type == PEER_ADDED)
4625 core::map<u16, RemoteClient*>::Node *n;
4626 n = m_clients.find(c.peer_id);
4627 // The client shouldn't already exist
4631 RemoteClient *client = new RemoteClient();
4632 client->peer_id = c.peer_id;
4633 m_clients.insert(client->peer_id, client);
4636 else if(c.type == PEER_REMOVED)
4643 core::map<u16, RemoteClient*>::Node *n;
4644 n = m_clients.find(c.peer_id);
4645 // The client should exist
4649 Mark objects to be not known by the client
4651 RemoteClient *client = n->getValue();
4653 for(core::map<u16, bool>::Iterator
4654 i = client->m_known_objects.getIterator();
4655 i.atEnd()==false; i++)
4658 u16 id = i.getNode()->getKey();
4659 ServerActiveObject* obj = m_env->getActiveObject(id);
4661 if(obj && obj->m_known_by_count > 0)
4662 obj->m_known_by_count--;
4666 Clear references to playing sounds
4668 for(std::map<s32, ServerPlayingSound>::iterator
4669 i = m_playing_sounds.begin();
4670 i != m_playing_sounds.end();)
4672 ServerPlayingSound &psound = i->second;
4673 psound.clients.erase(c.peer_id);
4674 if(psound.clients.size() == 0)
4675 m_playing_sounds.erase(i++);
4680 Player *player = m_env->getPlayer(c.peer_id);
4682 // Collect information about leaving in chat
4683 std::wstring message;
4687 std::wstring name = narrow_to_wide(player->getName());
4690 message += L" left the game.";
4692 message += L" (timed out)";
4696 /* Run scripts and remove from environment */
4700 PlayerSAO *playersao = player->getPlayerSAO();
4703 scriptapi_on_leaveplayer(m_lua, playersao);
4705 playersao->disconnected();
4715 std::ostringstream os(std::ios_base::binary);
4716 for(core::map<u16, RemoteClient*>::Iterator
4717 i = m_clients.getIterator();
4718 i.atEnd() == false; i++)
4720 RemoteClient *client = i.getNode()->getValue();
4721 assert(client->peer_id == i.getNode()->getKey());
4722 if(client->serialization_version == SER_FMT_VER_INVALID)
4725 Player *player = m_env->getPlayer(client->peer_id);
4728 // Get name of player
4729 os<<player->getName()<<" ";
4732 actionstream<<player->getName()<<" "
4733 <<(c.timeout?"times out.":"leaves game.")
4734 <<" List of players: "
4735 <<os.str()<<std::endl;
4740 delete m_clients[c.peer_id];
4741 m_clients.remove(c.peer_id);
4743 // Send player info to all remaining clients
4744 //SendPlayerInfos();
4746 // Send leave chat message to all remaining clients
4747 if(message.length() != 0)
4748 BroadcastChatMessage(message);
4757 void Server::handlePeerChanges()
4759 while(m_peer_change_queue.size() > 0)
4761 PeerChange c = m_peer_change_queue.pop_front();
4763 verbosestream<<"Server: Handling peer change: "
4764 <<"id="<<c.peer_id<<", timeout="<<c.timeout
4767 handlePeerChange(c);
4771 void dedicated_server_loop(Server &server, bool &kill)
4773 DSTACK(__FUNCTION_NAME);
4775 verbosestream<<"dedicated_server_loop()"<<std::endl;
4777 IntervalLimiter m_profiler_interval;
4781 float steplen = g_settings->getFloat("dedicated_server_step");
4782 // This is kind of a hack but can be done like this
4783 // because server.step() is very light
4785 ScopeProfiler sp(g_profiler, "dedicated server sleep");
4786 sleep_ms((int)(steplen*1000.0));
4788 server.step(steplen);
4790 if(server.getShutdownRequested() || kill)
4792 infostream<<"Dedicated server quitting"<<std::endl;
4799 float profiler_print_interval =
4800 g_settings->getFloat("profiler_print_interval");
4801 if(profiler_print_interval != 0)
4803 if(m_profiler_interval.step(steplen, profiler_print_interval))
4805 infostream<<"Profiler:"<<std::endl;
4806 g_profiler->print(infostream);
4807 g_profiler->clear();