3 Copyright (C) 2010-2013 celeron55, Perttu Ahola <celeron55@gmail.com>
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU Lesser General Public License as published by
7 the Free Software Foundation; either version 2.1 of the License, or
8 (at your option) any later version.
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU Lesser General Public License for more details.
15 You should have received a copy of the GNU Lesser General Public License along
16 with this program; if not, write to the Free Software Foundation, Inc.,
17 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
24 #include "clientserver.h"
26 #include "jmutexautolock.h"
28 #include "constants.h"
33 #include "serverobject.h"
38 #include "scriptapi.h"
45 #include "content_mapnode.h"
46 #include "content_nodemeta.h"
47 #include "content_abm.h"
48 #include "content_sao.h"
53 #include "sound.h" // dummySoundManager
54 #include "event_manager.h"
56 #include "serverlist.h"
57 #include "util/string.h"
58 #include "util/pointedthing.h"
59 #include "util/mathconstants.h"
61 #include "util/serialize.h"
62 #include "defaultsettings.h"
64 void * ServerThread::Thread()
68 log_register_thread("ServerThread");
70 DSTACK(__FUNCTION_NAME);
72 BEGIN_DEBUG_EXCEPTION_HANDLER
77 //TimeTaker timer("AsyncRunStep() + Receive()");
80 //TimeTaker timer("AsyncRunStep()");
81 m_server->AsyncRunStep();
84 //infostream<<"Running m_server->Receive()"<<std::endl;
87 catch(con::NoIncomingDataException &e)
90 catch(con::PeerNotFoundException &e)
92 infostream<<"Server: PeerNotFoundException"<<std::endl;
94 catch(con::ConnectionBindFailed &e)
96 m_server->setAsyncFatalError(e.what());
100 m_server->setAsyncFatalError(e.what());
104 END_DEBUG_EXCEPTION_HANDLER(errorstream)
109 v3f ServerSoundParams::getPos(ServerEnvironment *env, bool *pos_exists) const
111 if(pos_exists) *pos_exists = false;
116 if(pos_exists) *pos_exists = true;
121 ServerActiveObject *sao = env->getActiveObject(object);
124 if(pos_exists) *pos_exists = true;
125 return sao->getBasePosition(); }
130 void RemoteClient::GetNextBlocks(Server *server, float dtime,
131 std::vector<PrioritySortedBlockTransfer> &dest)
133 DSTACK(__FUNCTION_NAME);
136 TimeTaker timer("RemoteClient::GetNextBlocks", &timer_result);*/
139 m_nothing_to_send_pause_timer -= dtime;
140 m_nearest_unsent_reset_timer += dtime;
142 if(m_nothing_to_send_pause_timer >= 0)
145 Player *player = server->m_env->getPlayer(peer_id);
146 // This can happen sometimes; clients and players are not in perfect sync.
150 // Won't send anything if already sending
151 if(m_blocks_sending.size() >= g_settings->getU16
152 ("max_simultaneous_block_sends_per_client"))
154 //infostream<<"Not sending any blocks, Queue full."<<std::endl;
158 //TimeTaker timer("RemoteClient::GetNextBlocks");
160 v3f playerpos = player->getPosition();
161 v3f playerspeed = player->getSpeed();
162 v3f playerspeeddir(0,0,0);
163 if(playerspeed.getLength() > 1.0*BS)
164 playerspeeddir = playerspeed / playerspeed.getLength();
165 // Predict to next block
166 v3f playerpos_predicted = playerpos + playerspeeddir*MAP_BLOCKSIZE*BS;
168 v3s16 center_nodepos = floatToInt(playerpos_predicted, BS);
170 v3s16 center = getNodeBlockPos(center_nodepos);
172 // Camera position and direction
173 v3f camera_pos = player->getEyePosition();
174 v3f camera_dir = v3f(0,0,1);
175 camera_dir.rotateYZBy(player->getPitch());
176 camera_dir.rotateXZBy(player->getYaw());
178 /*infostream<<"camera_dir=("<<camera_dir.X<<","<<camera_dir.Y<<","
179 <<camera_dir.Z<<")"<<std::endl;*/
182 Get the starting value of the block finder radius.
185 if(m_last_center != center)
187 m_nearest_unsent_d = 0;
188 m_last_center = center;
191 /*infostream<<"m_nearest_unsent_reset_timer="
192 <<m_nearest_unsent_reset_timer<<std::endl;*/
194 // Reset periodically to workaround for some bugs or stuff
195 if(m_nearest_unsent_reset_timer > 20.0)
197 m_nearest_unsent_reset_timer = 0;
198 m_nearest_unsent_d = 0;
199 //infostream<<"Resetting m_nearest_unsent_d for "
200 // <<server->getPlayerName(peer_id)<<std::endl;
203 //s16 last_nearest_unsent_d = m_nearest_unsent_d;
204 s16 d_start = m_nearest_unsent_d;
206 //infostream<<"d_start="<<d_start<<std::endl;
208 u16 max_simul_sends_setting = g_settings->getU16
209 ("max_simultaneous_block_sends_per_client");
210 u16 max_simul_sends_usually = max_simul_sends_setting;
213 Check the time from last addNode/removeNode.
215 Decrease send rate if player is building stuff.
217 m_time_from_building += dtime;
218 if(m_time_from_building < g_settings->getFloat(
219 "full_block_send_enable_min_time_from_building"))
221 max_simul_sends_usually
222 = LIMITED_MAX_SIMULTANEOUS_BLOCK_SENDS;
226 Number of blocks sending + number of blocks selected for sending
228 u32 num_blocks_selected = m_blocks_sending.size();
231 next time d will be continued from the d from which the nearest
232 unsent block was found this time.
234 This is because not necessarily any of the blocks found this
235 time are actually sent.
237 s32 new_nearest_unsent_d = -1;
239 s16 d_max = g_settings->getS16("max_block_send_distance");
240 s16 d_max_gen = g_settings->getS16("max_block_generate_distance");
242 // Don't loop very much at a time
243 s16 max_d_increment_at_time = 2;
244 if(d_max > d_start + max_d_increment_at_time)
245 d_max = d_start + max_d_increment_at_time;
246 /*if(d_max_gen > d_start+2)
247 d_max_gen = d_start+2;*/
249 //infostream<<"Starting from "<<d_start<<std::endl;
251 s32 nearest_emerged_d = -1;
252 s32 nearest_emergefull_d = -1;
253 s32 nearest_sent_d = -1;
254 bool queue_is_full = false;
257 for(d = d_start; d <= d_max; d++)
259 /*errorstream<<"checking d="<<d<<" for "
260 <<server->getPlayerName(peer_id)<<std::endl;*/
261 //infostream<<"RemoteClient::SendBlocks(): d="<<d<<std::endl;
264 If m_nearest_unsent_d was changed by the EmergeThread
265 (it can change it to 0 through SetBlockNotSent),
267 Else update m_nearest_unsent_d
269 /*if(m_nearest_unsent_d != last_nearest_unsent_d)
271 d = m_nearest_unsent_d;
272 last_nearest_unsent_d = m_nearest_unsent_d;
276 Get the border/face dot coordinates of a "d-radiused"
279 std::list<v3s16> list;
280 getFacePositions(list, d);
282 std::list<v3s16>::iterator li;
283 for(li=list.begin(); li!=list.end(); ++li)
285 v3s16 p = *li + center;
289 - Don't allow too many simultaneous transfers
290 - EXCEPT when the blocks are very close
292 Also, don't send blocks that are already flying.
295 // Start with the usual maximum
296 u16 max_simul_dynamic = max_simul_sends_usually;
298 // If block is very close, allow full maximum
299 if(d <= BLOCK_SEND_DISABLE_LIMITS_MAX_D)
300 max_simul_dynamic = max_simul_sends_setting;
302 // Don't select too many blocks for sending
303 if(num_blocks_selected >= max_simul_dynamic)
305 queue_is_full = true;
306 goto queue_full_break;
309 // Don't send blocks that are currently being transferred
310 if(m_blocks_sending.find(p) != m_blocks_sending.end())
316 if(p.X < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
317 || p.X > MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
318 || p.Y < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
319 || p.Y > MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
320 || p.Z < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
321 || p.Z > MAP_GENERATION_LIMIT / MAP_BLOCKSIZE)
324 // If this is true, inexistent block will be made from scratch
325 bool generate = d <= d_max_gen;
328 /*// Limit the generating area vertically to 2/3
329 if(abs(p.Y - center.Y) > d_max_gen - d_max_gen / 3)
332 // Limit the send area vertically to 1/2
333 if(abs(p.Y - center.Y) > d_max / 2)
339 If block is far away, don't generate it unless it is
345 // Block center y in nodes
346 f32 y = (f32)(p.Y * MAP_BLOCKSIZE + MAP_BLOCKSIZE/2);
347 // Don't generate if it's very high or very low
348 if(y < -64 || y > 64)
352 v2s16 p2d_nodes_center(
356 // Get ground height in nodes
357 s16 gh = server->m_env->getServerMap().findGroundLevel(
360 // If differs a lot, don't generate
361 if(fabs(gh - y) > MAP_BLOCKSIZE*2)
363 // Actually, don't even send it
369 //infostream<<"d="<<d<<std::endl;
372 Don't generate or send if not in sight
373 FIXME This only works if the client uses a small enough
374 FOV setting. The default of 72 degrees is fine.
377 float camera_fov = (72.0*M_PI/180) * 4./3.;
378 if(isBlockInSight(p, camera_pos, camera_dir, camera_fov, 10000*BS) == false)
384 Don't send already sent blocks
387 if(m_blocks_sent.find(p) != m_blocks_sent.end())
394 Check if map has this block
396 MapBlock *block = server->m_env->getMap().getBlockNoCreateNoEx(p);
398 bool surely_not_found_on_disk = false;
399 bool block_is_invalid = false;
402 // Reset usage timer, this block will be of use in the future.
403 block->resetUsageTimer();
405 // Block is dummy if data doesn't exist.
406 // It means it has been not found from disk and not generated
409 surely_not_found_on_disk = true;
412 // Block is valid if lighting is up-to-date and data exists
413 if(block->isValid() == false)
415 block_is_invalid = true;
418 /*if(block->isFullyGenerated() == false)
420 block_is_invalid = true;
425 ServerMap *map = (ServerMap*)(&server->m_env->getMap());
426 v2s16 chunkpos = map->sector_to_chunk(p2d);
427 if(map->chunkNonVolatile(chunkpos) == false)
428 block_is_invalid = true;
430 if(block->isGenerated() == false)
431 block_is_invalid = true;
434 If block is not close, don't send it unless it is near
437 Block is near ground level if night-time mesh
438 differs from day-time mesh.
442 if(block->getDayNightDiff() == false)
449 If block has been marked to not exist on disk (dummy)
450 and generating new ones is not wanted, skip block.
452 if(generate == false && surely_not_found_on_disk == true)
459 Add inexistent block to emerge queue.
461 if(block == NULL || surely_not_found_on_disk || block_is_invalid)
463 /* //TODO: Get value from somewhere
464 // Allow only one block in emerge queue
465 //if(server->m_emerge_queue.peerItemCount(peer_id) < 1)
466 // Allow two blocks in queue per client
467 //if(server->m_emerge_queue.peerItemCount(peer_id) < 2)
469 // Make it more responsive when needing to generate stuff
470 if(surely_not_found_on_disk)
472 if(server->m_emerge_queue.peerItemCount(peer_id) < max_emerge)
474 //infostream<<"Adding block to emerge queue"<<std::endl;
476 // Add it to the emerge queue and trigger the thread
479 if(generate == false)
480 flags |= BLOCK_EMERGE_FLAG_FROMDISK;
482 server->m_emerge_queue.addBlock(peer_id, p, flags);
483 server->m_emergethread.trigger();
485 if(nearest_emerged_d == -1)
486 nearest_emerged_d = d;
488 if(nearest_emergefull_d == -1)
489 nearest_emergefull_d = d;
490 goto queue_full_break;
494 if (server->m_emerge->enqueueBlockEmerge(peer_id, p, generate)) {
495 if (nearest_emerged_d == -1)
496 nearest_emerged_d = d;
498 if (nearest_emergefull_d == -1)
499 nearest_emergefull_d = d;
500 goto queue_full_break;
507 if(nearest_sent_d == -1)
511 Add block to send queue
514 /*errorstream<<"sending from d="<<d<<" to "
515 <<server->getPlayerName(peer_id)<<std::endl;*/
517 PrioritySortedBlockTransfer q((float)d, p, peer_id);
521 num_blocks_selected += 1;
526 //infostream<<"Stopped at "<<d<<std::endl;
528 // If nothing was found for sending and nothing was queued for
529 // emerging, continue next time browsing from here
530 if(nearest_emerged_d != -1){
531 new_nearest_unsent_d = nearest_emerged_d;
532 } else if(nearest_emergefull_d != -1){
533 new_nearest_unsent_d = nearest_emergefull_d;
535 if(d > g_settings->getS16("max_block_send_distance")){
536 new_nearest_unsent_d = 0;
537 m_nothing_to_send_pause_timer = 2.0;
538 /*infostream<<"GetNextBlocks(): d wrapped around for "
539 <<server->getPlayerName(peer_id)
540 <<"; setting to 0 and pausing"<<std::endl;*/
542 if(nearest_sent_d != -1)
543 new_nearest_unsent_d = nearest_sent_d;
545 new_nearest_unsent_d = d;
549 if(new_nearest_unsent_d != -1)
550 m_nearest_unsent_d = new_nearest_unsent_d;
552 /*timer_result = timer.stop(true);
553 if(timer_result != 0)
554 infostream<<"GetNextBlocks timeout: "<<timer_result<<" (!=0)"<<std::endl;*/
557 void RemoteClient::GotBlock(v3s16 p)
559 if(m_blocks_sending.find(p) != m_blocks_sending.end())
560 m_blocks_sending.erase(p);
563 /*infostream<<"RemoteClient::GotBlock(): Didn't find in"
564 " m_blocks_sending"<<std::endl;*/
565 m_excess_gotblocks++;
567 m_blocks_sent.insert(p);
570 void RemoteClient::SentBlock(v3s16 p)
572 if(m_blocks_sending.find(p) == m_blocks_sending.end())
573 m_blocks_sending[p] = 0.0;
575 infostream<<"RemoteClient::SentBlock(): Sent block"
576 " already in m_blocks_sending"<<std::endl;
579 void RemoteClient::SetBlockNotSent(v3s16 p)
581 m_nearest_unsent_d = 0;
583 if(m_blocks_sending.find(p) != m_blocks_sending.end())
584 m_blocks_sending.erase(p);
585 if(m_blocks_sent.find(p) != m_blocks_sent.end())
586 m_blocks_sent.erase(p);
589 void RemoteClient::SetBlocksNotSent(std::map<v3s16, MapBlock*> &blocks)
591 m_nearest_unsent_d = 0;
593 for(std::map<v3s16, MapBlock*>::iterator
595 i != blocks.end(); ++i)
599 if(m_blocks_sending.find(p) != m_blocks_sending.end())
600 m_blocks_sending.erase(p);
601 if(m_blocks_sent.find(p) != m_blocks_sent.end())
602 m_blocks_sent.erase(p);
610 PlayerInfo::PlayerInfo()
616 void PlayerInfo::PrintLine(std::ostream *s)
619 (*s)<<"\""<<name<<"\" ("
620 <<(position.X/10)<<","<<(position.Y/10)
621 <<","<<(position.Z/10)<<") ";
623 (*s)<<" avg_rtt="<<avg_rtt;
632 const std::string &path_world,
633 const std::string &path_config,
634 const SubgameSpec &gamespec,
635 bool simple_singleplayer_mode
637 m_path_world(path_world),
638 m_path_config(path_config),
639 m_gamespec(gamespec),
640 m_simple_singleplayer_mode(simple_singleplayer_mode),
641 m_async_fatal_error(""),
643 m_con(PROTOCOL_ID, 512, CONNECTION_TIMEOUT, this),
644 m_banmanager(path_world+DIR_DELIM+"ipban.txt"),
646 m_rollback_sink_enabled(true),
647 m_enable_rollback_recording(false),
650 m_itemdef(createItemDefManager()),
651 m_nodedef(createNodeDefManager()),
652 m_craftdef(createCraftDefManager()),
653 m_event(new EventManager()),
655 m_time_of_day_send_timer(0),
657 m_shutdown_requested(false),
658 m_ignore_map_edit_events(false),
659 m_ignore_map_edit_events_peer_id(0)
661 m_liquid_transform_timer = 0.0;
662 m_liquid_transform_every = 1.0;
663 m_print_info_timer = 0.0;
664 m_masterserver_timer = 0.0;
665 m_objectdata_timer = 0.0;
666 m_emergethread_trigger_timer = 0.0;
667 m_savemap_timer = 0.0;
668 m_clients_number = 0;
672 m_step_dtime_mutex.Init();
676 throw ServerError("Supplied empty world path");
678 if(!gamespec.isValid())
679 throw ServerError("Supplied invalid gamespec");
681 infostream<<"Server created for gameid \""<<m_gamespec.id<<"\"";
682 if(m_simple_singleplayer_mode)
683 infostream<<" in simple singleplayer mode"<<std::endl;
685 infostream<<std::endl;
686 infostream<<"- world: "<<m_path_world<<std::endl;
687 infostream<<"- config: "<<m_path_config<<std::endl;
688 infostream<<"- game: "<<m_gamespec.path<<std::endl;
690 // Initialize default settings and override defaults with those provided
692 set_default_settings(g_settings);
693 Settings gamedefaults;
694 getGameMinetestConfig(gamespec.path, gamedefaults);
695 override_default_settings(g_settings, &gamedefaults);
697 // Create emerge manager
698 m_emerge = new EmergeManager(this);
700 // Create rollback manager
701 std::string rollback_path = m_path_world+DIR_DELIM+"rollback.txt";
702 m_rollback = createRollbackManager(rollback_path, this);
704 // Create world if it doesn't exist
705 if(!initializeWorld(m_path_world, m_gamespec.id))
706 throw ServerError("Failed to initialize world");
708 ModConfiguration modconf(m_path_world);
709 m_mods = modconf.getMods();
710 std::list<ModSpec> unsatisfied_mods = modconf.getUnsatisfiedMods();
711 // complain about mods with unsatisfied dependencies
712 if(!modconf.isConsistent())
714 for(std::list<ModSpec>::iterator it = unsatisfied_mods.begin();
715 it != unsatisfied_mods.end(); ++it)
718 errorstream << "mod \"" << mod.name << "\" has unsatisfied dependencies: ";
719 for(std::set<std::string>::iterator dep_it = mod.unsatisfied_depends.begin();
720 dep_it != mod.unsatisfied_depends.end(); ++dep_it)
721 errorstream << " \"" << *dep_it << "\"";
722 errorstream << std::endl;
726 Settings worldmt_settings;
727 std::string worldmt = m_path_world + DIR_DELIM + "world.mt";
728 worldmt_settings.readConfigFile(worldmt.c_str());
729 std::vector<std::string> names = worldmt_settings.getNames();
730 std::set<std::string> exclude_mod_names;
731 std::set<std::string> load_mod_names;
732 for(std::vector<std::string>::iterator it = names.begin();
733 it != names.end(); ++it)
735 std::string name = *it;
736 if (name.compare(0,9,"load_mod_")==0)
738 if(worldmt_settings.getBool(name))
739 load_mod_names.insert(name.substr(9));
741 exclude_mod_names.insert(name.substr(9));
744 // complain about mods declared to be loaded, but not found
745 for(std::vector<ModSpec>::iterator it = m_mods.begin();
746 it != m_mods.end(); ++it)
747 load_mod_names.erase((*it).name);
748 for(std::list<ModSpec>::iterator it = unsatisfied_mods.begin();
749 it != unsatisfied_mods.end(); ++it)
750 load_mod_names.erase((*it).name);
751 if(!load_mod_names.empty())
753 errorstream << "The following mods could not be found:";
754 for(std::set<std::string>::iterator it = load_mod_names.begin();
755 it != load_mod_names.end(); ++it)
756 errorstream << " \"" << (*it) << "\"";
757 errorstream << std::endl;
760 // Path to builtin.lua
761 std::string builtinpath = getBuiltinLuaPath() + DIR_DELIM + "builtin.lua";
764 JMutexAutoLock envlock(m_env_mutex);
765 JMutexAutoLock conlock(m_con_mutex);
767 // Initialize scripting
769 infostream<<"Server: Initializing Lua"<<std::endl;
770 m_lua = script_init();
773 scriptapi_export(m_lua, this);
774 // Load and run builtin.lua
775 infostream<<"Server: Loading builtin.lua [\""
776 <<builtinpath<<"\"]"<<std::endl;
777 bool success = scriptapi_loadmod(m_lua, builtinpath, "__builtin");
779 errorstream<<"Server: Failed to load and run "
780 <<builtinpath<<std::endl;
781 throw ModError("Failed to load and run "+builtinpath);
784 infostream<<"Server: Loading mods: ";
785 for(std::vector<ModSpec>::iterator i = m_mods.begin();
786 i != m_mods.end(); i++){
787 const ModSpec &mod = *i;
788 infostream<<mod.name<<" ";
790 infostream<<std::endl;
791 // Load and run "mod" scripts
792 for(std::vector<ModSpec>::iterator i = m_mods.begin();
793 i != m_mods.end(); i++){
794 const ModSpec &mod = *i;
795 std::string scriptpath = mod.path + DIR_DELIM + "init.lua";
796 infostream<<" ["<<padStringRight(mod.name, 12)<<"] [\""
797 <<scriptpath<<"\"]"<<std::endl;
798 bool success = scriptapi_loadmod(m_lua, scriptpath, mod.name);
800 errorstream<<"Server: Failed to load and run "
801 <<scriptpath<<std::endl;
802 throw ModError("Failed to load and run "+scriptpath);
806 // Read Textures and calculate sha1 sums
809 // Apply item aliases in the node definition manager
810 m_nodedef->updateAliases(m_itemdef);
812 // Initialize Environment
813 ServerMap *servermap = new ServerMap(path_world, this, m_emerge);
814 m_env = new ServerEnvironment(servermap, m_lua, this, this);
816 m_emerge->initMapgens(servermap->getMapgenParams());
818 // Give environment reference to scripting api
819 scriptapi_add_environment(m_lua, m_env);
821 // Register us to receive map edit events
822 servermap->addEventReceiver(this);
824 // If file exists, load environment metadata
825 if(fs::PathExists(m_path_world+DIR_DELIM+"env_meta.txt"))
827 infostream<<"Server: Loading environment metadata"<<std::endl;
828 m_env->loadMeta(m_path_world);
832 infostream<<"Server: Loading players"<<std::endl;
833 m_env->deSerializePlayers(m_path_world);
836 Add some test ActiveBlockModifiers to environment
838 add_legacy_abms(m_env, m_nodedef);
840 m_liquid_transform_every = g_settings->getFloat("liquid_update");
845 infostream<<"Server destructing"<<std::endl;
848 Send shutdown message
851 JMutexAutoLock conlock(m_con_mutex);
853 std::wstring line = L"*** Server shutting down";
856 Send the message to clients
858 for(std::map<u16, RemoteClient*>::iterator
859 i = m_clients.begin();
860 i != m_clients.end(); ++i)
862 // Get client and check that it is valid
863 RemoteClient *client = i->second;
864 assert(client->peer_id == i->first);
865 if(client->serialization_version == SER_FMT_VER_INVALID)
869 SendChatMessage(client->peer_id, line);
871 catch(con::PeerNotFoundException &e)
877 JMutexAutoLock envlock(m_env_mutex);
878 JMutexAutoLock conlock(m_con_mutex);
881 Execute script shutdown hooks
883 scriptapi_on_shutdown(m_lua);
887 JMutexAutoLock envlock(m_env_mutex);
892 infostream<<"Server: Saving players"<<std::endl;
893 m_env->serializePlayers(m_path_world);
896 Save environment metadata
898 infostream<<"Server: Saving environment metadata"<<std::endl;
899 m_env->saveMeta(m_path_world);
911 JMutexAutoLock clientslock(m_con_mutex);
913 for(std::map<u16, RemoteClient*>::iterator
914 i = m_clients.begin();
915 i != m_clients.end(); ++i)
923 // Delete things in the reverse order of creation
932 // Deinitialize scripting
933 infostream<<"Server: Deinitializing scripting"<<std::endl;
934 script_deinit(m_lua);
936 // Delete detached inventories
938 for(std::map<std::string, Inventory*>::iterator
939 i = m_detached_inventories.begin();
940 i != m_detached_inventories.end(); i++){
946 void Server::start(unsigned short port)
948 DSTACK(__FUNCTION_NAME);
949 infostream<<"Starting server on port "<<port<<"..."<<std::endl;
951 // Stop thread if already running
954 // Initialize connection
955 m_con.SetTimeoutMs(30);
959 m_thread.setRun(true);
962 // ASCII art for the win!
964 <<" .__ __ __ "<<std::endl
965 <<" _____ |__| ____ _____/ |_ ____ _______/ |_ "<<std::endl
966 <<" / \\| |/ \\_/ __ \\ __\\/ __ \\ / ___/\\ __\\"<<std::endl
967 <<"| Y Y \\ | | \\ ___/| | \\ ___/ \\___ \\ | | "<<std::endl
968 <<"|__|_| /__|___| /\\___ >__| \\___ >____ > |__| "<<std::endl
969 <<" \\/ \\/ \\/ \\/ \\/ "<<std::endl;
970 actionstream<<"World at ["<<m_path_world<<"]"<<std::endl;
971 actionstream<<"Server for gameid=\""<<m_gamespec.id
972 <<"\" listening on port "<<port<<"."<<std::endl;
977 DSTACK(__FUNCTION_NAME);
979 infostream<<"Server: Stopping and waiting threads"<<std::endl;
981 // Stop threads (set run=false first so both start stopping)
982 m_thread.setRun(false);
983 //m_emergethread.setRun(false);
985 //m_emergethread.stop();
987 infostream<<"Server: Threads stopped"<<std::endl;
990 void Server::step(float dtime)
992 DSTACK(__FUNCTION_NAME);
997 JMutexAutoLock lock(m_step_dtime_mutex);
998 m_step_dtime += dtime;
1000 // Throw if fatal error occurred in thread
1001 std::string async_err = m_async_fatal_error.get();
1002 if(async_err != ""){
1003 throw ServerError(async_err);
1007 void Server::AsyncRunStep()
1009 DSTACK(__FUNCTION_NAME);
1011 g_profiler->add("Server::AsyncRunStep (num)", 1);
1015 JMutexAutoLock lock1(m_step_dtime_mutex);
1016 dtime = m_step_dtime;
1020 // Send blocks to clients
1027 g_profiler->add("Server::AsyncRunStep with dtime (num)", 1);
1029 //infostream<<"Server steps "<<dtime<<std::endl;
1030 //infostream<<"Server::AsyncRunStep(): dtime="<<dtime<<std::endl;
1033 JMutexAutoLock lock1(m_step_dtime_mutex);
1034 m_step_dtime -= dtime;
1041 m_uptime.set(m_uptime.get() + dtime);
1045 // Process connection's timeouts
1046 JMutexAutoLock lock2(m_con_mutex);
1047 ScopeProfiler sp(g_profiler, "Server: connection timeout processing");
1048 m_con.RunTimeouts(dtime);
1052 // This has to be called so that the client list gets synced
1053 // with the peer list of the connection
1054 handlePeerChanges();
1058 Update time of day and overall game time
1061 JMutexAutoLock envlock(m_env_mutex);
1063 m_env->setTimeOfDaySpeed(g_settings->getFloat("time_speed"));
1066 Send to clients at constant intervals
1069 m_time_of_day_send_timer -= dtime;
1070 if(m_time_of_day_send_timer < 0.0)
1072 m_time_of_day_send_timer = g_settings->getFloat("time_send_interval");
1074 //JMutexAutoLock envlock(m_env_mutex);
1075 JMutexAutoLock conlock(m_con_mutex);
1077 for(std::map<u16, RemoteClient*>::iterator
1078 i = m_clients.begin();
1079 i != m_clients.end(); ++i)
1081 RemoteClient *client = i->second;
1082 SharedBuffer<u8> data = makePacket_TOCLIENT_TIME_OF_DAY(
1083 m_env->getTimeOfDay(), g_settings->getFloat("time_speed"));
1085 m_con.Send(client->peer_id, 0, data, true);
1091 JMutexAutoLock lock(m_env_mutex);
1093 ScopeProfiler sp(g_profiler, "SEnv step");
1094 ScopeProfiler sp2(g_profiler, "SEnv step avg", SPT_AVG);
1098 const float map_timer_and_unload_dtime = 2.92;
1099 if(m_map_timer_and_unload_interval.step(dtime, map_timer_and_unload_dtime))
1101 JMutexAutoLock lock(m_env_mutex);
1102 // Run Map's timers and unload unused data
1103 ScopeProfiler sp(g_profiler, "Server: map timer and unload");
1104 m_env->getMap().timerUpdate(map_timer_and_unload_dtime,
1105 g_settings->getFloat("server_unload_unused_data_timeout"));
1116 JMutexAutoLock lock(m_env_mutex);
1117 JMutexAutoLock lock2(m_con_mutex);
1119 ScopeProfiler sp(g_profiler, "Server: handle players");
1121 for(std::map<u16, RemoteClient*>::iterator
1122 i = m_clients.begin();
1123 i != m_clients.end(); ++i)
1125 RemoteClient *client = i->second;
1126 PlayerSAO *playersao = getPlayerSAO(client->peer_id);
1127 if(playersao == NULL)
1131 Handle player HPs (die if hp=0)
1133 if(playersao->m_hp_not_sent && g_settings->getBool("enable_damage"))
1135 if(playersao->getHP() == 0)
1136 DiePlayer(client->peer_id);
1138 SendPlayerHP(client->peer_id);
1142 Send player inventories if necessary
1144 if(playersao->m_moved){
1145 SendMovePlayer(client->peer_id);
1146 playersao->m_moved = false;
1148 if(playersao->m_inventory_not_sent){
1149 UpdateCrafting(client->peer_id);
1150 SendInventory(client->peer_id);
1155 /* Transform liquids */
1156 m_liquid_transform_timer += dtime;
1157 if(m_liquid_transform_timer >= m_liquid_transform_every)
1159 m_liquid_transform_timer -= m_liquid_transform_every;
1161 JMutexAutoLock lock(m_env_mutex);
1163 ScopeProfiler sp(g_profiler, "Server: liquid transform");
1165 std::map<v3s16, MapBlock*> modified_blocks;
1166 m_env->getMap().transformLiquids(modified_blocks);
1171 core::map<v3s16, MapBlock*> lighting_modified_blocks;
1172 ServerMap &map = ((ServerMap&)m_env->getMap());
1173 map.updateLighting(modified_blocks, lighting_modified_blocks);
1175 // Add blocks modified by lighting to modified_blocks
1176 for(core::map<v3s16, MapBlock*>::Iterator
1177 i = lighting_modified_blocks.getIterator();
1178 i.atEnd() == false; i++)
1180 MapBlock *block = i.getNode()->getValue();
1181 modified_blocks.insert(block->getPos(), block);
1185 Set the modified blocks unsent for all the clients
1188 JMutexAutoLock lock2(m_con_mutex);
1190 for(std::map<u16, RemoteClient*>::iterator
1191 i = m_clients.begin();
1192 i != m_clients.end(); ++i)
1194 RemoteClient *client = i->second;
1196 if(modified_blocks.size() > 0)
1198 // Remove block from sent history
1199 client->SetBlocksNotSent(modified_blocks);
1204 // Periodically print some info
1206 float &counter = m_print_info_timer;
1212 JMutexAutoLock lock2(m_con_mutex);
1213 m_clients_number = 0;
1214 if(m_clients.size() != 0)
1215 infostream<<"Players:"<<std::endl;
1216 for(std::map<u16, RemoteClient*>::iterator
1217 i = m_clients.begin();
1218 i != m_clients.end(); ++i)
1220 //u16 peer_id = i.getNode()->getKey();
1221 RemoteClient *client = i->second;
1222 Player *player = m_env->getPlayer(client->peer_id);
1225 infostream<<"* "<<player->getName()<<"\t";
1226 client->PrintInfo(infostream);
1234 // send masterserver announce
1236 float &counter = m_masterserver_timer;
1237 if((!counter || counter >= 300.0) && g_settings->getBool("server_announce") == true)
1239 ServerList::sendAnnounce(!counter ? "start" : "update", m_clients_number, m_uptime.get(), m_gamespec.id);
1246 //if(g_settings->getBool("enable_experimental"))
1250 Check added and deleted active objects
1253 //infostream<<"Server: Checking added and deleted active objects"<<std::endl;
1254 JMutexAutoLock envlock(m_env_mutex);
1255 JMutexAutoLock conlock(m_con_mutex);
1257 ScopeProfiler sp(g_profiler, "Server: checking added and deleted objs");
1259 // Radius inside which objects are active
1260 s16 radius = g_settings->getS16("active_object_send_range_blocks");
1261 radius *= MAP_BLOCKSIZE;
1263 for(std::map<u16, RemoteClient*>::iterator
1264 i = m_clients.begin();
1265 i != m_clients.end(); ++i)
1267 RemoteClient *client = i->second;
1269 // If definitions and textures have not been sent, don't
1270 // send objects either
1271 if(!client->definitions_sent)
1274 Player *player = m_env->getPlayer(client->peer_id);
1277 // This can happen if the client timeouts somehow
1278 /*infostream<<"WARNING: "<<__FUNCTION_NAME<<": Client "
1280 <<" has no associated player"<<std::endl;*/
1283 v3s16 pos = floatToInt(player->getPosition(), BS);
1285 std::set<u16> removed_objects;
1286 std::set<u16> added_objects;
1287 m_env->getRemovedActiveObjects(pos, radius,
1288 client->m_known_objects, removed_objects);
1289 m_env->getAddedActiveObjects(pos, radius,
1290 client->m_known_objects, added_objects);
1292 // Ignore if nothing happened
1293 if(removed_objects.size() == 0 && added_objects.size() == 0)
1295 //infostream<<"active objects: none changed"<<std::endl;
1299 std::string data_buffer;
1303 // Handle removed objects
1304 writeU16((u8*)buf, removed_objects.size());
1305 data_buffer.append(buf, 2);
1306 for(std::set<u16>::iterator
1307 i = removed_objects.begin();
1308 i != removed_objects.end(); ++i)
1312 ServerActiveObject* obj = m_env->getActiveObject(id);
1314 // Add to data buffer for sending
1315 writeU16((u8*)buf, id);
1316 data_buffer.append(buf, 2);
1318 // Remove from known objects
1319 client->m_known_objects.erase(id);
1321 if(obj && obj->m_known_by_count > 0)
1322 obj->m_known_by_count--;
1325 // Handle added objects
1326 writeU16((u8*)buf, added_objects.size());
1327 data_buffer.append(buf, 2);
1328 for(std::set<u16>::iterator
1329 i = added_objects.begin();
1330 i != added_objects.end(); ++i)
1334 ServerActiveObject* obj = m_env->getActiveObject(id);
1337 u8 type = ACTIVEOBJECT_TYPE_INVALID;
1339 infostream<<"WARNING: "<<__FUNCTION_NAME
1340 <<": NULL object"<<std::endl;
1342 type = obj->getSendType();
1344 // Add to data buffer for sending
1345 writeU16((u8*)buf, id);
1346 data_buffer.append(buf, 2);
1347 writeU8((u8*)buf, type);
1348 data_buffer.append(buf, 1);
1351 data_buffer.append(serializeLongString(
1352 obj->getClientInitializationData(client->net_proto_version)));
1354 data_buffer.append(serializeLongString(""));
1356 // Add to known objects
1357 client->m_known_objects.insert(id);
1360 obj->m_known_by_count++;
1364 SharedBuffer<u8> reply(2 + data_buffer.size());
1365 writeU16(&reply[0], TOCLIENT_ACTIVE_OBJECT_REMOVE_ADD);
1366 memcpy((char*)&reply[2], data_buffer.c_str(),
1367 data_buffer.size());
1369 m_con.Send(client->peer_id, 0, reply, true);
1371 verbosestream<<"Server: Sent object remove/add: "
1372 <<removed_objects.size()<<" removed, "
1373 <<added_objects.size()<<" added, "
1374 <<"packet size is "<<reply.getSize()<<std::endl;
1379 Collect a list of all the objects known by the clients
1380 and report it back to the environment.
1383 core::map<u16, bool> all_known_objects;
1385 for(core::map<u16, RemoteClient*>::Iterator
1386 i = m_clients.getIterator();
1387 i.atEnd() == false; i++)
1389 RemoteClient *client = i.getNode()->getValue();
1390 // Go through all known objects of client
1391 for(core::map<u16, bool>::Iterator
1392 i = client->m_known_objects.getIterator();
1393 i.atEnd()==false; i++)
1395 u16 id = i.getNode()->getKey();
1396 all_known_objects[id] = true;
1400 m_env->setKnownActiveObjects(whatever);
1406 Send object messages
1409 JMutexAutoLock envlock(m_env_mutex);
1410 JMutexAutoLock conlock(m_con_mutex);
1412 ScopeProfiler sp(g_profiler, "Server: sending object messages");
1415 // Value = data sent by object
1416 std::map<u16, std::list<ActiveObjectMessage>* > buffered_messages;
1418 // Get active object messages from environment
1421 ActiveObjectMessage aom = m_env->getActiveObjectMessage();
1425 std::list<ActiveObjectMessage>* message_list = NULL;
1426 std::map<u16, std::list<ActiveObjectMessage>* >::iterator n;
1427 n = buffered_messages.find(aom.id);
1428 if(n == buffered_messages.end())
1430 message_list = new std::list<ActiveObjectMessage>;
1431 buffered_messages[aom.id] = message_list;
1435 message_list = n->second;
1437 message_list->push_back(aom);
1440 // Route data to every client
1441 for(std::map<u16, RemoteClient*>::iterator
1442 i = m_clients.begin();
1443 i != m_clients.end(); ++i)
1445 RemoteClient *client = i->second;
1446 std::string reliable_data;
1447 std::string unreliable_data;
1448 // Go through all objects in message buffer
1449 for(std::map<u16, std::list<ActiveObjectMessage>* >::iterator
1450 j = buffered_messages.begin();
1451 j != buffered_messages.end(); ++j)
1453 // If object is not known by client, skip it
1455 if(client->m_known_objects.find(id) == client->m_known_objects.end())
1457 // Get message list of object
1458 std::list<ActiveObjectMessage>* list = j->second;
1459 // Go through every message
1460 for(std::list<ActiveObjectMessage>::iterator
1461 k = list->begin(); k != list->end(); ++k)
1463 // Compose the full new data with header
1464 ActiveObjectMessage aom = *k;
1465 std::string new_data;
1468 writeU16((u8*)&buf[0], aom.id);
1469 new_data.append(buf, 2);
1471 new_data += serializeString(aom.datastring);
1472 // Add data to buffer
1474 reliable_data += new_data;
1476 unreliable_data += new_data;
1480 reliable_data and unreliable_data are now ready.
1483 if(reliable_data.size() > 0)
1485 SharedBuffer<u8> reply(2 + reliable_data.size());
1486 writeU16(&reply[0], TOCLIENT_ACTIVE_OBJECT_MESSAGES);
1487 memcpy((char*)&reply[2], reliable_data.c_str(),
1488 reliable_data.size());
1490 m_con.Send(client->peer_id, 0, reply, true);
1492 if(unreliable_data.size() > 0)
1494 SharedBuffer<u8> reply(2 + unreliable_data.size());
1495 writeU16(&reply[0], TOCLIENT_ACTIVE_OBJECT_MESSAGES);
1496 memcpy((char*)&reply[2], unreliable_data.c_str(),
1497 unreliable_data.size());
1498 // Send as unreliable
1499 m_con.Send(client->peer_id, 0, reply, false);
1502 /*if(reliable_data.size() > 0 || unreliable_data.size() > 0)
1504 infostream<<"Server: Size of object message data: "
1505 <<"reliable: "<<reliable_data.size()
1506 <<", unreliable: "<<unreliable_data.size()
1511 // Clear buffered_messages
1512 for(std::map<u16, std::list<ActiveObjectMessage>* >::iterator
1513 i = buffered_messages.begin();
1514 i != buffered_messages.end(); ++i)
1520 } // enable_experimental
1523 Send queued-for-sending map edit events.
1526 // We will be accessing the environment and the connection
1527 JMutexAutoLock lock(m_env_mutex);
1528 JMutexAutoLock conlock(m_con_mutex);
1530 // Don't send too many at a time
1533 // Single change sending is disabled if queue size is not small
1534 bool disable_single_change_sending = false;
1535 if(m_unsent_map_edit_queue.size() >= 4)
1536 disable_single_change_sending = true;
1538 int event_count = m_unsent_map_edit_queue.size();
1540 // We'll log the amount of each
1543 while(m_unsent_map_edit_queue.size() != 0)
1545 MapEditEvent* event = m_unsent_map_edit_queue.pop_front();
1547 // Players far away from the change are stored here.
1548 // Instead of sending the changes, MapBlocks are set not sent
1550 std::list<u16> far_players;
1552 if(event->type == MEET_ADDNODE)
1554 //infostream<<"Server: MEET_ADDNODE"<<std::endl;
1555 prof.add("MEET_ADDNODE", 1);
1556 if(disable_single_change_sending)
1557 sendAddNode(event->p, event->n, event->already_known_by_peer,
1560 sendAddNode(event->p, event->n, event->already_known_by_peer,
1563 else if(event->type == MEET_REMOVENODE)
1565 //infostream<<"Server: MEET_REMOVENODE"<<std::endl;
1566 prof.add("MEET_REMOVENODE", 1);
1567 if(disable_single_change_sending)
1568 sendRemoveNode(event->p, event->already_known_by_peer,
1571 sendRemoveNode(event->p, event->already_known_by_peer,
1574 else if(event->type == MEET_BLOCK_NODE_METADATA_CHANGED)
1576 infostream<<"Server: MEET_BLOCK_NODE_METADATA_CHANGED"<<std::endl;
1577 prof.add("MEET_BLOCK_NODE_METADATA_CHANGED", 1);
1578 setBlockNotSent(event->p);
1580 else if(event->type == MEET_OTHER)
1582 infostream<<"Server: MEET_OTHER"<<std::endl;
1583 prof.add("MEET_OTHER", 1);
1584 for(std::set<v3s16>::iterator
1585 i = event->modified_blocks.begin();
1586 i != event->modified_blocks.end(); ++i)
1588 setBlockNotSent(*i);
1593 prof.add("unknown", 1);
1594 infostream<<"WARNING: Server: Unknown MapEditEvent "
1595 <<((u32)event->type)<<std::endl;
1599 Set blocks not sent to far players
1601 if(far_players.size() > 0)
1603 // Convert list format to that wanted by SetBlocksNotSent
1604 std::map<v3s16, MapBlock*> modified_blocks2;
1605 for(std::set<v3s16>::iterator
1606 i = event->modified_blocks.begin();
1607 i != event->modified_blocks.end(); ++i)
1609 modified_blocks2[*i] =
1610 m_env->getMap().getBlockNoCreateNoEx(*i);
1612 // Set blocks not sent
1613 for(std::list<u16>::iterator
1614 i = far_players.begin();
1615 i != far_players.end(); ++i)
1618 RemoteClient *client = getClient(peer_id);
1621 client->SetBlocksNotSent(modified_blocks2);
1627 /*// Don't send too many at a time
1629 if(count >= 1 && m_unsent_map_edit_queue.size() < 100)
1633 if(event_count >= 5){
1634 infostream<<"Server: MapEditEvents:"<<std::endl;
1635 prof.print(infostream);
1636 } else if(event_count != 0){
1637 verbosestream<<"Server: MapEditEvents:"<<std::endl;
1638 prof.print(verbosestream);
1644 Trigger emergethread (it somehow gets to a non-triggered but
1645 bysy state sometimes)
1648 float &counter = m_emergethread_trigger_timer;
1654 for (unsigned int i = 0; i != m_emerge->emergethread.size(); i++)
1655 m_emerge->emergethread[i]->trigger();
1657 // Update m_enable_rollback_recording here too
1658 m_enable_rollback_recording =
1659 g_settings->getBool("enable_rollback_recording");
1663 // Save map, players and auth stuff
1665 float &counter = m_savemap_timer;
1667 if(counter >= g_settings->getFloat("server_map_save_interval"))
1670 JMutexAutoLock lock(m_env_mutex);
1672 ScopeProfiler sp(g_profiler, "Server: saving stuff");
1675 if(m_banmanager.isModified())
1676 m_banmanager.save();
1678 // Save changed parts of map
1679 m_env->getMap().save(MOD_STATE_WRITE_NEEDED);
1682 m_env->serializePlayers(m_path_world);
1684 // Save environment metadata
1685 m_env->saveMeta(m_path_world);
1690 void Server::Receive()
1692 DSTACK(__FUNCTION_NAME);
1693 SharedBuffer<u8> data;
1698 JMutexAutoLock conlock(m_con_mutex);
1699 datasize = m_con.Receive(peer_id, data);
1702 // This has to be called so that the client list gets synced
1703 // with the peer list of the connection
1704 handlePeerChanges();
1706 ProcessData(*data, datasize, peer_id);
1708 catch(con::InvalidIncomingDataException &e)
1710 infostream<<"Server::Receive(): "
1711 "InvalidIncomingDataException: what()="
1712 <<e.what()<<std::endl;
1714 catch(con::PeerNotFoundException &e)
1716 //NOTE: This is not needed anymore
1718 // The peer has been disconnected.
1719 // Find the associated player and remove it.
1721 /*JMutexAutoLock envlock(m_env_mutex);
1723 infostream<<"ServerThread: peer_id="<<peer_id
1724 <<" has apparently closed connection. "
1725 <<"Removing player."<<std::endl;
1727 m_env->removePlayer(peer_id);*/
1731 void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
1733 DSTACK(__FUNCTION_NAME);
1734 // Environment is locked first.
1735 JMutexAutoLock envlock(m_env_mutex);
1736 JMutexAutoLock conlock(m_con_mutex);
1738 ScopeProfiler sp(g_profiler, "Server::ProcessData");
1741 Address address = m_con.GetPeerAddress(peer_id);
1742 std::string addr_s = address.serializeString();
1744 // drop player if is ip is banned
1745 if(m_banmanager.isIpBanned(addr_s)){
1746 infostream<<"Server: A banned client tried to connect from "
1747 <<addr_s<<"; banned name was "
1748 <<m_banmanager.getBanName(addr_s)<<std::endl;
1749 // This actually doesn't seem to transfer to the client
1750 SendAccessDenied(m_con, peer_id,
1751 L"Your ip is banned. Banned name was "
1752 +narrow_to_wide(m_banmanager.getBanName(addr_s)));
1753 m_con.DeletePeer(peer_id);
1757 catch(con::PeerNotFoundException &e)
1759 infostream<<"Server::ProcessData(): Cancelling: peer "
1760 <<peer_id<<" not found"<<std::endl;
1764 std::string addr_s = m_con.GetPeerAddress(peer_id).serializeString();
1766 u8 peer_ser_ver = getClient(peer_id)->serialization_version;
1774 ToServerCommand command = (ToServerCommand)readU16(&data[0]);
1776 if(command == TOSERVER_INIT)
1778 // [0] u16 TOSERVER_INIT
1779 // [2] u8 SER_FMT_VER_HIGHEST
1780 // [3] u8[20] player_name
1781 // [23] u8[28] password <--- can be sent without this, from old versions
1783 if(datasize < 2+1+PLAYERNAME_SIZE)
1786 verbosestream<<"Server: Got TOSERVER_INIT from "
1787 <<peer_id<<std::endl;
1789 // First byte after command is maximum supported
1790 // serialization version
1791 u8 client_max = data[2];
1792 u8 our_max = SER_FMT_VER_HIGHEST;
1793 // Use the highest version supported by both
1794 u8 deployed = std::min(client_max, our_max);
1795 // If it's lower than the lowest supported, give up.
1796 if(deployed < SER_FMT_VER_LOWEST)
1797 deployed = SER_FMT_VER_INVALID;
1799 //peer->serialization_version = deployed;
1800 getClient(peer_id)->pending_serialization_version = deployed;
1802 if(deployed == SER_FMT_VER_INVALID)
1804 actionstream<<"Server: A mismatched client tried to connect from "
1805 <<addr_s<<std::endl;
1806 infostream<<"Server: Cannot negotiate "
1807 "serialization version with peer "
1808 <<peer_id<<std::endl;
1809 SendAccessDenied(m_con, peer_id, std::wstring(
1810 L"Your client's version is not supported.\n"
1811 L"Server version is ")
1812 + narrow_to_wide(VERSION_STRING) + L"."
1818 Read and check network protocol version
1821 u16 min_net_proto_version = 0;
1822 if(datasize >= 2+1+PLAYERNAME_SIZE+PASSWORD_SIZE+2)
1823 min_net_proto_version = readU16(&data[2+1+PLAYERNAME_SIZE+PASSWORD_SIZE]);
1825 // Use same version as minimum and maximum if maximum version field
1826 // doesn't exist (backwards compatibility)
1827 u16 max_net_proto_version = min_net_proto_version;
1828 if(datasize >= 2+1+PLAYERNAME_SIZE+PASSWORD_SIZE+2+2)
1829 max_net_proto_version = readU16(&data[2+1+PLAYERNAME_SIZE+PASSWORD_SIZE+2]);
1831 // Start with client's maximum version
1832 u16 net_proto_version = max_net_proto_version;
1834 // Figure out a working version if it is possible at all
1835 if(max_net_proto_version >= SERVER_PROTOCOL_VERSION_MIN ||
1836 min_net_proto_version <= SERVER_PROTOCOL_VERSION_MAX)
1838 // If maximum is larger than our maximum, go with our maximum
1839 if(max_net_proto_version > SERVER_PROTOCOL_VERSION_MAX)
1840 net_proto_version = SERVER_PROTOCOL_VERSION_MAX;
1841 // Else go with client's maximum
1843 net_proto_version = max_net_proto_version;
1846 verbosestream<<"Server: "<<peer_id<<" Protocol version: min: "
1847 <<min_net_proto_version<<", max: "<<max_net_proto_version
1848 <<", chosen: "<<net_proto_version<<std::endl;
1850 getClient(peer_id)->net_proto_version = net_proto_version;
1852 if(net_proto_version < SERVER_PROTOCOL_VERSION_MIN ||
1853 net_proto_version > SERVER_PROTOCOL_VERSION_MAX)
1855 actionstream<<"Server: A mismatched client tried to connect from "<<addr_s
1857 SendAccessDenied(m_con, peer_id, std::wstring(
1858 L"Your client's version is not supported.\n"
1859 L"Server version is ")
1860 + narrow_to_wide(VERSION_STRING) + L",\n"
1861 + L"server's PROTOCOL_VERSION is "
1862 + narrow_to_wide(itos(SERVER_PROTOCOL_VERSION_MIN))
1864 + narrow_to_wide(itos(SERVER_PROTOCOL_VERSION_MAX))
1865 + L", client's PROTOCOL_VERSION is "
1866 + narrow_to_wide(itos(min_net_proto_version))
1868 + narrow_to_wide(itos(max_net_proto_version))
1873 if(g_settings->getBool("strict_protocol_version_checking"))
1875 if(net_proto_version != LATEST_PROTOCOL_VERSION)
1877 actionstream<<"Server: A mismatched (strict) client tried to "
1878 <<"connect from "<<addr_s<<std::endl;
1879 SendAccessDenied(m_con, peer_id, std::wstring(
1880 L"Your client's version is not supported.\n"
1881 L"Server version is ")
1882 + narrow_to_wide(VERSION_STRING) + L",\n"
1883 + L"server's PROTOCOL_VERSION (strict) is "
1884 + narrow_to_wide(itos(LATEST_PROTOCOL_VERSION))
1885 + L", client's PROTOCOL_VERSION is "
1886 + narrow_to_wide(itos(min_net_proto_version))
1888 + narrow_to_wide(itos(max_net_proto_version))
1899 char playername[PLAYERNAME_SIZE];
1900 for(u32 i=0; i<PLAYERNAME_SIZE-1; i++)
1902 playername[i] = data[3+i];
1904 playername[PLAYERNAME_SIZE-1] = 0;
1906 if(playername[0]=='\0')
1908 actionstream<<"Server: Player with an empty name "
1909 <<"tried to connect from "<<addr_s<<std::endl;
1910 SendAccessDenied(m_con, peer_id,
1915 if(string_allowed(playername, PLAYERNAME_ALLOWED_CHARS)==false)
1917 actionstream<<"Server: Player with an invalid name "
1918 <<"tried to connect from "<<addr_s<<std::endl;
1919 SendAccessDenied(m_con, peer_id,
1920 L"Name contains unallowed characters");
1924 infostream<<"Server: New connection: \""<<playername<<"\" from "
1925 <<m_con.GetPeerAddress(peer_id).serializeString()<<std::endl;
1928 char given_password[PASSWORD_SIZE];
1929 if(datasize < 2+1+PLAYERNAME_SIZE+PASSWORD_SIZE)
1931 // old version - assume blank password
1932 given_password[0] = 0;
1936 for(u32 i=0; i<PASSWORD_SIZE-1; i++)
1938 given_password[i] = data[23+i];
1940 given_password[PASSWORD_SIZE-1] = 0;
1943 if(!base64_is_valid(given_password)){
1944 infostream<<"Server: "<<playername
1945 <<" supplied invalid password hash"<<std::endl;
1946 SendAccessDenied(m_con, peer_id, L"Invalid password hash");
1950 std::string checkpwd; // Password hash to check against
1951 bool has_auth = scriptapi_get_auth(m_lua, playername, &checkpwd, NULL);
1953 // If no authentication info exists for user, create it
1955 if(!isSingleplayer() &&
1956 g_settings->getBool("disallow_empty_password") &&
1957 std::string(given_password) == ""){
1958 SendAccessDenied(m_con, peer_id, L"Empty passwords are "
1959 L"disallowed. Set a password and try again.");
1962 std::wstring raw_default_password =
1963 narrow_to_wide(g_settings->get("default_password"));
1964 std::string initial_password =
1965 translatePassword(playername, raw_default_password);
1967 // If default_password is empty, allow any initial password
1968 if (raw_default_password.length() == 0)
1969 initial_password = given_password;
1971 scriptapi_create_auth(m_lua, playername, initial_password);
1974 has_auth = scriptapi_get_auth(m_lua, playername, &checkpwd, NULL);
1977 SendAccessDenied(m_con, peer_id, L"Not allowed to login");
1981 if(given_password != checkpwd){
1982 infostream<<"Server: peer_id="<<peer_id
1983 <<": supplied invalid password for "
1984 <<playername<<std::endl;
1985 SendAccessDenied(m_con, peer_id, L"Invalid password");
1989 // Do not allow multiple players in simple singleplayer mode.
1990 // This isn't a perfect way to do it, but will suffice for now.
1991 if(m_simple_singleplayer_mode && m_clients.size() > 1){
1992 infostream<<"Server: Not allowing another client to connect in"
1993 <<" simple singleplayer mode"<<std::endl;
1994 SendAccessDenied(m_con, peer_id,
1995 L"Running in simple singleplayer mode.");
1999 // Enforce user limit.
2000 // Don't enforce for users that have some admin right
2001 if(m_clients.size() >= g_settings->getU16("max_users") &&
2002 !checkPriv(playername, "server") &&
2003 !checkPriv(playername, "ban") &&
2004 !checkPriv(playername, "privs") &&
2005 !checkPriv(playername, "password") &&
2006 playername != g_settings->get("name"))
2008 actionstream<<"Server: "<<playername<<" tried to join, but there"
2009 <<" are already max_users="
2010 <<g_settings->getU16("max_users")<<" players."<<std::endl;
2011 SendAccessDenied(m_con, peer_id, L"Too many users.");
2016 PlayerSAO *playersao = emergePlayer(playername, peer_id);
2018 // If failed, cancel
2019 if(playersao == NULL)
2021 errorstream<<"Server: peer_id="<<peer_id
2022 <<": failed to emerge player"<<std::endl;
2027 Answer with a TOCLIENT_INIT
2030 SharedBuffer<u8> reply(2+1+6+8+4);
2031 writeU16(&reply[0], TOCLIENT_INIT);
2032 writeU8(&reply[2], deployed);
2033 writeV3S16(&reply[2+1], floatToInt(playersao->getPlayer()->getPosition()+v3f(0,BS/2,0), BS));
2034 writeU64(&reply[2+1+6], m_env->getServerMap().getSeed());
2035 writeF1000(&reply[2+1+6+8], g_settings->getFloat("dedicated_server_step"));
2038 m_con.Send(peer_id, 0, reply, true);
2042 Send complete position information
2044 SendMovePlayer(peer_id);
2049 if(command == TOSERVER_INIT2)
2051 verbosestream<<"Server: Got TOSERVER_INIT2 from "
2052 <<peer_id<<std::endl;
2054 Player *player = m_env->getPlayer(peer_id);
2056 verbosestream<<"Server: TOSERVER_INIT2: "
2057 <<"Player not found; ignoring."<<std::endl;
2061 RemoteClient *client = getClient(peer_id);
2062 client->serialization_version =
2063 getClient(peer_id)->pending_serialization_version;
2066 Send some initialization data
2069 infostream<<"Server: Sending content to "
2070 <<getPlayerName(peer_id)<<std::endl;
2072 // Send player movement settings
2073 SendMovement(m_con, peer_id);
2075 // Send item definitions
2076 SendItemDef(m_con, peer_id, m_itemdef, client->net_proto_version);
2078 // Send node definitions
2079 SendNodeDef(m_con, peer_id, m_nodedef, client->net_proto_version);
2081 // Send media announcement
2082 sendMediaAnnouncement(peer_id);
2085 SendPlayerPrivileges(peer_id);
2087 // Send inventory formspec
2088 SendPlayerInventoryFormspec(peer_id);
2091 UpdateCrafting(peer_id);
2092 SendInventory(peer_id);
2095 if(g_settings->getBool("enable_damage"))
2096 SendPlayerHP(peer_id);
2098 // Send detached inventories
2099 sendDetachedInventories(peer_id);
2101 // Show death screen if necessary
2103 SendDeathscreen(m_con, peer_id, false, v3f(0,0,0));
2107 SharedBuffer<u8> data = makePacket_TOCLIENT_TIME_OF_DAY(
2108 m_env->getTimeOfDay(), g_settings->getFloat("time_speed"));
2109 m_con.Send(peer_id, 0, data, true);
2112 // Note things in chat if not in simple singleplayer mode
2113 if(!m_simple_singleplayer_mode)
2115 // Send information about server to player in chat
2116 SendChatMessage(peer_id, getStatusString());
2118 // Send information about joining in chat
2120 std::wstring name = L"unknown";
2121 Player *player = m_env->getPlayer(peer_id);
2123 name = narrow_to_wide(player->getName());
2125 std::wstring message;
2128 message += L" joined the game.";
2129 BroadcastChatMessage(message);
2133 // Warnings about protocol version can be issued here
2134 if(getClient(peer_id)->net_proto_version < LATEST_PROTOCOL_VERSION)
2136 SendChatMessage(peer_id, L"# Server: WARNING: YOUR CLIENT'S "
2137 L"VERSION MAY NOT BE FULLY COMPATIBLE WITH THIS SERVER!");
2144 std::ostringstream os(std::ios_base::binary);
2145 for(std::map<u16, RemoteClient*>::iterator
2146 i = m_clients.begin();
2147 i != m_clients.end(); ++i)
2149 RemoteClient *client = i->second;
2150 assert(client->peer_id == i->first);
2151 if(client->serialization_version == SER_FMT_VER_INVALID)
2154 Player *player = m_env->getPlayer(client->peer_id);
2157 // Get name of player
2158 os<<player->getName()<<" ";
2161 actionstream<<player->getName()<<" joins game. List of players: "
2162 <<os.str()<<std::endl;
2168 if(peer_ser_ver == SER_FMT_VER_INVALID)
2170 infostream<<"Server::ProcessData(): Cancelling: Peer"
2171 " serialization format invalid or not initialized."
2172 " Skipping incoming command="<<command<<std::endl;
2176 Player *player = m_env->getPlayer(peer_id);
2178 infostream<<"Server::ProcessData(): Cancelling: "
2179 "No player for peer_id="<<peer_id
2184 PlayerSAO *playersao = player->getPlayerSAO();
2185 if(playersao == NULL){
2186 infostream<<"Server::ProcessData(): Cancelling: "
2187 "No player object for peer_id="<<peer_id
2192 if(command == TOSERVER_PLAYERPOS)
2194 if(datasize < 2+12+12+4+4)
2198 v3s32 ps = readV3S32(&data[start+2]);
2199 v3s32 ss = readV3S32(&data[start+2+12]);
2200 f32 pitch = (f32)readS32(&data[2+12+12]) / 100.0;
2201 f32 yaw = (f32)readS32(&data[2+12+12+4]) / 100.0;
2203 if(datasize >= 2+12+12+4+4+4)
2204 keyPressed = (u32)readU32(&data[2+12+12+4+4]);
2205 v3f position((f32)ps.X/100., (f32)ps.Y/100., (f32)ps.Z/100.);
2206 v3f speed((f32)ss.X/100., (f32)ss.Y/100., (f32)ss.Z/100.);
2207 pitch = wrapDegrees(pitch);
2208 yaw = wrapDegrees(yaw);
2210 player->setPosition(position);
2211 player->setSpeed(speed);
2212 player->setPitch(pitch);
2213 player->setYaw(yaw);
2214 player->keyPressed=keyPressed;
2215 player->control.up = (bool)(keyPressed&1);
2216 player->control.down = (bool)(keyPressed&2);
2217 player->control.left = (bool)(keyPressed&4);
2218 player->control.right = (bool)(keyPressed&8);
2219 player->control.jump = (bool)(keyPressed&16);
2220 player->control.aux1 = (bool)(keyPressed&32);
2221 player->control.sneak = (bool)(keyPressed&64);
2222 player->control.LMB = (bool)(keyPressed&128);
2223 player->control.RMB = (bool)(keyPressed&256);
2225 /*infostream<<"Server::ProcessData(): Moved player "<<peer_id<<" to "
2226 <<"("<<position.X<<","<<position.Y<<","<<position.Z<<")"
2227 <<" pitch="<<pitch<<" yaw="<<yaw<<std::endl;*/
2229 else if(command == TOSERVER_GOTBLOCKS)
2242 u16 count = data[2];
2243 for(u16 i=0; i<count; i++)
2245 if((s16)datasize < 2+1+(i+1)*6)
2246 throw con::InvalidIncomingDataException
2247 ("GOTBLOCKS length is too short");
2248 v3s16 p = readV3S16(&data[2+1+i*6]);
2249 /*infostream<<"Server: GOTBLOCKS ("
2250 <<p.X<<","<<p.Y<<","<<p.Z<<")"<<std::endl;*/
2251 RemoteClient *client = getClient(peer_id);
2252 client->GotBlock(p);
2255 else if(command == TOSERVER_DELETEDBLOCKS)
2268 u16 count = data[2];
2269 for(u16 i=0; i<count; i++)
2271 if((s16)datasize < 2+1+(i+1)*6)
2272 throw con::InvalidIncomingDataException
2273 ("DELETEDBLOCKS length is too short");
2274 v3s16 p = readV3S16(&data[2+1+i*6]);
2275 /*infostream<<"Server: DELETEDBLOCKS ("
2276 <<p.X<<","<<p.Y<<","<<p.Z<<")"<<std::endl;*/
2277 RemoteClient *client = getClient(peer_id);
2278 client->SetBlockNotSent(p);
2281 else if(command == TOSERVER_CLICK_OBJECT)
2283 infostream<<"Server: CLICK_OBJECT not supported anymore"<<std::endl;
2286 else if(command == TOSERVER_CLICK_ACTIVEOBJECT)
2288 infostream<<"Server: CLICK_ACTIVEOBJECT not supported anymore"<<std::endl;
2291 else if(command == TOSERVER_GROUND_ACTION)
2293 infostream<<"Server: GROUND_ACTION not supported anymore"<<std::endl;
2297 else if(command == TOSERVER_RELEASE)
2299 infostream<<"Server: RELEASE not supported anymore"<<std::endl;
2302 else if(command == TOSERVER_SIGNTEXT)
2304 infostream<<"Server: SIGNTEXT not supported anymore"
2308 else if(command == TOSERVER_SIGNNODETEXT)
2310 infostream<<"Server: SIGNNODETEXT not supported anymore"
2314 else if(command == TOSERVER_INVENTORY_ACTION)
2316 // Strip command and create a stream
2317 std::string datastring((char*)&data[2], datasize-2);
2318 verbosestream<<"TOSERVER_INVENTORY_ACTION: data="<<datastring<<std::endl;
2319 std::istringstream is(datastring, std::ios_base::binary);
2321 InventoryAction *a = InventoryAction::deSerialize(is);
2324 infostream<<"TOSERVER_INVENTORY_ACTION: "
2325 <<"InventoryAction::deSerialize() returned NULL"
2330 // If something goes wrong, this player is to blame
2331 RollbackScopeActor rollback_scope(m_rollback,
2332 std::string("player:")+player->getName());
2335 Note: Always set inventory not sent, to repair cases
2336 where the client made a bad prediction.
2340 Handle restrictions and special cases of the move action
2342 if(a->getType() == IACTION_MOVE)
2344 IMoveAction *ma = (IMoveAction*)a;
2346 ma->from_inv.applyCurrentPlayer(player->getName());
2347 ma->to_inv.applyCurrentPlayer(player->getName());
2349 setInventoryModified(ma->from_inv);
2350 setInventoryModified(ma->to_inv);
2352 bool from_inv_is_current_player =
2353 (ma->from_inv.type == InventoryLocation::PLAYER) &&
2354 (ma->from_inv.name == player->getName());
2356 bool to_inv_is_current_player =
2357 (ma->to_inv.type == InventoryLocation::PLAYER) &&
2358 (ma->to_inv.name == player->getName());
2361 Disable moving items out of craftpreview
2363 if(ma->from_list == "craftpreview")
2365 infostream<<"Ignoring IMoveAction from "
2366 <<(ma->from_inv.dump())<<":"<<ma->from_list
2367 <<" to "<<(ma->to_inv.dump())<<":"<<ma->to_list
2368 <<" because src is "<<ma->from_list<<std::endl;
2374 Disable moving items into craftresult and craftpreview
2376 if(ma->to_list == "craftpreview" || ma->to_list == "craftresult")
2378 infostream<<"Ignoring IMoveAction from "
2379 <<(ma->from_inv.dump())<<":"<<ma->from_list
2380 <<" to "<<(ma->to_inv.dump())<<":"<<ma->to_list
2381 <<" because dst is "<<ma->to_list<<std::endl;
2386 // Disallow moving items in elsewhere than player's inventory
2387 // if not allowed to interact
2388 if(!checkPriv(player->getName(), "interact") &&
2389 (!from_inv_is_current_player ||
2390 !to_inv_is_current_player))
2392 infostream<<"Cannot move outside of player's inventory: "
2393 <<"No interact privilege"<<std::endl;
2399 Handle restrictions and special cases of the drop action
2401 else if(a->getType() == IACTION_DROP)
2403 IDropAction *da = (IDropAction*)a;
2405 da->from_inv.applyCurrentPlayer(player->getName());
2407 setInventoryModified(da->from_inv);
2409 // Disallow dropping items if not allowed to interact
2410 if(!checkPriv(player->getName(), "interact"))
2417 Handle restrictions and special cases of the craft action
2419 else if(a->getType() == IACTION_CRAFT)
2421 ICraftAction *ca = (ICraftAction*)a;
2423 ca->craft_inv.applyCurrentPlayer(player->getName());
2425 setInventoryModified(ca->craft_inv);
2427 //bool craft_inv_is_current_player =
2428 // (ca->craft_inv.type == InventoryLocation::PLAYER) &&
2429 // (ca->craft_inv.name == player->getName());
2431 // Disallow crafting if not allowed to interact
2432 if(!checkPriv(player->getName(), "interact"))
2434 infostream<<"Cannot craft: "
2435 <<"No interact privilege"<<std::endl;
2442 a->apply(this, playersao, this);
2446 else if(command == TOSERVER_CHAT_MESSAGE)
2454 std::string datastring((char*)&data[2], datasize-2);
2455 std::istringstream is(datastring, std::ios_base::binary);
2458 is.read((char*)buf, 2);
2459 u16 len = readU16(buf);
2461 std::wstring message;
2462 for(u16 i=0; i<len; i++)
2464 is.read((char*)buf, 2);
2465 message += (wchar_t)readU16(buf);
2468 // If something goes wrong, this player is to blame
2469 RollbackScopeActor rollback_scope(m_rollback,
2470 std::string("player:")+player->getName());
2472 // Get player name of this client
2473 std::wstring name = narrow_to_wide(player->getName());
2476 bool ate = scriptapi_on_chat_message(m_lua, player->getName(),
2477 wide_to_narrow(message));
2478 // If script ate the message, don't proceed
2482 // Line to send to players
2484 // Whether to send to the player that sent the line
2485 bool send_to_sender = false;
2486 // Whether to send to other players
2487 bool send_to_others = false;
2489 // Commands are implemented in Lua, so only catch invalid
2490 // commands that were not "eaten" and send an error back
2491 if(message[0] == L'/')
2493 message = message.substr(1);
2494 send_to_sender = true;
2495 if(message.length() == 0)
2496 line += L"-!- Empty command";
2498 line += L"-!- Invalid command: " + str_split(message, L' ')[0];
2502 if(checkPriv(player->getName(), "shout")){
2507 send_to_others = true;
2509 line += L"-!- You don't have permission to shout.";
2510 send_to_sender = true;
2517 actionstream<<"CHAT: "<<wide_to_narrow(line)<<std::endl;
2520 Send the message to clients
2522 for(std::map<u16, RemoteClient*>::iterator
2523 i = m_clients.begin();
2524 i != m_clients.end(); ++i)
2526 // Get client and check that it is valid
2527 RemoteClient *client = i->second;
2528 assert(client->peer_id == i->first);
2529 if(client->serialization_version == SER_FMT_VER_INVALID)
2533 bool sender_selected = (peer_id == client->peer_id);
2534 if(sender_selected == true && send_to_sender == false)
2536 if(sender_selected == false && send_to_others == false)
2539 SendChatMessage(client->peer_id, line);
2543 else if(command == TOSERVER_DAMAGE)
2545 std::string datastring((char*)&data[2], datasize-2);
2546 std::istringstream is(datastring, std::ios_base::binary);
2547 u8 damage = readU8(is);
2549 if(g_settings->getBool("enable_damage"))
2551 actionstream<<player->getName()<<" damaged by "
2552 <<(int)damage<<" hp at "<<PP(player->getPosition()/BS)
2555 playersao->setHP(playersao->getHP() - damage);
2557 if(playersao->getHP() == 0 && playersao->m_hp_not_sent)
2560 if(playersao->m_hp_not_sent)
2561 SendPlayerHP(peer_id);
2564 else if(command == TOSERVER_PASSWORD)
2567 [0] u16 TOSERVER_PASSWORD
2568 [2] u8[28] old password
2569 [30] u8[28] new password
2572 if(datasize != 2+PASSWORD_SIZE*2)
2574 /*char password[PASSWORD_SIZE];
2575 for(u32 i=0; i<PASSWORD_SIZE-1; i++)
2576 password[i] = data[2+i];
2577 password[PASSWORD_SIZE-1] = 0;*/
2579 for(u32 i=0; i<PASSWORD_SIZE-1; i++)
2587 for(u32 i=0; i<PASSWORD_SIZE-1; i++)
2589 char c = data[2+PASSWORD_SIZE+i];
2595 if(!base64_is_valid(newpwd)){
2596 infostream<<"Server: "<<player->getName()<<" supplied invalid password hash"<<std::endl;
2597 // Wrong old password supplied!!
2598 SendChatMessage(peer_id, L"Invalid new password hash supplied. Password NOT changed.");
2602 infostream<<"Server: Client requests a password change from "
2603 <<"'"<<oldpwd<<"' to '"<<newpwd<<"'"<<std::endl;
2605 std::string playername = player->getName();
2607 std::string checkpwd;
2608 scriptapi_get_auth(m_lua, playername, &checkpwd, NULL);
2610 if(oldpwd != checkpwd)
2612 infostream<<"Server: invalid old password"<<std::endl;
2613 // Wrong old password supplied!!
2614 SendChatMessage(peer_id, L"Invalid old password supplied. Password NOT changed.");
2618 bool success = scriptapi_set_password(m_lua, playername, newpwd);
2620 actionstream<<player->getName()<<" changes password"<<std::endl;
2621 SendChatMessage(peer_id, L"Password change successful.");
2623 actionstream<<player->getName()<<" tries to change password but "
2624 <<"it fails"<<std::endl;
2625 SendChatMessage(peer_id, L"Password change failed or inavailable.");
2628 else if(command == TOSERVER_PLAYERITEM)
2633 u16 item = readU16(&data[2]);
2634 playersao->setWieldIndex(item);
2636 else if(command == TOSERVER_RESPAWN)
2638 if(player->hp != 0 || !g_settings->getBool("enable_damage"))
2641 RespawnPlayer(peer_id);
2643 actionstream<<player->getName()<<" respawns at "
2644 <<PP(player->getPosition()/BS)<<std::endl;
2646 // ActiveObject is added to environment in AsyncRunStep after
2647 // the previous addition has been succesfully removed
2649 else if(command == TOSERVER_REQUEST_MEDIA) {
2650 std::string datastring((char*)&data[2], datasize-2);
2651 std::istringstream is(datastring, std::ios_base::binary);
2653 std::list<MediaRequest> tosend;
2654 u16 numfiles = readU16(is);
2656 infostream<<"Sending "<<numfiles<<" files to "
2657 <<getPlayerName(peer_id)<<std::endl;
2658 verbosestream<<"TOSERVER_REQUEST_MEDIA: "<<std::endl;
2660 for(int i = 0; i < numfiles; i++) {
2661 std::string name = deSerializeString(is);
2662 tosend.push_back(MediaRequest(name));
2663 verbosestream<<"TOSERVER_REQUEST_MEDIA: requested file "
2667 sendRequestedMedia(peer_id, tosend);
2669 // Now the client should know about everything
2670 // (definitions and files)
2671 getClient(peer_id)->definitions_sent = true;
2673 else if(command == TOSERVER_RECEIVED_MEDIA) {
2674 getClient(peer_id)->definitions_sent = true;
2676 else if(command == TOSERVER_INTERACT)
2678 std::string datastring((char*)&data[2], datasize-2);
2679 std::istringstream is(datastring, std::ios_base::binary);
2685 [5] u32 length of the next item
2686 [9] serialized PointedThing
2688 0: start digging (from undersurface) or use
2689 1: stop digging (all parameters ignored)
2690 2: digging completed
2691 3: place block or item (to abovesurface)
2694 u8 action = readU8(is);
2695 u16 item_i = readU16(is);
2696 std::istringstream tmp_is(deSerializeLongString(is), std::ios::binary);
2697 PointedThing pointed;
2698 pointed.deSerialize(tmp_is);
2700 verbosestream<<"TOSERVER_INTERACT: action="<<(int)action<<", item="
2701 <<item_i<<", pointed="<<pointed.dump()<<std::endl;
2705 verbosestream<<"TOSERVER_INTERACT: "<<player->getName()
2706 <<" tried to interact, but is dead!"<<std::endl;
2710 v3f player_pos = playersao->getLastGoodPosition();
2712 // Update wielded item
2713 playersao->setWieldIndex(item_i);
2715 // Get pointed to node (undefined if not POINTEDTYPE_NODE)
2716 v3s16 p_under = pointed.node_undersurface;
2717 v3s16 p_above = pointed.node_abovesurface;
2719 // Get pointed to object (NULL if not POINTEDTYPE_OBJECT)
2720 ServerActiveObject *pointed_object = NULL;
2721 if(pointed.type == POINTEDTHING_OBJECT)
2723 pointed_object = m_env->getActiveObject(pointed.object_id);
2724 if(pointed_object == NULL)
2726 verbosestream<<"TOSERVER_INTERACT: "
2727 "pointed object is NULL"<<std::endl;
2733 v3f pointed_pos_under = player_pos;
2734 v3f pointed_pos_above = player_pos;
2735 if(pointed.type == POINTEDTHING_NODE)
2737 pointed_pos_under = intToFloat(p_under, BS);
2738 pointed_pos_above = intToFloat(p_above, BS);
2740 else if(pointed.type == POINTEDTHING_OBJECT)
2742 pointed_pos_under = pointed_object->getBasePosition();
2743 pointed_pos_above = pointed_pos_under;
2747 Check that target is reasonably close
2748 (only when digging or placing things)
2750 if(action == 0 || action == 2 || action == 3)
2752 float d = player_pos.getDistanceFrom(pointed_pos_under);
2753 float max_d = BS * 14; // Just some large enough value
2755 actionstream<<"Player "<<player->getName()
2756 <<" tried to access "<<pointed.dump()
2758 <<"d="<<d<<", max_d="<<max_d
2759 <<". ignoring."<<std::endl;
2760 // Re-send block to revert change on client-side
2761 RemoteClient *client = getClient(peer_id);
2762 v3s16 blockpos = getNodeBlockPos(floatToInt(pointed_pos_under, BS));
2763 client->SetBlockNotSent(blockpos);
2770 Make sure the player is allowed to do it
2772 if(!checkPriv(player->getName(), "interact"))
2774 actionstream<<player->getName()<<" attempted to interact with "
2775 <<pointed.dump()<<" without 'interact' privilege"
2777 // Re-send block to revert change on client-side
2778 RemoteClient *client = getClient(peer_id);
2779 // Digging completed -> under
2781 v3s16 blockpos = getNodeBlockPos(floatToInt(pointed_pos_under, BS));
2782 client->SetBlockNotSent(blockpos);
2784 // Placement -> above
2786 v3s16 blockpos = getNodeBlockPos(floatToInt(pointed_pos_above, BS));
2787 client->SetBlockNotSent(blockpos);
2793 If something goes wrong, this player is to blame
2795 RollbackScopeActor rollback_scope(m_rollback,
2796 std::string("player:")+player->getName());
2799 0: start digging or punch object
2803 if(pointed.type == POINTEDTHING_NODE)
2806 NOTE: This can be used in the future to check if
2807 somebody is cheating, by checking the timing.
2809 MapNode n(CONTENT_IGNORE);
2812 n = m_env->getMap().getNode(p_under);
2814 catch(InvalidPositionException &e)
2816 infostream<<"Server: Not punching: Node not found."
2817 <<" Adding block to emerge queue."
2819 m_emerge->enqueueBlockEmerge(peer_id, getNodeBlockPos(p_above), false);
2821 if(n.getContent() != CONTENT_IGNORE)
2822 scriptapi_node_on_punch(m_lua, p_under, n, playersao);
2824 playersao->noCheatDigStart(p_under);
2826 else if(pointed.type == POINTEDTHING_OBJECT)
2828 // Skip if object has been removed
2829 if(pointed_object->m_removed)
2832 actionstream<<player->getName()<<" punches object "
2833 <<pointed.object_id<<": "
2834 <<pointed_object->getDescription()<<std::endl;
2836 ItemStack punchitem = playersao->getWieldedItem();
2837 ToolCapabilities toolcap =
2838 punchitem.getToolCapabilities(m_itemdef);
2839 v3f dir = (pointed_object->getBasePosition() -
2840 (player->getPosition() + player->getEyeOffset())
2842 float time_from_last_punch =
2843 playersao->resetTimeFromLastPunch();
2844 pointed_object->punch(dir, &toolcap, playersao,
2845 time_from_last_punch);
2853 else if(action == 1)
2858 2: Digging completed
2860 else if(action == 2)
2862 // Only digging of nodes
2863 if(pointed.type == POINTEDTHING_NODE)
2865 MapNode n(CONTENT_IGNORE);
2868 n = m_env->getMap().getNode(p_under);
2870 catch(InvalidPositionException &e)
2872 infostream<<"Server: Not finishing digging: Node not found."
2873 <<" Adding block to emerge queue."
2875 m_emerge->enqueueBlockEmerge(peer_id, getNodeBlockPos(p_above), false);
2878 /* Cheat prevention */
2879 bool is_valid_dig = true;
2880 if(!isSingleplayer() && !g_settings->getBool("disable_anticheat"))
2882 v3s16 nocheat_p = playersao->getNoCheatDigPos();
2883 float nocheat_t = playersao->getNoCheatDigTime();
2884 playersao->noCheatDigEnd();
2885 // If player didn't start digging this, ignore dig
2886 if(nocheat_p != p_under){
2887 infostream<<"Server: NoCheat: "<<player->getName()
2888 <<" started digging "
2889 <<PP(nocheat_p)<<" and completed digging "
2890 <<PP(p_under)<<"; not digging."<<std::endl;
2891 is_valid_dig = false;
2893 // Get player's wielded item
2894 ItemStack playeritem;
2895 InventoryList *mlist = playersao->getInventory()->getList("main");
2897 playeritem = mlist->getItem(playersao->getWieldIndex());
2898 ToolCapabilities playeritem_toolcap =
2899 playeritem.getToolCapabilities(m_itemdef);
2900 // Get diggability and expected digging time
2901 DigParams params = getDigParams(m_nodedef->get(n).groups,
2902 &playeritem_toolcap);
2903 // If can't dig, try hand
2904 if(!params.diggable){
2905 const ItemDefinition &hand = m_itemdef->get("");
2906 const ToolCapabilities *tp = hand.tool_capabilities;
2908 params = getDigParams(m_nodedef->get(n).groups, tp);
2910 // If can't dig, ignore dig
2911 if(!params.diggable){
2912 infostream<<"Server: NoCheat: "<<player->getName()
2913 <<" completed digging "<<PP(p_under)
2914 <<", which is not diggable with tool. not digging."
2916 is_valid_dig = false;
2918 // If time is considerably too short, ignore dig
2919 // Check time only for medium and slow timed digs
2920 if(params.diggable && params.time > 0.3 && nocheat_t < 0.5 * params.time){
2921 infostream<<"Server: NoCheat: "<<player->getName()
2922 <<" completed digging "
2923 <<PP(p_under)<<" in "<<nocheat_t<<"s; expected "
2924 <<params.time<<"s; not digging."<<std::endl;
2925 is_valid_dig = false;
2929 /* Actually dig node */
2931 if(is_valid_dig && n.getContent() != CONTENT_IGNORE)
2932 scriptapi_node_on_dig(m_lua, p_under, n, playersao);
2934 // Send unusual result (that is, node not being removed)
2935 if(m_env->getMap().getNodeNoEx(p_under).getContent() != CONTENT_AIR)
2937 // Re-send block to revert change on client-side
2938 RemoteClient *client = getClient(peer_id);
2939 v3s16 blockpos = getNodeBlockPos(floatToInt(pointed_pos_under, BS));
2940 client->SetBlockNotSent(blockpos);
2946 3: place block or right-click object
2948 else if(action == 3)
2950 ItemStack item = playersao->getWieldedItem();
2952 // Reset build time counter
2953 if(pointed.type == POINTEDTHING_NODE &&
2954 item.getDefinition(m_itemdef).type == ITEM_NODE)
2955 getClient(peer_id)->m_time_from_building = 0.0;
2957 if(pointed.type == POINTEDTHING_OBJECT)
2959 // Right click object
2961 // Skip if object has been removed
2962 if(pointed_object->m_removed)
2965 actionstream<<player->getName()<<" right-clicks object "
2966 <<pointed.object_id<<": "
2967 <<pointed_object->getDescription()<<std::endl;
2970 pointed_object->rightClick(playersao);
2972 else if(scriptapi_item_on_place(m_lua,
2973 item, playersao, pointed))
2975 // Placement was handled in lua
2977 // Apply returned ItemStack
2978 playersao->setWieldedItem(item);
2981 // If item has node placement prediction, always send the above
2982 // node to make sure the client knows what exactly happened
2983 if(item.getDefinition(m_itemdef).node_placement_prediction != ""){
2984 RemoteClient *client = getClient(peer_id);
2985 v3s16 blockpos = getNodeBlockPos(floatToInt(pointed_pos_above, BS));
2986 client->SetBlockNotSent(blockpos);
2993 else if(action == 4)
2995 ItemStack item = playersao->getWieldedItem();
2997 actionstream<<player->getName()<<" uses "<<item.name
2998 <<", pointing at "<<pointed.dump()<<std::endl;
3000 if(scriptapi_item_on_use(m_lua,
3001 item, playersao, pointed))
3003 // Apply returned ItemStack
3004 playersao->setWieldedItem(item);
3011 Catch invalid actions
3015 infostream<<"WARNING: Server: Invalid action "
3016 <<action<<std::endl;
3019 else if(command == TOSERVER_REMOVED_SOUNDS)
3021 std::string datastring((char*)&data[2], datasize-2);
3022 std::istringstream is(datastring, std::ios_base::binary);
3024 int num = readU16(is);
3025 for(int k=0; k<num; k++){
3026 s32 id = readS32(is);
3027 std::map<s32, ServerPlayingSound>::iterator i =
3028 m_playing_sounds.find(id);
3029 if(i == m_playing_sounds.end())
3031 ServerPlayingSound &psound = i->second;
3032 psound.clients.erase(peer_id);
3033 if(psound.clients.size() == 0)
3034 m_playing_sounds.erase(i++);
3037 else if(command == TOSERVER_NODEMETA_FIELDS)
3039 std::string datastring((char*)&data[2], datasize-2);
3040 std::istringstream is(datastring, std::ios_base::binary);
3042 v3s16 p = readV3S16(is);
3043 std::string formname = deSerializeString(is);
3044 int num = readU16(is);
3045 std::map<std::string, std::string> fields;
3046 for(int k=0; k<num; k++){
3047 std::string fieldname = deSerializeString(is);
3048 std::string fieldvalue = deSerializeLongString(is);
3049 fields[fieldname] = fieldvalue;
3052 // If something goes wrong, this player is to blame
3053 RollbackScopeActor rollback_scope(m_rollback,
3054 std::string("player:")+player->getName());
3056 // Check the target node for rollback data; leave others unnoticed
3057 RollbackNode rn_old(&m_env->getMap(), p, this);
3059 scriptapi_node_on_receive_fields(m_lua, p, formname, fields,
3062 // Report rollback data
3063 RollbackNode rn_new(&m_env->getMap(), p, this);
3064 if(rollback() && rn_new != rn_old){
3065 RollbackAction action;
3066 action.setSetNode(p, rn_old, rn_new);
3067 rollback()->reportAction(action);
3070 else if(command == TOSERVER_INVENTORY_FIELDS)
3072 std::string datastring((char*)&data[2], datasize-2);
3073 std::istringstream is(datastring, std::ios_base::binary);
3075 std::string formname = deSerializeString(is);
3076 int num = readU16(is);
3077 std::map<std::string, std::string> fields;
3078 for(int k=0; k<num; k++){
3079 std::string fieldname = deSerializeString(is);
3080 std::string fieldvalue = deSerializeLongString(is);
3081 fields[fieldname] = fieldvalue;
3084 scriptapi_on_player_receive_fields(m_lua, playersao, formname, fields);
3088 infostream<<"Server::ProcessData(): Ignoring "
3089 "unknown command "<<command<<std::endl;
3093 catch(SendFailedException &e)
3095 errorstream<<"Server::ProcessData(): SendFailedException: "
3101 void Server::onMapEditEvent(MapEditEvent *event)
3103 //infostream<<"Server::onMapEditEvent()"<<std::endl;
3104 if(m_ignore_map_edit_events)
3106 if(m_ignore_map_edit_events_area.contains(event->getArea()))
3108 MapEditEvent *e = event->clone();
3109 m_unsent_map_edit_queue.push_back(e);
3112 Inventory* Server::getInventory(const InventoryLocation &loc)
3115 case InventoryLocation::UNDEFINED:
3118 case InventoryLocation::CURRENT_PLAYER:
3121 case InventoryLocation::PLAYER:
3123 Player *player = m_env->getPlayer(loc.name.c_str());
3126 PlayerSAO *playersao = player->getPlayerSAO();
3129 return playersao->getInventory();
3132 case InventoryLocation::NODEMETA:
3134 NodeMetadata *meta = m_env->getMap().getNodeMetadata(loc.p);
3137 return meta->getInventory();
3140 case InventoryLocation::DETACHED:
3142 if(m_detached_inventories.count(loc.name) == 0)
3144 return m_detached_inventories[loc.name];
3152 void Server::setInventoryModified(const InventoryLocation &loc)
3155 case InventoryLocation::UNDEFINED:
3158 case InventoryLocation::PLAYER:
3160 Player *player = m_env->getPlayer(loc.name.c_str());
3163 PlayerSAO *playersao = player->getPlayerSAO();
3166 playersao->m_inventory_not_sent = true;
3167 playersao->m_wielded_item_not_sent = true;
3170 case InventoryLocation::NODEMETA:
3172 v3s16 blockpos = getNodeBlockPos(loc.p);
3174 MapBlock *block = m_env->getMap().getBlockNoCreateNoEx(blockpos);
3176 block->raiseModified(MOD_STATE_WRITE_NEEDED);
3178 setBlockNotSent(blockpos);
3181 case InventoryLocation::DETACHED:
3183 sendDetachedInventoryToAll(loc.name);
3191 std::list<PlayerInfo> Server::getPlayerInfo()
3193 DSTACK(__FUNCTION_NAME);
3194 JMutexAutoLock envlock(m_env_mutex);
3195 JMutexAutoLock conlock(m_con_mutex);
3197 std::list<PlayerInfo> list;
3199 std::list<Player*> players = m_env->getPlayers();
3201 std::list<Player*>::iterator i;
3202 for(i = players.begin();
3203 i != players.end(); ++i)
3207 Player *player = *i;
3210 // Copy info from connection to info struct
3211 info.id = player->peer_id;
3212 info.address = m_con.GetPeerAddress(player->peer_id);
3213 info.avg_rtt = m_con.GetPeerAvgRTT(player->peer_id);
3215 catch(con::PeerNotFoundException &e)
3217 // Set dummy peer info
3219 info.address = Address(0,0,0,0,0);
3223 snprintf(info.name, PLAYERNAME_SIZE, "%s", player->getName());
3224 info.position = player->getPosition();
3226 list.push_back(info);
3233 void Server::peerAdded(con::Peer *peer)
3235 DSTACK(__FUNCTION_NAME);
3236 verbosestream<<"Server::peerAdded(): peer->id="
3237 <<peer->id<<std::endl;
3240 c.type = PEER_ADDED;
3241 c.peer_id = peer->id;
3243 m_peer_change_queue.push_back(c);
3246 void Server::deletingPeer(con::Peer *peer, bool timeout)
3248 DSTACK(__FUNCTION_NAME);
3249 verbosestream<<"Server::deletingPeer(): peer->id="
3250 <<peer->id<<", timeout="<<timeout<<std::endl;
3253 c.type = PEER_REMOVED;
3254 c.peer_id = peer->id;
3255 c.timeout = timeout;
3256 m_peer_change_queue.push_back(c);
3263 void Server::SendMovement(con::Connection &con, u16 peer_id)
3265 DSTACK(__FUNCTION_NAME);
3266 std::ostringstream os(std::ios_base::binary);
3268 writeU16(os, TOCLIENT_MOVEMENT);
3269 writeF1000(os, g_settings->getFloat("movement_acceleration_default"));
3270 writeF1000(os, g_settings->getFloat("movement_acceleration_air"));
3271 writeF1000(os, g_settings->getFloat("movement_acceleration_fast"));
3272 writeF1000(os, g_settings->getFloat("movement_speed_walk"));
3273 writeF1000(os, g_settings->getFloat("movement_speed_crouch"));
3274 writeF1000(os, g_settings->getFloat("movement_speed_fast"));
3275 writeF1000(os, g_settings->getFloat("movement_speed_climb"));
3276 writeF1000(os, g_settings->getFloat("movement_speed_jump"));
3277 writeF1000(os, g_settings->getFloat("movement_liquid_fluidity"));
3278 writeF1000(os, g_settings->getFloat("movement_liquid_fluidity_smooth"));
3279 writeF1000(os, g_settings->getFloat("movement_liquid_sink"));
3280 writeF1000(os, g_settings->getFloat("movement_gravity"));
3283 std::string s = os.str();
3284 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3286 con.Send(peer_id, 0, data, true);
3289 void Server::SendHP(con::Connection &con, u16 peer_id, u8 hp)
3291 DSTACK(__FUNCTION_NAME);
3292 std::ostringstream os(std::ios_base::binary);
3294 writeU16(os, TOCLIENT_HP);
3298 std::string s = os.str();
3299 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3301 con.Send(peer_id, 0, data, true);
3304 void Server::SendAccessDenied(con::Connection &con, u16 peer_id,
3305 const std::wstring &reason)
3307 DSTACK(__FUNCTION_NAME);
3308 std::ostringstream os(std::ios_base::binary);
3310 writeU16(os, TOCLIENT_ACCESS_DENIED);
3311 os<<serializeWideString(reason);
3314 std::string s = os.str();
3315 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3317 con.Send(peer_id, 0, data, true);
3320 void Server::SendDeathscreen(con::Connection &con, u16 peer_id,
3321 bool set_camera_point_target, v3f camera_point_target)
3323 DSTACK(__FUNCTION_NAME);
3324 std::ostringstream os(std::ios_base::binary);
3326 writeU16(os, TOCLIENT_DEATHSCREEN);
3327 writeU8(os, set_camera_point_target);
3328 writeV3F1000(os, camera_point_target);
3331 std::string s = os.str();
3332 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3334 con.Send(peer_id, 0, data, true);
3337 void Server::SendItemDef(con::Connection &con, u16 peer_id,
3338 IItemDefManager *itemdef, u16 protocol_version)
3340 DSTACK(__FUNCTION_NAME);
3341 std::ostringstream os(std::ios_base::binary);
3345 u32 length of the next item
3346 zlib-compressed serialized ItemDefManager
3348 writeU16(os, TOCLIENT_ITEMDEF);
3349 std::ostringstream tmp_os(std::ios::binary);
3350 itemdef->serialize(tmp_os, protocol_version);
3351 std::ostringstream tmp_os2(std::ios::binary);
3352 compressZlib(tmp_os.str(), tmp_os2);
3353 os<<serializeLongString(tmp_os2.str());
3356 std::string s = os.str();
3357 verbosestream<<"Server: Sending item definitions to id("<<peer_id
3358 <<"): size="<<s.size()<<std::endl;
3359 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3361 con.Send(peer_id, 0, data, true);
3364 void Server::SendNodeDef(con::Connection &con, u16 peer_id,
3365 INodeDefManager *nodedef, u16 protocol_version)
3367 DSTACK(__FUNCTION_NAME);
3368 std::ostringstream os(std::ios_base::binary);
3372 u32 length of the next item
3373 zlib-compressed serialized NodeDefManager
3375 writeU16(os, TOCLIENT_NODEDEF);
3376 std::ostringstream tmp_os(std::ios::binary);
3377 nodedef->serialize(tmp_os, protocol_version);
3378 std::ostringstream tmp_os2(std::ios::binary);
3379 compressZlib(tmp_os.str(), tmp_os2);
3380 os<<serializeLongString(tmp_os2.str());
3383 std::string s = os.str();
3384 verbosestream<<"Server: Sending node definitions to id("<<peer_id
3385 <<"): size="<<s.size()<<std::endl;
3386 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3388 con.Send(peer_id, 0, data, true);
3392 Non-static send methods
3395 void Server::SendInventory(u16 peer_id)
3397 DSTACK(__FUNCTION_NAME);
3399 PlayerSAO *playersao = getPlayerSAO(peer_id);
3402 playersao->m_inventory_not_sent = false;
3408 std::ostringstream os;
3409 playersao->getInventory()->serialize(os);
3411 std::string s = os.str();
3413 SharedBuffer<u8> data(s.size()+2);
3414 writeU16(&data[0], TOCLIENT_INVENTORY);
3415 memcpy(&data[2], s.c_str(), s.size());
3418 m_con.Send(peer_id, 0, data, true);
3421 void Server::SendChatMessage(u16 peer_id, const std::wstring &message)
3423 DSTACK(__FUNCTION_NAME);
3425 std::ostringstream os(std::ios_base::binary);
3429 writeU16(buf, TOCLIENT_CHAT_MESSAGE);
3430 os.write((char*)buf, 2);
3433 writeU16(buf, message.size());
3434 os.write((char*)buf, 2);
3437 for(u32 i=0; i<message.size(); i++)
3441 os.write((char*)buf, 2);
3445 std::string s = os.str();
3446 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3448 m_con.Send(peer_id, 0, data, true);
3450 void Server::SendShowFormspecMessage(u16 peer_id, const std::string formspec, const std::string formname)
3452 DSTACK(__FUNCTION_NAME);
3454 std::ostringstream os(std::ios_base::binary);
3458 writeU16(buf, TOCLIENT_SHOW_FORMSPEC);
3459 os.write((char*)buf, 2);
3460 os<<serializeLongString(formspec);
3461 os<<serializeString(formname);
3464 std::string s = os.str();
3465 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3467 m_con.Send(peer_id, 0, data, true);
3470 // Spawns a particle on peer with peer_id
3471 void Server::SendSpawnParticle(u16 peer_id, v3f pos, v3f velocity, v3f acceleration, float expirationtime, float size, bool collisiondetection, std::string texture)
3473 DSTACK(__FUNCTION_NAME);
3475 std::ostringstream os(std::ios_base::binary);
3476 writeU16(os, TOCLIENT_SPAWN_PARTICLE);
3477 writeV3F1000(os, pos);
3478 writeV3F1000(os, velocity);
3479 writeV3F1000(os, acceleration);
3480 writeF1000(os, expirationtime);
3481 writeF1000(os, size);
3482 writeU8(os, collisiondetection);
3483 os<<serializeLongString(texture);
3486 std::string s = os.str();
3487 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3489 m_con.Send(peer_id, 0, data, true);
3492 // Spawns a particle on all peers
3493 void Server::SendSpawnParticleAll(v3f pos, v3f velocity, v3f acceleration, float expirationtime, float size, bool collisiondetection, std::string texture)
3495 for(std::map<u16, RemoteClient*>::iterator
3496 i = m_clients.begin();
3497 i != m_clients.end(); i++)
3499 // Get client and check that it is valid
3500 RemoteClient *client = i->second;
3501 assert(client->peer_id == i->first);
3502 if(client->serialization_version == SER_FMT_VER_INVALID)
3505 SendSpawnParticle(client->peer_id, pos, velocity, acceleration,
3506 expirationtime, size, collisiondetection, texture);
3510 // Adds a ParticleSpawner on peer with peer_id
3511 void Server::SendAddParticleSpawner(u16 peer_id, u16 amount, float spawntime, v3f minpos, v3f maxpos,
3512 v3f minvel, v3f maxvel, v3f minacc, v3f maxacc, float minexptime, float maxexptime,
3513 float minsize, float maxsize, bool collisiondetection, std::string texture, u32 id)
3515 DSTACK(__FUNCTION_NAME);
3517 std::ostringstream os(std::ios_base::binary);
3518 writeU16(os, TOCLIENT_ADD_PARTICLESPAWNER);
3520 writeU16(os, amount);
3521 writeF1000(os, spawntime);
3522 writeV3F1000(os, minpos);
3523 writeV3F1000(os, maxpos);
3524 writeV3F1000(os, minvel);
3525 writeV3F1000(os, maxvel);
3526 writeV3F1000(os, minacc);
3527 writeV3F1000(os, maxacc);
3528 writeF1000(os, minexptime);
3529 writeF1000(os, maxexptime);
3530 writeF1000(os, minsize);
3531 writeF1000(os, maxsize);
3532 writeU8(os, collisiondetection);
3533 os<<serializeLongString(texture);
3537 std::string s = os.str();
3538 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3540 m_con.Send(peer_id, 0, data, true);
3543 // Adds a ParticleSpawner on all peers
3544 void Server::SendAddParticleSpawnerAll(u16 amount, float spawntime, v3f minpos, v3f maxpos,
3545 v3f minvel, v3f maxvel, v3f minacc, v3f maxacc, float minexptime, float maxexptime,
3546 float minsize, float maxsize, bool collisiondetection, std::string texture, u32 id)
3548 for(std::map<u16, RemoteClient*>::iterator
3549 i = m_clients.begin();
3550 i != m_clients.end(); i++)
3552 // Get client and check that it is valid
3553 RemoteClient *client = i->second;
3554 assert(client->peer_id == i->first);
3555 if(client->serialization_version == SER_FMT_VER_INVALID)
3558 SendAddParticleSpawner(client->peer_id, amount, spawntime,
3559 minpos, maxpos, minvel, maxvel, minacc, maxacc,
3560 minexptime, maxexptime, minsize, maxsize, collisiondetection, texture, id);
3564 void Server::SendDeleteParticleSpawner(u16 peer_id, u32 id)
3566 DSTACK(__FUNCTION_NAME);
3568 std::ostringstream os(std::ios_base::binary);
3569 writeU16(os, TOCLIENT_DELETE_PARTICLESPAWNER);
3574 std::string s = os.str();
3575 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3577 m_con.Send(peer_id, 0, data, true);
3580 void Server::SendDeleteParticleSpawnerAll(u32 id)
3582 for(std::map<u16, RemoteClient*>::iterator
3583 i = m_clients.begin();
3584 i != m_clients.end(); i++)
3586 // Get client and check that it is valid
3587 RemoteClient *client = i->second;
3588 assert(client->peer_id == i->first);
3589 if(client->serialization_version == SER_FMT_VER_INVALID)
3592 SendDeleteParticleSpawner(client->peer_id, id);
3596 void Server::BroadcastChatMessage(const std::wstring &message)
3598 for(std::map<u16, RemoteClient*>::iterator
3599 i = m_clients.begin();
3600 i != m_clients.end(); ++i)
3602 // Get client and check that it is valid
3603 RemoteClient *client = i->second;
3604 assert(client->peer_id == i->first);
3605 if(client->serialization_version == SER_FMT_VER_INVALID)
3608 SendChatMessage(client->peer_id, message);
3612 void Server::SendPlayerHP(u16 peer_id)
3614 DSTACK(__FUNCTION_NAME);
3615 PlayerSAO *playersao = getPlayerSAO(peer_id);
3617 playersao->m_hp_not_sent = false;
3618 SendHP(m_con, peer_id, playersao->getHP());
3621 void Server::SendMovePlayer(u16 peer_id)
3623 DSTACK(__FUNCTION_NAME);
3624 Player *player = m_env->getPlayer(peer_id);
3627 std::ostringstream os(std::ios_base::binary);
3628 writeU16(os, TOCLIENT_MOVE_PLAYER);
3629 writeV3F1000(os, player->getPosition());
3630 writeF1000(os, player->getPitch());
3631 writeF1000(os, player->getYaw());
3634 v3f pos = player->getPosition();
3635 f32 pitch = player->getPitch();
3636 f32 yaw = player->getYaw();
3637 verbosestream<<"Server: Sending TOCLIENT_MOVE_PLAYER"
3638 <<" pos=("<<pos.X<<","<<pos.Y<<","<<pos.Z<<")"
3645 std::string s = os.str();
3646 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3648 m_con.Send(peer_id, 0, data, true);
3651 void Server::SendPlayerPrivileges(u16 peer_id)
3653 Player *player = m_env->getPlayer(peer_id);
3655 if(player->peer_id == PEER_ID_INEXISTENT)
3658 std::set<std::string> privs;
3659 scriptapi_get_auth(m_lua, player->getName(), NULL, &privs);
3661 std::ostringstream os(std::ios_base::binary);
3662 writeU16(os, TOCLIENT_PRIVILEGES);
3663 writeU16(os, privs.size());
3664 for(std::set<std::string>::const_iterator i = privs.begin();
3665 i != privs.end(); i++){
3666 os<<serializeString(*i);
3670 std::string s = os.str();
3671 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3673 m_con.Send(peer_id, 0, data, true);
3676 void Server::SendPlayerInventoryFormspec(u16 peer_id)
3678 Player *player = m_env->getPlayer(peer_id);
3680 if(player->peer_id == PEER_ID_INEXISTENT)
3683 std::ostringstream os(std::ios_base::binary);
3684 writeU16(os, TOCLIENT_INVENTORY_FORMSPEC);
3685 os<<serializeLongString(player->inventory_formspec);
3688 std::string s = os.str();
3689 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3691 m_con.Send(peer_id, 0, data, true);
3694 s32 Server::playSound(const SimpleSoundSpec &spec,
3695 const ServerSoundParams ¶ms)
3697 // Find out initial position of sound
3698 bool pos_exists = false;
3699 v3f pos = params.getPos(m_env, &pos_exists);
3700 // If position is not found while it should be, cancel sound
3701 if(pos_exists != (params.type != ServerSoundParams::SSP_LOCAL))
3703 // Filter destination clients
3704 std::set<RemoteClient*> dst_clients;
3705 if(params.to_player != "")
3707 Player *player = m_env->getPlayer(params.to_player.c_str());
3709 infostream<<"Server::playSound: Player \""<<params.to_player
3710 <<"\" not found"<<std::endl;
3713 if(player->peer_id == PEER_ID_INEXISTENT){
3714 infostream<<"Server::playSound: Player \""<<params.to_player
3715 <<"\" not connected"<<std::endl;
3718 RemoteClient *client = getClient(player->peer_id);
3719 dst_clients.insert(client);
3723 for(std::map<u16, RemoteClient*>::iterator
3724 i = m_clients.begin(); i != m_clients.end(); ++i)
3726 RemoteClient *client = i->second;
3727 Player *player = m_env->getPlayer(client->peer_id);
3731 if(player->getPosition().getDistanceFrom(pos) >
3732 params.max_hear_distance)
3735 dst_clients.insert(client);
3738 if(dst_clients.size() == 0)
3741 s32 id = m_next_sound_id++;
3742 // The sound will exist as a reference in m_playing_sounds
3743 m_playing_sounds[id] = ServerPlayingSound();
3744 ServerPlayingSound &psound = m_playing_sounds[id];
3745 psound.params = params;
3746 for(std::set<RemoteClient*>::iterator i = dst_clients.begin();
3747 i != dst_clients.end(); i++)
3748 psound.clients.insert((*i)->peer_id);
3750 std::ostringstream os(std::ios_base::binary);
3751 writeU16(os, TOCLIENT_PLAY_SOUND);
3753 os<<serializeString(spec.name);
3754 writeF1000(os, spec.gain * params.gain);
3755 writeU8(os, params.type);
3756 writeV3F1000(os, pos);
3757 writeU16(os, params.object);
3758 writeU8(os, params.loop);
3760 std::string s = os.str();
3761 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3763 for(std::set<RemoteClient*>::iterator i = dst_clients.begin();
3764 i != dst_clients.end(); i++){
3766 m_con.Send((*i)->peer_id, 0, data, true);
3770 void Server::stopSound(s32 handle)
3772 // Get sound reference
3773 std::map<s32, ServerPlayingSound>::iterator i =
3774 m_playing_sounds.find(handle);
3775 if(i == m_playing_sounds.end())
3777 ServerPlayingSound &psound = i->second;
3779 std::ostringstream os(std::ios_base::binary);
3780 writeU16(os, TOCLIENT_STOP_SOUND);
3781 writeS32(os, handle);
3783 std::string s = os.str();
3784 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3786 for(std::set<u16>::iterator i = psound.clients.begin();
3787 i != psound.clients.end(); i++){
3789 m_con.Send(*i, 0, data, true);
3791 // Remove sound reference
3792 m_playing_sounds.erase(i);
3795 void Server::sendRemoveNode(v3s16 p, u16 ignore_id,
3796 std::list<u16> *far_players, float far_d_nodes)
3798 float maxd = far_d_nodes*BS;
3799 v3f p_f = intToFloat(p, BS);
3803 SharedBuffer<u8> reply(replysize);
3804 writeU16(&reply[0], TOCLIENT_REMOVENODE);
3805 writeS16(&reply[2], p.X);
3806 writeS16(&reply[4], p.Y);
3807 writeS16(&reply[6], p.Z);
3809 for(std::map<u16, RemoteClient*>::iterator
3810 i = m_clients.begin();
3811 i != m_clients.end(); ++i)
3813 // Get client and check that it is valid
3814 RemoteClient *client = i->second;
3815 assert(client->peer_id == i->first);
3816 if(client->serialization_version == SER_FMT_VER_INVALID)
3819 // Don't send if it's the same one
3820 if(client->peer_id == ignore_id)
3826 Player *player = m_env->getPlayer(client->peer_id);
3829 // If player is far away, only set modified blocks not sent
3830 v3f player_pos = player->getPosition();
3831 if(player_pos.getDistanceFrom(p_f) > maxd)
3833 far_players->push_back(client->peer_id);
3840 m_con.Send(client->peer_id, 0, reply, true);
3844 void Server::sendAddNode(v3s16 p, MapNode n, u16 ignore_id,
3845 std::list<u16> *far_players, float far_d_nodes)
3847 float maxd = far_d_nodes*BS;
3848 v3f p_f = intToFloat(p, BS);
3850 for(std::map<u16, RemoteClient*>::iterator
3851 i = m_clients.begin();
3852 i != m_clients.end(); ++i)
3854 // Get client and check that it is valid
3855 RemoteClient *client = i->second;
3856 assert(client->peer_id == i->first);
3857 if(client->serialization_version == SER_FMT_VER_INVALID)
3860 // Don't send if it's the same one
3861 if(client->peer_id == ignore_id)
3867 Player *player = m_env->getPlayer(client->peer_id);
3870 // If player is far away, only set modified blocks not sent
3871 v3f player_pos = player->getPosition();
3872 if(player_pos.getDistanceFrom(p_f) > maxd)
3874 far_players->push_back(client->peer_id);
3881 u32 replysize = 8 + MapNode::serializedLength(client->serialization_version);
3882 SharedBuffer<u8> reply(replysize);
3883 writeU16(&reply[0], TOCLIENT_ADDNODE);
3884 writeS16(&reply[2], p.X);
3885 writeS16(&reply[4], p.Y);
3886 writeS16(&reply[6], p.Z);
3887 n.serialize(&reply[8], client->serialization_version);
3890 m_con.Send(client->peer_id, 0, reply, true);
3894 void Server::setBlockNotSent(v3s16 p)
3896 for(std::map<u16, RemoteClient*>::iterator
3897 i = m_clients.begin();
3898 i != m_clients.end(); ++i)
3900 RemoteClient *client = i->second;
3901 client->SetBlockNotSent(p);
3905 void Server::SendBlockNoLock(u16 peer_id, MapBlock *block, u8 ver)
3907 DSTACK(__FUNCTION_NAME);
3909 v3s16 p = block->getPos();
3913 bool completely_air = true;
3914 for(s16 z0=0; z0<MAP_BLOCKSIZE; z0++)
3915 for(s16 x0=0; x0<MAP_BLOCKSIZE; x0++)
3916 for(s16 y0=0; y0<MAP_BLOCKSIZE; y0++)
3918 if(block->getNodeNoEx(v3s16(x0,y0,z0)).d != CONTENT_AIR)
3920 completely_air = false;
3921 x0 = y0 = z0 = MAP_BLOCKSIZE; // Break out
3926 infostream<<"Server: Sending block ("<<p.X<<","<<p.Y<<","<<p.Z<<"): ";
3928 infostream<<"[completely air] ";
3929 infostream<<std::endl;
3933 Create a packet with the block in the right format
3936 std::ostringstream os(std::ios_base::binary);
3937 block->serialize(os, ver, false);
3938 std::string s = os.str();
3939 SharedBuffer<u8> blockdata((u8*)s.c_str(), s.size());
3941 u32 replysize = 8 + blockdata.getSize();
3942 SharedBuffer<u8> reply(replysize);
3943 writeU16(&reply[0], TOCLIENT_BLOCKDATA);
3944 writeS16(&reply[2], p.X);
3945 writeS16(&reply[4], p.Y);
3946 writeS16(&reply[6], p.Z);
3947 memcpy(&reply[8], *blockdata, blockdata.getSize());
3949 /*infostream<<"Server: Sending block ("<<p.X<<","<<p.Y<<","<<p.Z<<")"
3950 <<": \tpacket size: "<<replysize<<std::endl;*/
3955 m_con.Send(peer_id, 1, reply, true);
3958 void Server::SendBlocks(float dtime)
3960 DSTACK(__FUNCTION_NAME);
3962 JMutexAutoLock envlock(m_env_mutex);
3963 JMutexAutoLock conlock(m_con_mutex);
3965 ScopeProfiler sp(g_profiler, "Server: sel and send blocks to clients");
3967 std::vector<PrioritySortedBlockTransfer> queue;
3969 s32 total_sending = 0;
3972 ScopeProfiler sp(g_profiler, "Server: selecting blocks for sending");
3974 for(std::map<u16, RemoteClient*>::iterator
3975 i = m_clients.begin();
3976 i != m_clients.end(); ++i)
3978 RemoteClient *client = i->second;
3979 assert(client->peer_id == i->first);
3981 // If definitions and textures have not been sent, don't
3982 // send MapBlocks either
3983 if(!client->definitions_sent)
3986 total_sending += client->SendingCount();
3988 if(client->serialization_version == SER_FMT_VER_INVALID)
3991 client->GetNextBlocks(this, dtime, queue);
3996 // Lowest priority number comes first.
3997 // Lowest is most important.
3998 std::sort(queue.begin(), queue.end());
4000 for(u32 i=0; i<queue.size(); i++)
4002 //TODO: Calculate limit dynamically
4003 if(total_sending >= g_settings->getS32
4004 ("max_simultaneous_block_sends_server_total"))
4007 PrioritySortedBlockTransfer q = queue[i];
4009 MapBlock *block = NULL;
4012 block = m_env->getMap().getBlockNoCreate(q.pos);
4014 catch(InvalidPositionException &e)
4019 RemoteClient *client = getClient(q.peer_id);
4021 SendBlockNoLock(q.peer_id, block, client->serialization_version);
4023 client->SentBlock(q.pos);
4029 void Server::fillMediaCache()
4031 DSTACK(__FUNCTION_NAME);
4033 infostream<<"Server: Calculating media file checksums"<<std::endl;
4035 // Collect all media file paths
4036 std::list<std::string> paths;
4037 for(std::vector<ModSpec>::iterator i = m_mods.begin();
4038 i != m_mods.end(); i++){
4039 const ModSpec &mod = *i;
4040 paths.push_back(mod.path + DIR_DELIM + "textures");
4041 paths.push_back(mod.path + DIR_DELIM + "sounds");
4042 paths.push_back(mod.path + DIR_DELIM + "media");
4043 paths.push_back(mod.path + DIR_DELIM + "models");
4045 std::string path_all = "textures";
4046 paths.push_back(path_all + DIR_DELIM + "all");
4048 // Collect media file information from paths into cache
4049 for(std::list<std::string>::iterator i = paths.begin();
4050 i != paths.end(); i++)
4052 std::string mediapath = *i;
4053 std::vector<fs::DirListNode> dirlist = fs::GetDirListing(mediapath);
4054 for(u32 j=0; j<dirlist.size(); j++){
4055 if(dirlist[j].dir) // Ignode dirs
4057 std::string filename = dirlist[j].name;
4058 // If name contains illegal characters, ignore the file
4059 if(!string_allowed(filename, TEXTURENAME_ALLOWED_CHARS)){
4060 infostream<<"Server: ignoring illegal file name: \""
4061 <<filename<<"\""<<std::endl;
4064 // If name is not in a supported format, ignore it
4065 const char *supported_ext[] = {
4066 ".png", ".jpg", ".bmp", ".tga",
4067 ".pcx", ".ppm", ".psd", ".wal", ".rgb",
4069 ".x", ".b3d", ".md2", ".obj",
4072 if(removeStringEnd(filename, supported_ext) == ""){
4073 infostream<<"Server: ignoring unsupported file extension: \""
4074 <<filename<<"\""<<std::endl;
4077 // Ok, attempt to load the file and add to cache
4078 std::string filepath = mediapath + DIR_DELIM + filename;
4080 std::ifstream fis(filepath.c_str(), std::ios_base::binary);
4081 if(fis.good() == false){
4082 errorstream<<"Server::fillMediaCache(): Could not open \""
4083 <<filename<<"\" for reading"<<std::endl;
4086 std::ostringstream tmp_os(std::ios_base::binary);
4090 fis.read(buf, 1024);
4091 std::streamsize len = fis.gcount();
4092 tmp_os.write(buf, len);
4101 errorstream<<"Server::fillMediaCache(): Failed to read \""
4102 <<filename<<"\""<<std::endl;
4105 if(tmp_os.str().length() == 0){
4106 errorstream<<"Server::fillMediaCache(): Empty file \""
4107 <<filepath<<"\""<<std::endl;
4112 sha1.addBytes(tmp_os.str().c_str(), tmp_os.str().length());
4114 unsigned char *digest = sha1.getDigest();
4115 std::string sha1_base64 = base64_encode(digest, 20);
4116 std::string sha1_hex = hex_encode((char*)digest, 20);
4120 this->m_media[filename] = MediaInfo(filepath, sha1_base64);
4121 verbosestream<<"Server: "<<sha1_hex<<" is "<<filename<<std::endl;
4126 struct SendableMediaAnnouncement
4129 std::string sha1_digest;
4131 SendableMediaAnnouncement(const std::string name_="",
4132 const std::string sha1_digest_=""):
4134 sha1_digest(sha1_digest_)
4138 void Server::sendMediaAnnouncement(u16 peer_id)
4140 DSTACK(__FUNCTION_NAME);
4142 verbosestream<<"Server: Announcing files to id("<<peer_id<<")"
4145 std::list<SendableMediaAnnouncement> file_announcements;
4147 for(std::map<std::string, MediaInfo>::iterator i = m_media.begin();
4148 i != m_media.end(); i++){
4150 file_announcements.push_back(
4151 SendableMediaAnnouncement(i->first, i->second.sha1_digest));
4155 std::ostringstream os(std::ios_base::binary);
4163 u16 length of sha1_digest
4168 writeU16(os, TOCLIENT_ANNOUNCE_MEDIA);
4169 writeU16(os, file_announcements.size());
4171 for(std::list<SendableMediaAnnouncement>::iterator
4172 j = file_announcements.begin();
4173 j != file_announcements.end(); ++j){
4174 os<<serializeString(j->name);
4175 os<<serializeString(j->sha1_digest);
4177 os<<serializeString(g_settings->get("remote_media"));
4180 std::string s = os.str();
4181 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
4184 m_con.Send(peer_id, 0, data, true);
4187 struct SendableMedia
4193 SendableMedia(const std::string &name_="", const std::string path_="",
4194 const std::string &data_=""):
4201 void Server::sendRequestedMedia(u16 peer_id,
4202 const std::list<MediaRequest> &tosend)
4204 DSTACK(__FUNCTION_NAME);
4206 verbosestream<<"Server::sendRequestedMedia(): "
4207 <<"Sending files to client"<<std::endl;
4211 // Put 5kB in one bunch (this is not accurate)
4212 u32 bytes_per_bunch = 5000;
4214 std::vector< std::list<SendableMedia> > file_bunches;
4215 file_bunches.push_back(std::list<SendableMedia>());
4217 u32 file_size_bunch_total = 0;
4219 for(std::list<MediaRequest>::const_iterator i = tosend.begin();
4220 i != tosend.end(); ++i)
4222 if(m_media.find(i->name) == m_media.end()){
4223 errorstream<<"Server::sendRequestedMedia(): Client asked for "
4224 <<"unknown file \""<<(i->name)<<"\""<<std::endl;
4228 //TODO get path + name
4229 std::string tpath = m_media[(*i).name].path;
4232 std::ifstream fis(tpath.c_str(), std::ios_base::binary);
4233 if(fis.good() == false){
4234 errorstream<<"Server::sendRequestedMedia(): Could not open \""
4235 <<tpath<<"\" for reading"<<std::endl;
4238 std::ostringstream tmp_os(std::ios_base::binary);
4242 fis.read(buf, 1024);
4243 std::streamsize len = fis.gcount();
4244 tmp_os.write(buf, len);
4245 file_size_bunch_total += len;
4254 errorstream<<"Server::sendRequestedMedia(): Failed to read \""
4255 <<(*i).name<<"\""<<std::endl;
4258 /*infostream<<"Server::sendRequestedMedia(): Loaded \""
4259 <<tname<<"\""<<std::endl;*/
4261 file_bunches[file_bunches.size()-1].push_back(
4262 SendableMedia((*i).name, tpath, tmp_os.str()));
4264 // Start next bunch if got enough data
4265 if(file_size_bunch_total >= bytes_per_bunch){
4266 file_bunches.push_back(std::list<SendableMedia>());
4267 file_size_bunch_total = 0;
4272 /* Create and send packets */
4274 u32 num_bunches = file_bunches.size();
4275 for(u32 i=0; i<num_bunches; i++)
4277 std::ostringstream os(std::ios_base::binary);
4281 u16 total number of texture bunches
4282 u16 index of this bunch
4283 u32 number of files in this bunch
4292 writeU16(os, TOCLIENT_MEDIA);
4293 writeU16(os, num_bunches);
4295 writeU32(os, file_bunches[i].size());
4297 for(std::list<SendableMedia>::iterator
4298 j = file_bunches[i].begin();
4299 j != file_bunches[i].end(); ++j){
4300 os<<serializeString(j->name);
4301 os<<serializeLongString(j->data);
4305 std::string s = os.str();
4306 verbosestream<<"Server::sendRequestedMedia(): bunch "
4307 <<i<<"/"<<num_bunches
4308 <<" files="<<file_bunches[i].size()
4309 <<" size=" <<s.size()<<std::endl;
4310 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
4312 m_con.Send(peer_id, 0, data, true);
4316 void Server::sendDetachedInventory(const std::string &name, u16 peer_id)
4318 if(m_detached_inventories.count(name) == 0){
4319 errorstream<<__FUNCTION_NAME<<": \""<<name<<"\" not found"<<std::endl;
4322 Inventory *inv = m_detached_inventories[name];
4324 std::ostringstream os(std::ios_base::binary);
4325 writeU16(os, TOCLIENT_DETACHED_INVENTORY);
4326 os<<serializeString(name);
4330 std::string s = os.str();
4331 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
4333 m_con.Send(peer_id, 0, data, true);
4336 void Server::sendDetachedInventoryToAll(const std::string &name)
4338 DSTACK(__FUNCTION_NAME);
4340 for(std::map<u16, RemoteClient*>::iterator
4341 i = m_clients.begin();
4342 i != m_clients.end(); ++i){
4343 RemoteClient *client = i->second;
4344 sendDetachedInventory(name, client->peer_id);
4348 void Server::sendDetachedInventories(u16 peer_id)
4350 DSTACK(__FUNCTION_NAME);
4352 for(std::map<std::string, Inventory*>::iterator
4353 i = m_detached_inventories.begin();
4354 i != m_detached_inventories.end(); i++){
4355 const std::string &name = i->first;
4356 //Inventory *inv = i->second;
4357 sendDetachedInventory(name, peer_id);
4365 void Server::DiePlayer(u16 peer_id)
4367 DSTACK(__FUNCTION_NAME);
4369 PlayerSAO *playersao = getPlayerSAO(peer_id);
4372 infostream<<"Server::DiePlayer(): Player "
4373 <<playersao->getPlayer()->getName()
4374 <<" dies"<<std::endl;
4376 playersao->setHP(0);
4378 // Trigger scripted stuff
4379 scriptapi_on_dieplayer(m_lua, playersao);
4381 SendPlayerHP(peer_id);
4382 SendDeathscreen(m_con, peer_id, false, v3f(0,0,0));
4385 void Server::RespawnPlayer(u16 peer_id)
4387 DSTACK(__FUNCTION_NAME);
4389 PlayerSAO *playersao = getPlayerSAO(peer_id);
4392 infostream<<"Server::RespawnPlayer(): Player "
4393 <<playersao->getPlayer()->getName()
4394 <<" respawns"<<std::endl;
4396 playersao->setHP(PLAYER_MAX_HP);
4398 bool repositioned = scriptapi_on_respawnplayer(m_lua, playersao);
4400 v3f pos = findSpawnPos(m_env->getServerMap());
4401 playersao->setPos(pos);
4405 void Server::UpdateCrafting(u16 peer_id)
4407 DSTACK(__FUNCTION_NAME);
4409 Player* player = m_env->getPlayer(peer_id);
4412 // Get a preview for crafting
4414 getCraftingResult(&player->inventory, preview, false, this);
4416 // Put the new preview in
4417 InventoryList *plist = player->inventory.getList("craftpreview");
4419 assert(plist->getSize() >= 1);
4420 plist->changeItem(0, preview);
4423 RemoteClient* Server::getClient(u16 peer_id)
4425 DSTACK(__FUNCTION_NAME);
4426 //JMutexAutoLock lock(m_con_mutex);
4427 std::map<u16, RemoteClient*>::iterator n;
4428 n = m_clients.find(peer_id);
4429 // A client should exist for all peers
4430 assert(n != m_clients.end());
4434 std::wstring Server::getStatusString()
4436 std::wostringstream os(std::ios_base::binary);
4439 os<<L"version="<<narrow_to_wide(VERSION_STRING);
4441 os<<L", uptime="<<m_uptime.get();
4442 // Information about clients
4443 std::map<u16, RemoteClient*>::iterator i;
4446 for(i = m_clients.begin(), first = true;
4447 i != m_clients.end(); ++i)
4449 // Get client and check that it is valid
4450 RemoteClient *client = i->second;
4451 assert(client->peer_id == i->first);
4452 if(client->serialization_version == SER_FMT_VER_INVALID)
4455 Player *player = m_env->getPlayer(client->peer_id);
4456 // Get name of player
4457 std::wstring name = L"unknown";
4459 name = narrow_to_wide(player->getName());
4460 // Add name to information string
4468 if(((ServerMap*)(&m_env->getMap()))->isSavingEnabled() == false)
4469 os<<std::endl<<L"# Server: "<<" WARNING: Map saving is disabled.";
4470 if(g_settings->get("motd") != "")
4471 os<<std::endl<<L"# Server: "<<narrow_to_wide(g_settings->get("motd"));
4475 std::set<std::string> Server::getPlayerEffectivePrivs(const std::string &name)
4477 std::set<std::string> privs;
4478 scriptapi_get_auth(m_lua, name, NULL, &privs);
4482 bool Server::checkPriv(const std::string &name, const std::string &priv)
4484 std::set<std::string> privs = getPlayerEffectivePrivs(name);
4485 return (privs.count(priv) != 0);
4488 void Server::reportPrivsModified(const std::string &name)
4491 for(std::map<u16, RemoteClient*>::iterator
4492 i = m_clients.begin();
4493 i != m_clients.end(); ++i){
4494 RemoteClient *client = i->second;
4495 Player *player = m_env->getPlayer(client->peer_id);
4496 reportPrivsModified(player->getName());
4499 Player *player = m_env->getPlayer(name.c_str());
4502 SendPlayerPrivileges(player->peer_id);
4503 PlayerSAO *sao = player->getPlayerSAO();
4506 sao->updatePrivileges(
4507 getPlayerEffectivePrivs(name),
4512 void Server::reportInventoryFormspecModified(const std::string &name)
4514 Player *player = m_env->getPlayer(name.c_str());
4517 SendPlayerInventoryFormspec(player->peer_id);
4520 // Saves g_settings to configpath given at initialization
4521 void Server::saveConfig()
4523 if(m_path_config != "")
4524 g_settings->updateConfigFile(m_path_config.c_str());
4527 void Server::notifyPlayer(const char *name, const std::wstring msg)
4529 Player *player = m_env->getPlayer(name);
4532 SendChatMessage(player->peer_id, std::wstring(L"Server: -!- ")+msg);
4535 bool Server::showFormspec(const char *playername, const std::string &formspec, const std::string &formname)
4537 Player *player = m_env->getPlayer(playername);
4541 infostream<<"showFormspec: couldn't find player:"<<playername<<std::endl;
4545 SendShowFormspecMessage(player->peer_id, formspec, formname);
4549 void Server::notifyPlayers(const std::wstring msg)
4551 BroadcastChatMessage(msg);
4554 void Server::spawnParticle(const char *playername, v3f pos,
4555 v3f velocity, v3f acceleration,
4556 float expirationtime, float size, bool
4557 collisiondetection, std::string texture)
4559 Player *player = m_env->getPlayer(playername);
4562 SendSpawnParticle(player->peer_id, pos, velocity, acceleration,
4563 expirationtime, size, collisiondetection, texture);
4566 void Server::spawnParticleAll(v3f pos, v3f velocity, v3f acceleration,
4567 float expirationtime, float size,
4568 bool collisiondetection, std::string texture)
4570 SendSpawnParticleAll(pos, velocity, acceleration,
4571 expirationtime, size, collisiondetection, texture);
4574 u32 Server::addParticleSpawner(const char *playername,
4575 u16 amount, float spawntime,
4576 v3f minpos, v3f maxpos,
4577 v3f minvel, v3f maxvel,
4578 v3f minacc, v3f maxacc,
4579 float minexptime, float maxexptime,
4580 float minsize, float maxsize,
4581 bool collisiondetection, std::string texture)
4583 Player *player = m_env->getPlayer(playername);
4588 for(;;) // look for unused particlespawner id
4591 if (std::find(m_particlespawner_ids.begin(),
4592 m_particlespawner_ids.end(), id)
4593 == m_particlespawner_ids.end())
4595 m_particlespawner_ids.push_back(id);
4600 SendAddParticleSpawner(player->peer_id, amount, spawntime,
4601 minpos, maxpos, minvel, maxvel, minacc, maxacc,
4602 minexptime, maxexptime, minsize, maxsize,
4603 collisiondetection, texture, id);
4608 u32 Server::addParticleSpawnerAll(u16 amount, float spawntime,
4609 v3f minpos, v3f maxpos,
4610 v3f minvel, v3f maxvel,
4611 v3f minacc, v3f maxacc,
4612 float minexptime, float maxexptime,
4613 float minsize, float maxsize,
4614 bool collisiondetection, std::string texture)
4617 for(;;) // look for unused particlespawner id
4620 if (std::find(m_particlespawner_ids.begin(),
4621 m_particlespawner_ids.end(), id)
4622 == m_particlespawner_ids.end())
4624 m_particlespawner_ids.push_back(id);
4629 SendAddParticleSpawnerAll(amount, spawntime,
4630 minpos, maxpos, minvel, maxvel, minacc, maxacc,
4631 minexptime, maxexptime, minsize, maxsize,
4632 collisiondetection, texture, id);
4637 void Server::deleteParticleSpawner(const char *playername, u32 id)
4639 Player *player = m_env->getPlayer(playername);
4643 m_particlespawner_ids.erase(
4644 std::remove(m_particlespawner_ids.begin(),
4645 m_particlespawner_ids.end(), id),
4646 m_particlespawner_ids.end());
4647 SendDeleteParticleSpawner(player->peer_id, id);
4650 void Server::deleteParticleSpawnerAll(u32 id)
4652 m_particlespawner_ids.erase(
4653 std::remove(m_particlespawner_ids.begin(),
4654 m_particlespawner_ids.end(), id),
4655 m_particlespawner_ids.end());
4656 SendDeleteParticleSpawnerAll(id);
4659 void Server::queueBlockEmerge(v3s16 blockpos, bool allow_generate)
4661 m_emerge->enqueueBlockEmerge(PEER_ID_INEXISTENT, blockpos, allow_generate);
4664 Inventory* Server::createDetachedInventory(const std::string &name)
4666 if(m_detached_inventories.count(name) > 0){
4667 infostream<<"Server clearing detached inventory \""<<name<<"\""<<std::endl;
4668 delete m_detached_inventories[name];
4670 infostream<<"Server creating detached inventory \""<<name<<"\""<<std::endl;
4672 Inventory *inv = new Inventory(m_itemdef);
4674 m_detached_inventories[name] = inv;
4675 sendDetachedInventoryToAll(name);
4682 BoolScopeSet(bool *dst, bool val):
4685 m_orig_state = *m_dst;
4690 *m_dst = m_orig_state;
4697 // actions: time-reversed list
4698 // Return value: success/failure
4699 bool Server::rollbackRevertActions(const std::list<RollbackAction> &actions,
4700 std::list<std::string> *log)
4702 infostream<<"Server::rollbackRevertActions(len="<<actions.size()<<")"<<std::endl;
4703 ServerMap *map = (ServerMap*)(&m_env->getMap());
4704 // Disable rollback report sink while reverting
4705 BoolScopeSet rollback_scope_disable(&m_rollback_sink_enabled, false);
4707 // Fail if no actions to handle
4708 if(actions.empty()){
4709 log->push_back("Nothing to do.");
4716 for(std::list<RollbackAction>::const_iterator
4717 i = actions.begin();
4718 i != actions.end(); i++)
4720 const RollbackAction &action = *i;
4722 bool success = action.applyRevert(map, this, this);
4725 std::ostringstream os;
4726 os<<"Revert of step ("<<num_tried<<") "<<action.toString()<<" failed";
4727 infostream<<"Map::rollbackRevertActions(): "<<os.str()<<std::endl;
4729 log->push_back(os.str());
4731 std::ostringstream os;
4732 os<<"Successfully reverted step ("<<num_tried<<") "<<action.toString();
4733 infostream<<"Map::rollbackRevertActions(): "<<os.str()<<std::endl;
4735 log->push_back(os.str());
4739 infostream<<"Map::rollbackRevertActions(): "<<num_failed<<"/"<<num_tried
4740 <<" failed"<<std::endl;
4742 // Call it done if less than half failed
4743 return num_failed <= num_tried/2;
4746 // IGameDef interface
4748 IItemDefManager* Server::getItemDefManager()
4752 INodeDefManager* Server::getNodeDefManager()
4756 ICraftDefManager* Server::getCraftDefManager()
4760 ITextureSource* Server::getTextureSource()
4764 IShaderSource* Server::getShaderSource()
4768 u16 Server::allocateUnknownNodeId(const std::string &name)
4770 return m_nodedef->allocateDummy(name);
4772 ISoundManager* Server::getSoundManager()
4774 return &dummySoundManager;
4776 MtEventManager* Server::getEventManager()
4780 IRollbackReportSink* Server::getRollbackReportSink()
4782 if(!m_enable_rollback_recording)
4784 if(!m_rollback_sink_enabled)
4789 IWritableItemDefManager* Server::getWritableItemDefManager()
4793 IWritableNodeDefManager* Server::getWritableNodeDefManager()
4797 IWritableCraftDefManager* Server::getWritableCraftDefManager()
4802 const ModSpec* Server::getModSpec(const std::string &modname)
4804 for(std::vector<ModSpec>::iterator i = m_mods.begin();
4805 i != m_mods.end(); i++){
4806 const ModSpec &mod = *i;
4807 if(mod.name == modname)
4812 void Server::getModNames(std::list<std::string> &modlist)
4814 for(std::vector<ModSpec>::iterator i = m_mods.begin(); i != m_mods.end(); i++)
4816 modlist.push_back(i->name);
4819 std::string Server::getBuiltinLuaPath()
4821 return porting::path_share + DIR_DELIM + "builtin";
4824 v3f findSpawnPos(ServerMap &map)
4826 //return v3f(50,50,50)*BS;
4831 nodepos = v2s16(0,0);
4836 s16 water_level = map.m_mgparams->water_level;
4838 // Try to find a good place a few times
4839 for(s32 i=0; i<1000; i++)
4842 // We're going to try to throw the player to this position
4843 v2s16 nodepos2d = v2s16(-range + (myrand()%(range*2)),
4844 -range + (myrand()%(range*2)));
4845 //v2s16 sectorpos = getNodeSectorPos(nodepos2d);
4846 // Get ground height at point (fallbacks to heightmap function)
4847 s16 groundheight = map.findGroundLevel(nodepos2d);
4848 // Don't go underwater
4849 if(groundheight <= water_level)
4851 //infostream<<"-> Underwater"<<std::endl;
4854 // Don't go to high places
4855 if(groundheight > water_level + 6)
4857 //infostream<<"-> Underwater"<<std::endl;
4861 nodepos = v3s16(nodepos2d.X, groundheight-2, nodepos2d.Y);
4862 bool is_good = false;
4864 for(s32 i=0; i<10; i++){
4865 v3s16 blockpos = getNodeBlockPos(nodepos);
4866 map.emergeBlock(blockpos, true);
4867 MapNode n = map.getNodeNoEx(nodepos);
4868 if(n.getContent() == CONTENT_AIR){
4879 // Found a good place
4880 //infostream<<"Searched through "<<i<<" places."<<std::endl;
4886 return intToFloat(nodepos, BS);
4889 PlayerSAO* Server::emergePlayer(const char *name, u16 peer_id)
4891 RemotePlayer *player = NULL;
4892 bool newplayer = false;
4895 Try to get an existing player
4897 player = static_cast<RemotePlayer*>(m_env->getPlayer(name));
4899 // If player is already connected, cancel
4900 if(player != NULL && player->peer_id != 0)
4902 infostream<<"emergePlayer(): Player already connected"<<std::endl;
4907 If player with the wanted peer_id already exists, cancel.
4909 if(m_env->getPlayer(peer_id) != NULL)
4911 infostream<<"emergePlayer(): Player with wrong name but same"
4912 " peer_id already exists"<<std::endl;
4917 Create a new player if it doesn't exist yet
4922 player = new RemotePlayer(this);
4923 player->updateName(name);
4925 /* Set player position */
4926 infostream<<"Server: Finding spawn place for player \""
4927 <<name<<"\""<<std::endl;
4928 v3f pos = findSpawnPos(m_env->getServerMap());
4929 player->setPosition(pos);
4931 /* Add player to environment */
4932 m_env->addPlayer(player);
4936 Create a new player active object
4938 PlayerSAO *playersao = new PlayerSAO(m_env, player, peer_id,
4939 getPlayerEffectivePrivs(player->getName()),
4942 /* Add object to environment */
4943 m_env->addActiveObject(playersao);
4947 scriptapi_on_newplayer(m_lua, playersao);
4949 scriptapi_on_joinplayer(m_lua, playersao);
4954 void Server::handlePeerChange(PeerChange &c)
4956 JMutexAutoLock envlock(m_env_mutex);
4957 JMutexAutoLock conlock(m_con_mutex);
4959 if(c.type == PEER_ADDED)
4966 std::map<u16, RemoteClient*>::iterator n;
4967 n = m_clients.find(c.peer_id);
4968 // The client shouldn't already exist
4969 assert(n == m_clients.end());
4972 RemoteClient *client = new RemoteClient();
4973 client->peer_id = c.peer_id;
4974 m_clients[client->peer_id] = client;
4977 else if(c.type == PEER_REMOVED)
4984 std::map<u16, RemoteClient*>::iterator n;
4985 n = m_clients.find(c.peer_id);
4986 // The client should exist
4987 assert(n != m_clients.end());
4990 Mark objects to be not known by the client
4992 RemoteClient *client = n->second;
4994 for(std::set<u16>::iterator
4995 i = client->m_known_objects.begin();
4996 i != client->m_known_objects.end(); ++i)
5000 ServerActiveObject* obj = m_env->getActiveObject(id);
5002 if(obj && obj->m_known_by_count > 0)
5003 obj->m_known_by_count--;
5007 Clear references to playing sounds
5009 for(std::map<s32, ServerPlayingSound>::iterator
5010 i = m_playing_sounds.begin();
5011 i != m_playing_sounds.end();)
5013 ServerPlayingSound &psound = i->second;
5014 psound.clients.erase(c.peer_id);
5015 if(psound.clients.size() == 0)
5016 m_playing_sounds.erase(i++);
5021 Player *player = m_env->getPlayer(c.peer_id);
5023 // Collect information about leaving in chat
5024 std::wstring message;
5028 std::wstring name = narrow_to_wide(player->getName());
5031 message += L" left the game.";
5033 message += L" (timed out)";
5037 /* Run scripts and remove from environment */
5041 PlayerSAO *playersao = player->getPlayerSAO();
5044 scriptapi_on_leaveplayer(m_lua, playersao);
5046 playersao->disconnected();
5056 std::ostringstream os(std::ios_base::binary);
5057 for(std::map<u16, RemoteClient*>::iterator
5058 i = m_clients.begin();
5059 i != m_clients.end(); ++i)
5061 RemoteClient *client = i->second;
5062 assert(client->peer_id == i->first);
5063 if(client->serialization_version == SER_FMT_VER_INVALID)
5066 Player *player = m_env->getPlayer(client->peer_id);
5069 // Get name of player
5070 os<<player->getName()<<" ";
5073 actionstream<<player->getName()<<" "
5074 <<(c.timeout?"times out.":"leaves game.")
5075 <<" List of players: "
5076 <<os.str()<<std::endl;
5081 delete m_clients[c.peer_id];
5082 m_clients.erase(c.peer_id);
5084 // Send player info to all remaining clients
5085 //SendPlayerInfos();
5087 // Send leave chat message to all remaining clients
5088 if(message.length() != 0)
5089 BroadcastChatMessage(message);
5098 void Server::handlePeerChanges()
5100 while(m_peer_change_queue.size() > 0)
5102 PeerChange c = m_peer_change_queue.pop_front();
5104 verbosestream<<"Server: Handling peer change: "
5105 <<"id="<<c.peer_id<<", timeout="<<c.timeout
5108 handlePeerChange(c);
5112 void dedicated_server_loop(Server &server, bool &kill)
5114 DSTACK(__FUNCTION_NAME);
5116 verbosestream<<"dedicated_server_loop()"<<std::endl;
5118 IntervalLimiter m_profiler_interval;
5122 float steplen = g_settings->getFloat("dedicated_server_step");
5123 // This is kind of a hack but can be done like this
5124 // because server.step() is very light
5126 ScopeProfiler sp(g_profiler, "dedicated server sleep");
5127 sleep_ms((int)(steplen*1000.0));
5129 server.step(steplen);
5131 if(server.getShutdownRequested() || kill)
5133 infostream<<"Dedicated server quitting"<<std::endl;
5135 if(g_settings->getBool("server_announce") == true)
5136 ServerList::sendAnnounce("delete");
5144 float profiler_print_interval =
5145 g_settings->getFloat("profiler_print_interval");
5146 if(profiler_print_interval != 0)
5148 if(m_profiler_interval.step(steplen, profiler_print_interval))
5150 infostream<<"Profiler:"<<std::endl;
5151 g_profiler->print(infostream);
5152 g_profiler->clear();