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);
907 //shutdown all emerge threads first!
914 JMutexAutoLock clientslock(m_con_mutex);
916 for(std::map<u16, RemoteClient*>::iterator
917 i = m_clients.begin();
918 i != m_clients.end(); ++i)
926 // Delete things in the reverse order of creation
934 // Deinitialize scripting
935 infostream<<"Server: Deinitializing scripting"<<std::endl;
936 script_deinit(m_lua);
938 // Delete detached inventories
940 for(std::map<std::string, Inventory*>::iterator
941 i = m_detached_inventories.begin();
942 i != m_detached_inventories.end(); i++){
948 void Server::start(unsigned short port)
950 DSTACK(__FUNCTION_NAME);
951 infostream<<"Starting server on port "<<port<<"..."<<std::endl;
953 // Stop thread if already running
956 // Initialize connection
957 m_con.SetTimeoutMs(30);
961 m_thread.setRun(true);
964 // ASCII art for the win!
966 <<" .__ __ __ "<<std::endl
967 <<" _____ |__| ____ _____/ |_ ____ _______/ |_ "<<std::endl
968 <<" / \\| |/ \\_/ __ \\ __\\/ __ \\ / ___/\\ __\\"<<std::endl
969 <<"| Y Y \\ | | \\ ___/| | \\ ___/ \\___ \\ | | "<<std::endl
970 <<"|__|_| /__|___| /\\___ >__| \\___ >____ > |__| "<<std::endl
971 <<" \\/ \\/ \\/ \\/ \\/ "<<std::endl;
972 actionstream<<"World at ["<<m_path_world<<"]"<<std::endl;
973 actionstream<<"Server for gameid=\""<<m_gamespec.id
974 <<"\" listening on port "<<port<<"."<<std::endl;
979 DSTACK(__FUNCTION_NAME);
981 infostream<<"Server: Stopping and waiting threads"<<std::endl;
983 // Stop threads (set run=false first so both start stopping)
984 m_thread.setRun(false);
985 //m_emergethread.setRun(false);
987 //m_emergethread.stop();
989 infostream<<"Server: Threads stopped"<<std::endl;
992 void Server::step(float dtime)
994 DSTACK(__FUNCTION_NAME);
999 JMutexAutoLock lock(m_step_dtime_mutex);
1000 m_step_dtime += dtime;
1002 // Throw if fatal error occurred in thread
1003 std::string async_err = m_async_fatal_error.get();
1004 if(async_err != ""){
1005 throw ServerError(async_err);
1009 void Server::AsyncRunStep()
1011 DSTACK(__FUNCTION_NAME);
1013 g_profiler->add("Server::AsyncRunStep (num)", 1);
1017 JMutexAutoLock lock1(m_step_dtime_mutex);
1018 dtime = m_step_dtime;
1022 // Send blocks to clients
1029 g_profiler->add("Server::AsyncRunStep with dtime (num)", 1);
1031 //infostream<<"Server steps "<<dtime<<std::endl;
1032 //infostream<<"Server::AsyncRunStep(): dtime="<<dtime<<std::endl;
1035 JMutexAutoLock lock1(m_step_dtime_mutex);
1036 m_step_dtime -= dtime;
1043 m_uptime.set(m_uptime.get() + dtime);
1047 // Process connection's timeouts
1048 JMutexAutoLock lock2(m_con_mutex);
1049 ScopeProfiler sp(g_profiler, "Server: connection timeout processing");
1050 m_con.RunTimeouts(dtime);
1054 // This has to be called so that the client list gets synced
1055 // with the peer list of the connection
1056 handlePeerChanges();
1060 Update time of day and overall game time
1063 JMutexAutoLock envlock(m_env_mutex);
1065 m_env->setTimeOfDaySpeed(g_settings->getFloat("time_speed"));
1068 Send to clients at constant intervals
1071 m_time_of_day_send_timer -= dtime;
1072 if(m_time_of_day_send_timer < 0.0)
1074 m_time_of_day_send_timer = g_settings->getFloat("time_send_interval");
1076 //JMutexAutoLock envlock(m_env_mutex);
1077 JMutexAutoLock conlock(m_con_mutex);
1079 for(std::map<u16, RemoteClient*>::iterator
1080 i = m_clients.begin();
1081 i != m_clients.end(); ++i)
1083 RemoteClient *client = i->second;
1084 SharedBuffer<u8> data = makePacket_TOCLIENT_TIME_OF_DAY(
1085 m_env->getTimeOfDay(), g_settings->getFloat("time_speed"));
1087 m_con.Send(client->peer_id, 0, data, true);
1093 JMutexAutoLock lock(m_env_mutex);
1095 ScopeProfiler sp(g_profiler, "SEnv step");
1096 ScopeProfiler sp2(g_profiler, "SEnv step avg", SPT_AVG);
1100 const float map_timer_and_unload_dtime = 2.92;
1101 if(m_map_timer_and_unload_interval.step(dtime, map_timer_and_unload_dtime))
1103 JMutexAutoLock lock(m_env_mutex);
1104 // Run Map's timers and unload unused data
1105 ScopeProfiler sp(g_profiler, "Server: map timer and unload");
1106 m_env->getMap().timerUpdate(map_timer_and_unload_dtime,
1107 g_settings->getFloat("server_unload_unused_data_timeout"));
1118 JMutexAutoLock lock(m_env_mutex);
1119 JMutexAutoLock lock2(m_con_mutex);
1121 ScopeProfiler sp(g_profiler, "Server: handle players");
1123 for(std::map<u16, RemoteClient*>::iterator
1124 i = m_clients.begin();
1125 i != m_clients.end(); ++i)
1127 RemoteClient *client = i->second;
1128 PlayerSAO *playersao = getPlayerSAO(client->peer_id);
1129 if(playersao == NULL)
1133 Handle player HPs (die if hp=0)
1135 if(playersao->m_hp_not_sent && g_settings->getBool("enable_damage"))
1137 if(playersao->getHP() == 0)
1138 DiePlayer(client->peer_id);
1140 SendPlayerHP(client->peer_id);
1144 Send player inventories if necessary
1146 if(playersao->m_moved){
1147 SendMovePlayer(client->peer_id);
1148 playersao->m_moved = false;
1150 if(playersao->m_inventory_not_sent){
1151 UpdateCrafting(client->peer_id);
1152 SendInventory(client->peer_id);
1157 /* Transform liquids */
1158 m_liquid_transform_timer += dtime;
1159 if(m_liquid_transform_timer >= m_liquid_transform_every)
1161 m_liquid_transform_timer -= m_liquid_transform_every;
1163 JMutexAutoLock lock(m_env_mutex);
1165 ScopeProfiler sp(g_profiler, "Server: liquid transform");
1167 std::map<v3s16, MapBlock*> modified_blocks;
1168 m_env->getMap().transformLiquids(modified_blocks);
1173 core::map<v3s16, MapBlock*> lighting_modified_blocks;
1174 ServerMap &map = ((ServerMap&)m_env->getMap());
1175 map.updateLighting(modified_blocks, lighting_modified_blocks);
1177 // Add blocks modified by lighting to modified_blocks
1178 for(core::map<v3s16, MapBlock*>::Iterator
1179 i = lighting_modified_blocks.getIterator();
1180 i.atEnd() == false; i++)
1182 MapBlock *block = i.getNode()->getValue();
1183 modified_blocks.insert(block->getPos(), block);
1187 Set the modified blocks unsent for all the clients
1190 JMutexAutoLock lock2(m_con_mutex);
1192 for(std::map<u16, RemoteClient*>::iterator
1193 i = m_clients.begin();
1194 i != m_clients.end(); ++i)
1196 RemoteClient *client = i->second;
1198 if(modified_blocks.size() > 0)
1200 // Remove block from sent history
1201 client->SetBlocksNotSent(modified_blocks);
1206 // Periodically print some info
1208 float &counter = m_print_info_timer;
1214 JMutexAutoLock lock2(m_con_mutex);
1215 m_clients_number = 0;
1216 if(m_clients.size() != 0)
1217 infostream<<"Players:"<<std::endl;
1218 for(std::map<u16, RemoteClient*>::iterator
1219 i = m_clients.begin();
1220 i != m_clients.end(); ++i)
1222 //u16 peer_id = i.getNode()->getKey();
1223 RemoteClient *client = i->second;
1224 Player *player = m_env->getPlayer(client->peer_id);
1227 infostream<<"* "<<player->getName()<<"\t";
1228 client->PrintInfo(infostream);
1236 // send masterserver announce
1238 float &counter = m_masterserver_timer;
1239 if((!counter || counter >= 300.0) && g_settings->getBool("server_announce") == true)
1241 ServerList::sendAnnounce(!counter ? "start" : "update", m_clients_number, m_uptime.get(), m_gamespec.id);
1248 //if(g_settings->getBool("enable_experimental"))
1252 Check added and deleted active objects
1255 //infostream<<"Server: Checking added and deleted active objects"<<std::endl;
1256 JMutexAutoLock envlock(m_env_mutex);
1257 JMutexAutoLock conlock(m_con_mutex);
1259 ScopeProfiler sp(g_profiler, "Server: checking added and deleted objs");
1261 // Radius inside which objects are active
1262 s16 radius = g_settings->getS16("active_object_send_range_blocks");
1263 radius *= MAP_BLOCKSIZE;
1265 for(std::map<u16, RemoteClient*>::iterator
1266 i = m_clients.begin();
1267 i != m_clients.end(); ++i)
1269 RemoteClient *client = i->second;
1271 // If definitions and textures have not been sent, don't
1272 // send objects either
1273 if(!client->definitions_sent)
1276 Player *player = m_env->getPlayer(client->peer_id);
1279 // This can happen if the client timeouts somehow
1280 /*infostream<<"WARNING: "<<__FUNCTION_NAME<<": Client "
1282 <<" has no associated player"<<std::endl;*/
1285 v3s16 pos = floatToInt(player->getPosition(), BS);
1287 std::set<u16> removed_objects;
1288 std::set<u16> added_objects;
1289 m_env->getRemovedActiveObjects(pos, radius,
1290 client->m_known_objects, removed_objects);
1291 m_env->getAddedActiveObjects(pos, radius,
1292 client->m_known_objects, added_objects);
1294 // Ignore if nothing happened
1295 if(removed_objects.size() == 0 && added_objects.size() == 0)
1297 //infostream<<"active objects: none changed"<<std::endl;
1301 std::string data_buffer;
1305 // Handle removed objects
1306 writeU16((u8*)buf, removed_objects.size());
1307 data_buffer.append(buf, 2);
1308 for(std::set<u16>::iterator
1309 i = removed_objects.begin();
1310 i != removed_objects.end(); ++i)
1314 ServerActiveObject* obj = m_env->getActiveObject(id);
1316 // Add to data buffer for sending
1317 writeU16((u8*)buf, id);
1318 data_buffer.append(buf, 2);
1320 // Remove from known objects
1321 client->m_known_objects.erase(id);
1323 if(obj && obj->m_known_by_count > 0)
1324 obj->m_known_by_count--;
1327 // Handle added objects
1328 writeU16((u8*)buf, added_objects.size());
1329 data_buffer.append(buf, 2);
1330 for(std::set<u16>::iterator
1331 i = added_objects.begin();
1332 i != added_objects.end(); ++i)
1336 ServerActiveObject* obj = m_env->getActiveObject(id);
1339 u8 type = ACTIVEOBJECT_TYPE_INVALID;
1341 infostream<<"WARNING: "<<__FUNCTION_NAME
1342 <<": NULL object"<<std::endl;
1344 type = obj->getSendType();
1346 // Add to data buffer for sending
1347 writeU16((u8*)buf, id);
1348 data_buffer.append(buf, 2);
1349 writeU8((u8*)buf, type);
1350 data_buffer.append(buf, 1);
1353 data_buffer.append(serializeLongString(
1354 obj->getClientInitializationData(client->net_proto_version)));
1356 data_buffer.append(serializeLongString(""));
1358 // Add to known objects
1359 client->m_known_objects.insert(id);
1362 obj->m_known_by_count++;
1366 SharedBuffer<u8> reply(2 + data_buffer.size());
1367 writeU16(&reply[0], TOCLIENT_ACTIVE_OBJECT_REMOVE_ADD);
1368 memcpy((char*)&reply[2], data_buffer.c_str(),
1369 data_buffer.size());
1371 m_con.Send(client->peer_id, 0, reply, true);
1373 verbosestream<<"Server: Sent object remove/add: "
1374 <<removed_objects.size()<<" removed, "
1375 <<added_objects.size()<<" added, "
1376 <<"packet size is "<<reply.getSize()<<std::endl;
1381 Collect a list of all the objects known by the clients
1382 and report it back to the environment.
1385 core::map<u16, bool> all_known_objects;
1387 for(core::map<u16, RemoteClient*>::Iterator
1388 i = m_clients.getIterator();
1389 i.atEnd() == false; i++)
1391 RemoteClient *client = i.getNode()->getValue();
1392 // Go through all known objects of client
1393 for(core::map<u16, bool>::Iterator
1394 i = client->m_known_objects.getIterator();
1395 i.atEnd()==false; i++)
1397 u16 id = i.getNode()->getKey();
1398 all_known_objects[id] = true;
1402 m_env->setKnownActiveObjects(whatever);
1408 Send object messages
1411 JMutexAutoLock envlock(m_env_mutex);
1412 JMutexAutoLock conlock(m_con_mutex);
1414 ScopeProfiler sp(g_profiler, "Server: sending object messages");
1417 // Value = data sent by object
1418 std::map<u16, std::list<ActiveObjectMessage>* > buffered_messages;
1420 // Get active object messages from environment
1423 ActiveObjectMessage aom = m_env->getActiveObjectMessage();
1427 std::list<ActiveObjectMessage>* message_list = NULL;
1428 std::map<u16, std::list<ActiveObjectMessage>* >::iterator n;
1429 n = buffered_messages.find(aom.id);
1430 if(n == buffered_messages.end())
1432 message_list = new std::list<ActiveObjectMessage>;
1433 buffered_messages[aom.id] = message_list;
1437 message_list = n->second;
1439 message_list->push_back(aom);
1442 // Route data to every client
1443 for(std::map<u16, RemoteClient*>::iterator
1444 i = m_clients.begin();
1445 i != m_clients.end(); ++i)
1447 RemoteClient *client = i->second;
1448 std::string reliable_data;
1449 std::string unreliable_data;
1450 // Go through all objects in message buffer
1451 for(std::map<u16, std::list<ActiveObjectMessage>* >::iterator
1452 j = buffered_messages.begin();
1453 j != buffered_messages.end(); ++j)
1455 // If object is not known by client, skip it
1457 if(client->m_known_objects.find(id) == client->m_known_objects.end())
1459 // Get message list of object
1460 std::list<ActiveObjectMessage>* list = j->second;
1461 // Go through every message
1462 for(std::list<ActiveObjectMessage>::iterator
1463 k = list->begin(); k != list->end(); ++k)
1465 // Compose the full new data with header
1466 ActiveObjectMessage aom = *k;
1467 std::string new_data;
1470 writeU16((u8*)&buf[0], aom.id);
1471 new_data.append(buf, 2);
1473 new_data += serializeString(aom.datastring);
1474 // Add data to buffer
1476 reliable_data += new_data;
1478 unreliable_data += new_data;
1482 reliable_data and unreliable_data are now ready.
1485 if(reliable_data.size() > 0)
1487 SharedBuffer<u8> reply(2 + reliable_data.size());
1488 writeU16(&reply[0], TOCLIENT_ACTIVE_OBJECT_MESSAGES);
1489 memcpy((char*)&reply[2], reliable_data.c_str(),
1490 reliable_data.size());
1492 m_con.Send(client->peer_id, 0, reply, true);
1494 if(unreliable_data.size() > 0)
1496 SharedBuffer<u8> reply(2 + unreliable_data.size());
1497 writeU16(&reply[0], TOCLIENT_ACTIVE_OBJECT_MESSAGES);
1498 memcpy((char*)&reply[2], unreliable_data.c_str(),
1499 unreliable_data.size());
1500 // Send as unreliable
1501 m_con.Send(client->peer_id, 0, reply, false);
1504 /*if(reliable_data.size() > 0 || unreliable_data.size() > 0)
1506 infostream<<"Server: Size of object message data: "
1507 <<"reliable: "<<reliable_data.size()
1508 <<", unreliable: "<<unreliable_data.size()
1513 // Clear buffered_messages
1514 for(std::map<u16, std::list<ActiveObjectMessage>* >::iterator
1515 i = buffered_messages.begin();
1516 i != buffered_messages.end(); ++i)
1522 } // enable_experimental
1525 Send queued-for-sending map edit events.
1528 // We will be accessing the environment and the connection
1529 JMutexAutoLock lock(m_env_mutex);
1530 JMutexAutoLock conlock(m_con_mutex);
1532 // Don't send too many at a time
1535 // Single change sending is disabled if queue size is not small
1536 bool disable_single_change_sending = false;
1537 if(m_unsent_map_edit_queue.size() >= 4)
1538 disable_single_change_sending = true;
1540 int event_count = m_unsent_map_edit_queue.size();
1542 // We'll log the amount of each
1545 while(m_unsent_map_edit_queue.size() != 0)
1547 MapEditEvent* event = m_unsent_map_edit_queue.pop_front();
1549 // Players far away from the change are stored here.
1550 // Instead of sending the changes, MapBlocks are set not sent
1552 std::list<u16> far_players;
1554 if(event->type == MEET_ADDNODE)
1556 //infostream<<"Server: MEET_ADDNODE"<<std::endl;
1557 prof.add("MEET_ADDNODE", 1);
1558 if(disable_single_change_sending)
1559 sendAddNode(event->p, event->n, event->already_known_by_peer,
1562 sendAddNode(event->p, event->n, event->already_known_by_peer,
1565 else if(event->type == MEET_REMOVENODE)
1567 //infostream<<"Server: MEET_REMOVENODE"<<std::endl;
1568 prof.add("MEET_REMOVENODE", 1);
1569 if(disable_single_change_sending)
1570 sendRemoveNode(event->p, event->already_known_by_peer,
1573 sendRemoveNode(event->p, event->already_known_by_peer,
1576 else if(event->type == MEET_BLOCK_NODE_METADATA_CHANGED)
1578 infostream<<"Server: MEET_BLOCK_NODE_METADATA_CHANGED"<<std::endl;
1579 prof.add("MEET_BLOCK_NODE_METADATA_CHANGED", 1);
1580 setBlockNotSent(event->p);
1582 else if(event->type == MEET_OTHER)
1584 infostream<<"Server: MEET_OTHER"<<std::endl;
1585 prof.add("MEET_OTHER", 1);
1586 for(std::set<v3s16>::iterator
1587 i = event->modified_blocks.begin();
1588 i != event->modified_blocks.end(); ++i)
1590 setBlockNotSent(*i);
1595 prof.add("unknown", 1);
1596 infostream<<"WARNING: Server: Unknown MapEditEvent "
1597 <<((u32)event->type)<<std::endl;
1601 Set blocks not sent to far players
1603 if(far_players.size() > 0)
1605 // Convert list format to that wanted by SetBlocksNotSent
1606 std::map<v3s16, MapBlock*> modified_blocks2;
1607 for(std::set<v3s16>::iterator
1608 i = event->modified_blocks.begin();
1609 i != event->modified_blocks.end(); ++i)
1611 modified_blocks2[*i] =
1612 m_env->getMap().getBlockNoCreateNoEx(*i);
1614 // Set blocks not sent
1615 for(std::list<u16>::iterator
1616 i = far_players.begin();
1617 i != far_players.end(); ++i)
1620 RemoteClient *client = getClient(peer_id);
1623 client->SetBlocksNotSent(modified_blocks2);
1629 /*// Don't send too many at a time
1631 if(count >= 1 && m_unsent_map_edit_queue.size() < 100)
1635 if(event_count >= 5){
1636 infostream<<"Server: MapEditEvents:"<<std::endl;
1637 prof.print(infostream);
1638 } else if(event_count != 0){
1639 verbosestream<<"Server: MapEditEvents:"<<std::endl;
1640 prof.print(verbosestream);
1646 Trigger emergethread (it somehow gets to a non-triggered but
1647 bysy state sometimes)
1650 float &counter = m_emergethread_trigger_timer;
1656 for (unsigned int i = 0; i != m_emerge->emergethread.size(); i++)
1657 m_emerge->emergethread[i]->trigger();
1659 // Update m_enable_rollback_recording here too
1660 m_enable_rollback_recording =
1661 g_settings->getBool("enable_rollback_recording");
1665 // Save map, players and auth stuff
1667 float &counter = m_savemap_timer;
1669 if(counter >= g_settings->getFloat("server_map_save_interval"))
1672 JMutexAutoLock lock(m_env_mutex);
1674 ScopeProfiler sp(g_profiler, "Server: saving stuff");
1677 if(m_banmanager.isModified())
1678 m_banmanager.save();
1680 // Save changed parts of map
1681 m_env->getMap().save(MOD_STATE_WRITE_NEEDED);
1684 m_env->serializePlayers(m_path_world);
1686 // Save environment metadata
1687 m_env->saveMeta(m_path_world);
1692 void Server::Receive()
1694 DSTACK(__FUNCTION_NAME);
1695 SharedBuffer<u8> data;
1700 JMutexAutoLock conlock(m_con_mutex);
1701 datasize = m_con.Receive(peer_id, data);
1704 // This has to be called so that the client list gets synced
1705 // with the peer list of the connection
1706 handlePeerChanges();
1708 ProcessData(*data, datasize, peer_id);
1710 catch(con::InvalidIncomingDataException &e)
1712 infostream<<"Server::Receive(): "
1713 "InvalidIncomingDataException: what()="
1714 <<e.what()<<std::endl;
1716 catch(con::PeerNotFoundException &e)
1718 //NOTE: This is not needed anymore
1720 // The peer has been disconnected.
1721 // Find the associated player and remove it.
1723 /*JMutexAutoLock envlock(m_env_mutex);
1725 infostream<<"ServerThread: peer_id="<<peer_id
1726 <<" has apparently closed connection. "
1727 <<"Removing player."<<std::endl;
1729 m_env->removePlayer(peer_id);*/
1733 void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
1735 DSTACK(__FUNCTION_NAME);
1736 // Environment is locked first.
1737 JMutexAutoLock envlock(m_env_mutex);
1738 JMutexAutoLock conlock(m_con_mutex);
1740 ScopeProfiler sp(g_profiler, "Server::ProcessData");
1743 Address address = m_con.GetPeerAddress(peer_id);
1744 std::string addr_s = address.serializeString();
1746 // drop player if is ip is banned
1747 if(m_banmanager.isIpBanned(addr_s)){
1748 infostream<<"Server: A banned client tried to connect from "
1749 <<addr_s<<"; banned name was "
1750 <<m_banmanager.getBanName(addr_s)<<std::endl;
1751 // This actually doesn't seem to transfer to the client
1752 SendAccessDenied(m_con, peer_id,
1753 L"Your ip is banned. Banned name was "
1754 +narrow_to_wide(m_banmanager.getBanName(addr_s)));
1755 m_con.DeletePeer(peer_id);
1759 catch(con::PeerNotFoundException &e)
1761 infostream<<"Server::ProcessData(): Cancelling: peer "
1762 <<peer_id<<" not found"<<std::endl;
1766 std::string addr_s = m_con.GetPeerAddress(peer_id).serializeString();
1768 u8 peer_ser_ver = getClient(peer_id)->serialization_version;
1776 ToServerCommand command = (ToServerCommand)readU16(&data[0]);
1778 if(command == TOSERVER_INIT)
1780 // [0] u16 TOSERVER_INIT
1781 // [2] u8 SER_FMT_VER_HIGHEST
1782 // [3] u8[20] player_name
1783 // [23] u8[28] password <--- can be sent without this, from old versions
1785 if(datasize < 2+1+PLAYERNAME_SIZE)
1788 verbosestream<<"Server: Got TOSERVER_INIT from "
1789 <<peer_id<<std::endl;
1791 // First byte after command is maximum supported
1792 // serialization version
1793 u8 client_max = data[2];
1794 u8 our_max = SER_FMT_VER_HIGHEST;
1795 // Use the highest version supported by both
1796 u8 deployed = std::min(client_max, our_max);
1797 // If it's lower than the lowest supported, give up.
1798 if(deployed < SER_FMT_VER_LOWEST)
1799 deployed = SER_FMT_VER_INVALID;
1801 //peer->serialization_version = deployed;
1802 getClient(peer_id)->pending_serialization_version = deployed;
1804 if(deployed == SER_FMT_VER_INVALID)
1806 actionstream<<"Server: A mismatched client tried to connect from "
1807 <<addr_s<<std::endl;
1808 infostream<<"Server: Cannot negotiate "
1809 "serialization version with peer "
1810 <<peer_id<<std::endl;
1811 SendAccessDenied(m_con, peer_id, std::wstring(
1812 L"Your client's version is not supported.\n"
1813 L"Server version is ")
1814 + narrow_to_wide(VERSION_STRING) + L"."
1820 Read and check network protocol version
1823 u16 min_net_proto_version = 0;
1824 if(datasize >= 2+1+PLAYERNAME_SIZE+PASSWORD_SIZE+2)
1825 min_net_proto_version = readU16(&data[2+1+PLAYERNAME_SIZE+PASSWORD_SIZE]);
1827 // Use same version as minimum and maximum if maximum version field
1828 // doesn't exist (backwards compatibility)
1829 u16 max_net_proto_version = min_net_proto_version;
1830 if(datasize >= 2+1+PLAYERNAME_SIZE+PASSWORD_SIZE+2+2)
1831 max_net_proto_version = readU16(&data[2+1+PLAYERNAME_SIZE+PASSWORD_SIZE+2]);
1833 // Start with client's maximum version
1834 u16 net_proto_version = max_net_proto_version;
1836 // Figure out a working version if it is possible at all
1837 if(max_net_proto_version >= SERVER_PROTOCOL_VERSION_MIN ||
1838 min_net_proto_version <= SERVER_PROTOCOL_VERSION_MAX)
1840 // If maximum is larger than our maximum, go with our maximum
1841 if(max_net_proto_version > SERVER_PROTOCOL_VERSION_MAX)
1842 net_proto_version = SERVER_PROTOCOL_VERSION_MAX;
1843 // Else go with client's maximum
1845 net_proto_version = max_net_proto_version;
1848 verbosestream<<"Server: "<<peer_id<<" Protocol version: min: "
1849 <<min_net_proto_version<<", max: "<<max_net_proto_version
1850 <<", chosen: "<<net_proto_version<<std::endl;
1852 getClient(peer_id)->net_proto_version = net_proto_version;
1854 if(net_proto_version < SERVER_PROTOCOL_VERSION_MIN ||
1855 net_proto_version > SERVER_PROTOCOL_VERSION_MAX)
1857 actionstream<<"Server: A mismatched client tried to connect from "<<addr_s
1859 SendAccessDenied(m_con, peer_id, std::wstring(
1860 L"Your client's version is not supported.\n"
1861 L"Server version is ")
1862 + narrow_to_wide(VERSION_STRING) + L",\n"
1863 + L"server's PROTOCOL_VERSION is "
1864 + narrow_to_wide(itos(SERVER_PROTOCOL_VERSION_MIN))
1866 + narrow_to_wide(itos(SERVER_PROTOCOL_VERSION_MAX))
1867 + L", client's PROTOCOL_VERSION is "
1868 + narrow_to_wide(itos(min_net_proto_version))
1870 + narrow_to_wide(itos(max_net_proto_version))
1875 if(g_settings->getBool("strict_protocol_version_checking"))
1877 if(net_proto_version != LATEST_PROTOCOL_VERSION)
1879 actionstream<<"Server: A mismatched (strict) client tried to "
1880 <<"connect from "<<addr_s<<std::endl;
1881 SendAccessDenied(m_con, peer_id, std::wstring(
1882 L"Your client's version is not supported.\n"
1883 L"Server version is ")
1884 + narrow_to_wide(VERSION_STRING) + L",\n"
1885 + L"server's PROTOCOL_VERSION (strict) is "
1886 + narrow_to_wide(itos(LATEST_PROTOCOL_VERSION))
1887 + L", client's PROTOCOL_VERSION is "
1888 + narrow_to_wide(itos(min_net_proto_version))
1890 + narrow_to_wide(itos(max_net_proto_version))
1901 char playername[PLAYERNAME_SIZE];
1902 for(u32 i=0; i<PLAYERNAME_SIZE-1; i++)
1904 playername[i] = data[3+i];
1906 playername[PLAYERNAME_SIZE-1] = 0;
1908 if(playername[0]=='\0')
1910 actionstream<<"Server: Player with an empty name "
1911 <<"tried to connect from "<<addr_s<<std::endl;
1912 SendAccessDenied(m_con, peer_id,
1917 if(string_allowed(playername, PLAYERNAME_ALLOWED_CHARS)==false)
1919 actionstream<<"Server: Player with an invalid name "
1920 <<"tried to connect from "<<addr_s<<std::endl;
1921 SendAccessDenied(m_con, peer_id,
1922 L"Name contains unallowed characters");
1926 infostream<<"Server: New connection: \""<<playername<<"\" from "
1927 <<m_con.GetPeerAddress(peer_id).serializeString()<<std::endl;
1930 char given_password[PASSWORD_SIZE];
1931 if(datasize < 2+1+PLAYERNAME_SIZE+PASSWORD_SIZE)
1933 // old version - assume blank password
1934 given_password[0] = 0;
1938 for(u32 i=0; i<PASSWORD_SIZE-1; i++)
1940 given_password[i] = data[23+i];
1942 given_password[PASSWORD_SIZE-1] = 0;
1945 if(!base64_is_valid(given_password)){
1946 infostream<<"Server: "<<playername
1947 <<" supplied invalid password hash"<<std::endl;
1948 SendAccessDenied(m_con, peer_id, L"Invalid password hash");
1952 std::string checkpwd; // Password hash to check against
1953 bool has_auth = scriptapi_get_auth(m_lua, playername, &checkpwd, NULL);
1955 // If no authentication info exists for user, create it
1957 if(!isSingleplayer() &&
1958 g_settings->getBool("disallow_empty_password") &&
1959 std::string(given_password) == ""){
1960 SendAccessDenied(m_con, peer_id, L"Empty passwords are "
1961 L"disallowed. Set a password and try again.");
1964 std::wstring raw_default_password =
1965 narrow_to_wide(g_settings->get("default_password"));
1966 std::string initial_password =
1967 translatePassword(playername, raw_default_password);
1969 // If default_password is empty, allow any initial password
1970 if (raw_default_password.length() == 0)
1971 initial_password = given_password;
1973 scriptapi_create_auth(m_lua, playername, initial_password);
1976 has_auth = scriptapi_get_auth(m_lua, playername, &checkpwd, NULL);
1979 SendAccessDenied(m_con, peer_id, L"Not allowed to login");
1983 if(given_password != checkpwd){
1984 infostream<<"Server: peer_id="<<peer_id
1985 <<": supplied invalid password for "
1986 <<playername<<std::endl;
1987 SendAccessDenied(m_con, peer_id, L"Invalid password");
1991 // Do not allow multiple players in simple singleplayer mode.
1992 // This isn't a perfect way to do it, but will suffice for now.
1993 if(m_simple_singleplayer_mode && m_clients.size() > 1){
1994 infostream<<"Server: Not allowing another client to connect in"
1995 <<" simple singleplayer mode"<<std::endl;
1996 SendAccessDenied(m_con, peer_id,
1997 L"Running in simple singleplayer mode.");
2001 // Enforce user limit.
2002 // Don't enforce for users that have some admin right
2003 if(m_clients.size() >= g_settings->getU16("max_users") &&
2004 !checkPriv(playername, "server") &&
2005 !checkPriv(playername, "ban") &&
2006 !checkPriv(playername, "privs") &&
2007 !checkPriv(playername, "password") &&
2008 playername != g_settings->get("name"))
2010 actionstream<<"Server: "<<playername<<" tried to join, but there"
2011 <<" are already max_users="
2012 <<g_settings->getU16("max_users")<<" players."<<std::endl;
2013 SendAccessDenied(m_con, peer_id, L"Too many users.");
2018 PlayerSAO *playersao = emergePlayer(playername, peer_id);
2020 // If failed, cancel
2021 if(playersao == NULL)
2023 errorstream<<"Server: peer_id="<<peer_id
2024 <<": failed to emerge player"<<std::endl;
2029 Answer with a TOCLIENT_INIT
2032 SharedBuffer<u8> reply(2+1+6+8+4);
2033 writeU16(&reply[0], TOCLIENT_INIT);
2034 writeU8(&reply[2], deployed);
2035 writeV3S16(&reply[2+1], floatToInt(playersao->getPlayer()->getPosition()+v3f(0,BS/2,0), BS));
2036 writeU64(&reply[2+1+6], m_env->getServerMap().getSeed());
2037 writeF1000(&reply[2+1+6+8], g_settings->getFloat("dedicated_server_step"));
2040 m_con.Send(peer_id, 0, reply, true);
2044 Send complete position information
2046 SendMovePlayer(peer_id);
2051 if(command == TOSERVER_INIT2)
2053 verbosestream<<"Server: Got TOSERVER_INIT2 from "
2054 <<peer_id<<std::endl;
2056 Player *player = m_env->getPlayer(peer_id);
2058 verbosestream<<"Server: TOSERVER_INIT2: "
2059 <<"Player not found; ignoring."<<std::endl;
2063 RemoteClient *client = getClient(peer_id);
2064 client->serialization_version =
2065 getClient(peer_id)->pending_serialization_version;
2068 Send some initialization data
2071 infostream<<"Server: Sending content to "
2072 <<getPlayerName(peer_id)<<std::endl;
2074 // Send player movement settings
2075 SendMovement(m_con, peer_id);
2077 // Send item definitions
2078 SendItemDef(m_con, peer_id, m_itemdef, client->net_proto_version);
2080 // Send node definitions
2081 SendNodeDef(m_con, peer_id, m_nodedef, client->net_proto_version);
2083 // Send media announcement
2084 sendMediaAnnouncement(peer_id);
2087 SendPlayerPrivileges(peer_id);
2089 // Send inventory formspec
2090 SendPlayerInventoryFormspec(peer_id);
2093 UpdateCrafting(peer_id);
2094 SendInventory(peer_id);
2097 if(g_settings->getBool("enable_damage"))
2098 SendPlayerHP(peer_id);
2100 // Send detached inventories
2101 sendDetachedInventories(peer_id);
2103 // Show death screen if necessary
2105 SendDeathscreen(m_con, peer_id, false, v3f(0,0,0));
2109 SharedBuffer<u8> data = makePacket_TOCLIENT_TIME_OF_DAY(
2110 m_env->getTimeOfDay(), g_settings->getFloat("time_speed"));
2111 m_con.Send(peer_id, 0, data, true);
2114 // Note things in chat if not in simple singleplayer mode
2115 if(!m_simple_singleplayer_mode)
2117 // Send information about server to player in chat
2118 SendChatMessage(peer_id, getStatusString());
2120 // Send information about joining in chat
2122 std::wstring name = L"unknown";
2123 Player *player = m_env->getPlayer(peer_id);
2125 name = narrow_to_wide(player->getName());
2127 std::wstring message;
2130 message += L" joined the game.";
2131 BroadcastChatMessage(message);
2135 // Warnings about protocol version can be issued here
2136 if(getClient(peer_id)->net_proto_version < LATEST_PROTOCOL_VERSION)
2138 SendChatMessage(peer_id, L"# Server: WARNING: YOUR CLIENT'S "
2139 L"VERSION MAY NOT BE FULLY COMPATIBLE WITH THIS SERVER!");
2146 std::ostringstream os(std::ios_base::binary);
2147 for(std::map<u16, RemoteClient*>::iterator
2148 i = m_clients.begin();
2149 i != m_clients.end(); ++i)
2151 RemoteClient *client = i->second;
2152 assert(client->peer_id == i->first);
2153 if(client->serialization_version == SER_FMT_VER_INVALID)
2156 Player *player = m_env->getPlayer(client->peer_id);
2159 // Get name of player
2160 os<<player->getName()<<" ";
2163 actionstream<<player->getName()<<" joins game. List of players: "
2164 <<os.str()<<std::endl;
2170 if(peer_ser_ver == SER_FMT_VER_INVALID)
2172 infostream<<"Server::ProcessData(): Cancelling: Peer"
2173 " serialization format invalid or not initialized."
2174 " Skipping incoming command="<<command<<std::endl;
2178 Player *player = m_env->getPlayer(peer_id);
2180 infostream<<"Server::ProcessData(): Cancelling: "
2181 "No player for peer_id="<<peer_id
2186 PlayerSAO *playersao = player->getPlayerSAO();
2187 if(playersao == NULL){
2188 infostream<<"Server::ProcessData(): Cancelling: "
2189 "No player object for peer_id="<<peer_id
2194 if(command == TOSERVER_PLAYERPOS)
2196 if(datasize < 2+12+12+4+4)
2200 v3s32 ps = readV3S32(&data[start+2]);
2201 v3s32 ss = readV3S32(&data[start+2+12]);
2202 f32 pitch = (f32)readS32(&data[2+12+12]) / 100.0;
2203 f32 yaw = (f32)readS32(&data[2+12+12+4]) / 100.0;
2205 if(datasize >= 2+12+12+4+4+4)
2206 keyPressed = (u32)readU32(&data[2+12+12+4+4]);
2207 v3f position((f32)ps.X/100., (f32)ps.Y/100., (f32)ps.Z/100.);
2208 v3f speed((f32)ss.X/100., (f32)ss.Y/100., (f32)ss.Z/100.);
2209 pitch = wrapDegrees(pitch);
2210 yaw = wrapDegrees(yaw);
2212 player->setPosition(position);
2213 player->setSpeed(speed);
2214 player->setPitch(pitch);
2215 player->setYaw(yaw);
2216 player->keyPressed=keyPressed;
2217 player->control.up = (bool)(keyPressed&1);
2218 player->control.down = (bool)(keyPressed&2);
2219 player->control.left = (bool)(keyPressed&4);
2220 player->control.right = (bool)(keyPressed&8);
2221 player->control.jump = (bool)(keyPressed&16);
2222 player->control.aux1 = (bool)(keyPressed&32);
2223 player->control.sneak = (bool)(keyPressed&64);
2224 player->control.LMB = (bool)(keyPressed&128);
2225 player->control.RMB = (bool)(keyPressed&256);
2227 /*infostream<<"Server::ProcessData(): Moved player "<<peer_id<<" to "
2228 <<"("<<position.X<<","<<position.Y<<","<<position.Z<<")"
2229 <<" pitch="<<pitch<<" yaw="<<yaw<<std::endl;*/
2231 else if(command == TOSERVER_GOTBLOCKS)
2244 u16 count = data[2];
2245 for(u16 i=0; i<count; i++)
2247 if((s16)datasize < 2+1+(i+1)*6)
2248 throw con::InvalidIncomingDataException
2249 ("GOTBLOCKS length is too short");
2250 v3s16 p = readV3S16(&data[2+1+i*6]);
2251 /*infostream<<"Server: GOTBLOCKS ("
2252 <<p.X<<","<<p.Y<<","<<p.Z<<")"<<std::endl;*/
2253 RemoteClient *client = getClient(peer_id);
2254 client->GotBlock(p);
2257 else if(command == TOSERVER_DELETEDBLOCKS)
2270 u16 count = data[2];
2271 for(u16 i=0; i<count; i++)
2273 if((s16)datasize < 2+1+(i+1)*6)
2274 throw con::InvalidIncomingDataException
2275 ("DELETEDBLOCKS length is too short");
2276 v3s16 p = readV3S16(&data[2+1+i*6]);
2277 /*infostream<<"Server: DELETEDBLOCKS ("
2278 <<p.X<<","<<p.Y<<","<<p.Z<<")"<<std::endl;*/
2279 RemoteClient *client = getClient(peer_id);
2280 client->SetBlockNotSent(p);
2283 else if(command == TOSERVER_CLICK_OBJECT)
2285 infostream<<"Server: CLICK_OBJECT not supported anymore"<<std::endl;
2288 else if(command == TOSERVER_CLICK_ACTIVEOBJECT)
2290 infostream<<"Server: CLICK_ACTIVEOBJECT not supported anymore"<<std::endl;
2293 else if(command == TOSERVER_GROUND_ACTION)
2295 infostream<<"Server: GROUND_ACTION not supported anymore"<<std::endl;
2299 else if(command == TOSERVER_RELEASE)
2301 infostream<<"Server: RELEASE not supported anymore"<<std::endl;
2304 else if(command == TOSERVER_SIGNTEXT)
2306 infostream<<"Server: SIGNTEXT not supported anymore"
2310 else if(command == TOSERVER_SIGNNODETEXT)
2312 infostream<<"Server: SIGNNODETEXT not supported anymore"
2316 else if(command == TOSERVER_INVENTORY_ACTION)
2318 // Strip command and create a stream
2319 std::string datastring((char*)&data[2], datasize-2);
2320 verbosestream<<"TOSERVER_INVENTORY_ACTION: data="<<datastring<<std::endl;
2321 std::istringstream is(datastring, std::ios_base::binary);
2323 InventoryAction *a = InventoryAction::deSerialize(is);
2326 infostream<<"TOSERVER_INVENTORY_ACTION: "
2327 <<"InventoryAction::deSerialize() returned NULL"
2332 // If something goes wrong, this player is to blame
2333 RollbackScopeActor rollback_scope(m_rollback,
2334 std::string("player:")+player->getName());
2337 Note: Always set inventory not sent, to repair cases
2338 where the client made a bad prediction.
2342 Handle restrictions and special cases of the move action
2344 if(a->getType() == IACTION_MOVE)
2346 IMoveAction *ma = (IMoveAction*)a;
2348 ma->from_inv.applyCurrentPlayer(player->getName());
2349 ma->to_inv.applyCurrentPlayer(player->getName());
2351 setInventoryModified(ma->from_inv);
2352 setInventoryModified(ma->to_inv);
2354 bool from_inv_is_current_player =
2355 (ma->from_inv.type == InventoryLocation::PLAYER) &&
2356 (ma->from_inv.name == player->getName());
2358 bool to_inv_is_current_player =
2359 (ma->to_inv.type == InventoryLocation::PLAYER) &&
2360 (ma->to_inv.name == player->getName());
2363 Disable moving items out of craftpreview
2365 if(ma->from_list == "craftpreview")
2367 infostream<<"Ignoring IMoveAction from "
2368 <<(ma->from_inv.dump())<<":"<<ma->from_list
2369 <<" to "<<(ma->to_inv.dump())<<":"<<ma->to_list
2370 <<" because src is "<<ma->from_list<<std::endl;
2376 Disable moving items into craftresult and craftpreview
2378 if(ma->to_list == "craftpreview" || ma->to_list == "craftresult")
2380 infostream<<"Ignoring IMoveAction from "
2381 <<(ma->from_inv.dump())<<":"<<ma->from_list
2382 <<" to "<<(ma->to_inv.dump())<<":"<<ma->to_list
2383 <<" because dst is "<<ma->to_list<<std::endl;
2388 // Disallow moving items in elsewhere than player's inventory
2389 // if not allowed to interact
2390 if(!checkPriv(player->getName(), "interact") &&
2391 (!from_inv_is_current_player ||
2392 !to_inv_is_current_player))
2394 infostream<<"Cannot move outside of player's inventory: "
2395 <<"No interact privilege"<<std::endl;
2401 Handle restrictions and special cases of the drop action
2403 else if(a->getType() == IACTION_DROP)
2405 IDropAction *da = (IDropAction*)a;
2407 da->from_inv.applyCurrentPlayer(player->getName());
2409 setInventoryModified(da->from_inv);
2411 // Disallow dropping items if not allowed to interact
2412 if(!checkPriv(player->getName(), "interact"))
2419 Handle restrictions and special cases of the craft action
2421 else if(a->getType() == IACTION_CRAFT)
2423 ICraftAction *ca = (ICraftAction*)a;
2425 ca->craft_inv.applyCurrentPlayer(player->getName());
2427 setInventoryModified(ca->craft_inv);
2429 //bool craft_inv_is_current_player =
2430 // (ca->craft_inv.type == InventoryLocation::PLAYER) &&
2431 // (ca->craft_inv.name == player->getName());
2433 // Disallow crafting if not allowed to interact
2434 if(!checkPriv(player->getName(), "interact"))
2436 infostream<<"Cannot craft: "
2437 <<"No interact privilege"<<std::endl;
2444 a->apply(this, playersao, this);
2448 else if(command == TOSERVER_CHAT_MESSAGE)
2456 std::string datastring((char*)&data[2], datasize-2);
2457 std::istringstream is(datastring, std::ios_base::binary);
2460 is.read((char*)buf, 2);
2461 u16 len = readU16(buf);
2463 std::wstring message;
2464 for(u16 i=0; i<len; i++)
2466 is.read((char*)buf, 2);
2467 message += (wchar_t)readU16(buf);
2470 // If something goes wrong, this player is to blame
2471 RollbackScopeActor rollback_scope(m_rollback,
2472 std::string("player:")+player->getName());
2474 // Get player name of this client
2475 std::wstring name = narrow_to_wide(player->getName());
2478 bool ate = scriptapi_on_chat_message(m_lua, player->getName(),
2479 wide_to_narrow(message));
2480 // If script ate the message, don't proceed
2484 // Line to send to players
2486 // Whether to send to the player that sent the line
2487 bool send_to_sender = false;
2488 // Whether to send to other players
2489 bool send_to_others = false;
2491 // Commands are implemented in Lua, so only catch invalid
2492 // commands that were not "eaten" and send an error back
2493 if(message[0] == L'/')
2495 message = message.substr(1);
2496 send_to_sender = true;
2497 if(message.length() == 0)
2498 line += L"-!- Empty command";
2500 line += L"-!- Invalid command: " + str_split(message, L' ')[0];
2504 if(checkPriv(player->getName(), "shout")){
2509 send_to_others = true;
2511 line += L"-!- You don't have permission to shout.";
2512 send_to_sender = true;
2519 actionstream<<"CHAT: "<<wide_to_narrow(line)<<std::endl;
2522 Send the message to clients
2524 for(std::map<u16, RemoteClient*>::iterator
2525 i = m_clients.begin();
2526 i != m_clients.end(); ++i)
2528 // Get client and check that it is valid
2529 RemoteClient *client = i->second;
2530 assert(client->peer_id == i->first);
2531 if(client->serialization_version == SER_FMT_VER_INVALID)
2535 bool sender_selected = (peer_id == client->peer_id);
2536 if(sender_selected == true && send_to_sender == false)
2538 if(sender_selected == false && send_to_others == false)
2541 SendChatMessage(client->peer_id, line);
2545 else if(command == TOSERVER_DAMAGE)
2547 std::string datastring((char*)&data[2], datasize-2);
2548 std::istringstream is(datastring, std::ios_base::binary);
2549 u8 damage = readU8(is);
2551 if(g_settings->getBool("enable_damage"))
2553 actionstream<<player->getName()<<" damaged by "
2554 <<(int)damage<<" hp at "<<PP(player->getPosition()/BS)
2557 playersao->setHP(playersao->getHP() - damage);
2559 if(playersao->getHP() == 0 && playersao->m_hp_not_sent)
2562 if(playersao->m_hp_not_sent)
2563 SendPlayerHP(peer_id);
2566 else if(command == TOSERVER_PASSWORD)
2569 [0] u16 TOSERVER_PASSWORD
2570 [2] u8[28] old password
2571 [30] u8[28] new password
2574 if(datasize != 2+PASSWORD_SIZE*2)
2576 /*char password[PASSWORD_SIZE];
2577 for(u32 i=0; i<PASSWORD_SIZE-1; i++)
2578 password[i] = data[2+i];
2579 password[PASSWORD_SIZE-1] = 0;*/
2581 for(u32 i=0; i<PASSWORD_SIZE-1; i++)
2589 for(u32 i=0; i<PASSWORD_SIZE-1; i++)
2591 char c = data[2+PASSWORD_SIZE+i];
2597 if(!base64_is_valid(newpwd)){
2598 infostream<<"Server: "<<player->getName()<<" supplied invalid password hash"<<std::endl;
2599 // Wrong old password supplied!!
2600 SendChatMessage(peer_id, L"Invalid new password hash supplied. Password NOT changed.");
2604 infostream<<"Server: Client requests a password change from "
2605 <<"'"<<oldpwd<<"' to '"<<newpwd<<"'"<<std::endl;
2607 std::string playername = player->getName();
2609 std::string checkpwd;
2610 scriptapi_get_auth(m_lua, playername, &checkpwd, NULL);
2612 if(oldpwd != checkpwd)
2614 infostream<<"Server: invalid old password"<<std::endl;
2615 // Wrong old password supplied!!
2616 SendChatMessage(peer_id, L"Invalid old password supplied. Password NOT changed.");
2620 bool success = scriptapi_set_password(m_lua, playername, newpwd);
2622 actionstream<<player->getName()<<" changes password"<<std::endl;
2623 SendChatMessage(peer_id, L"Password change successful.");
2625 actionstream<<player->getName()<<" tries to change password but "
2626 <<"it fails"<<std::endl;
2627 SendChatMessage(peer_id, L"Password change failed or inavailable.");
2630 else if(command == TOSERVER_PLAYERITEM)
2635 u16 item = readU16(&data[2]);
2636 playersao->setWieldIndex(item);
2638 else if(command == TOSERVER_RESPAWN)
2640 if(player->hp != 0 || !g_settings->getBool("enable_damage"))
2643 RespawnPlayer(peer_id);
2645 actionstream<<player->getName()<<" respawns at "
2646 <<PP(player->getPosition()/BS)<<std::endl;
2648 // ActiveObject is added to environment in AsyncRunStep after
2649 // the previous addition has been succesfully removed
2651 else if(command == TOSERVER_REQUEST_MEDIA) {
2652 std::string datastring((char*)&data[2], datasize-2);
2653 std::istringstream is(datastring, std::ios_base::binary);
2655 std::list<MediaRequest> tosend;
2656 u16 numfiles = readU16(is);
2658 infostream<<"Sending "<<numfiles<<" files to "
2659 <<getPlayerName(peer_id)<<std::endl;
2660 verbosestream<<"TOSERVER_REQUEST_MEDIA: "<<std::endl;
2662 for(int i = 0; i < numfiles; i++) {
2663 std::string name = deSerializeString(is);
2664 tosend.push_back(MediaRequest(name));
2665 verbosestream<<"TOSERVER_REQUEST_MEDIA: requested file "
2669 sendRequestedMedia(peer_id, tosend);
2671 // Now the client should know about everything
2672 // (definitions and files)
2673 getClient(peer_id)->definitions_sent = true;
2675 else if(command == TOSERVER_RECEIVED_MEDIA) {
2676 getClient(peer_id)->definitions_sent = true;
2678 else if(command == TOSERVER_INTERACT)
2680 std::string datastring((char*)&data[2], datasize-2);
2681 std::istringstream is(datastring, std::ios_base::binary);
2687 [5] u32 length of the next item
2688 [9] serialized PointedThing
2690 0: start digging (from undersurface) or use
2691 1: stop digging (all parameters ignored)
2692 2: digging completed
2693 3: place block or item (to abovesurface)
2696 u8 action = readU8(is);
2697 u16 item_i = readU16(is);
2698 std::istringstream tmp_is(deSerializeLongString(is), std::ios::binary);
2699 PointedThing pointed;
2700 pointed.deSerialize(tmp_is);
2702 verbosestream<<"TOSERVER_INTERACT: action="<<(int)action<<", item="
2703 <<item_i<<", pointed="<<pointed.dump()<<std::endl;
2707 verbosestream<<"TOSERVER_INTERACT: "<<player->getName()
2708 <<" tried to interact, but is dead!"<<std::endl;
2712 v3f player_pos = playersao->getLastGoodPosition();
2714 // Update wielded item
2715 playersao->setWieldIndex(item_i);
2717 // Get pointed to node (undefined if not POINTEDTYPE_NODE)
2718 v3s16 p_under = pointed.node_undersurface;
2719 v3s16 p_above = pointed.node_abovesurface;
2721 // Get pointed to object (NULL if not POINTEDTYPE_OBJECT)
2722 ServerActiveObject *pointed_object = NULL;
2723 if(pointed.type == POINTEDTHING_OBJECT)
2725 pointed_object = m_env->getActiveObject(pointed.object_id);
2726 if(pointed_object == NULL)
2728 verbosestream<<"TOSERVER_INTERACT: "
2729 "pointed object is NULL"<<std::endl;
2735 v3f pointed_pos_under = player_pos;
2736 v3f pointed_pos_above = player_pos;
2737 if(pointed.type == POINTEDTHING_NODE)
2739 pointed_pos_under = intToFloat(p_under, BS);
2740 pointed_pos_above = intToFloat(p_above, BS);
2742 else if(pointed.type == POINTEDTHING_OBJECT)
2744 pointed_pos_under = pointed_object->getBasePosition();
2745 pointed_pos_above = pointed_pos_under;
2749 Check that target is reasonably close
2750 (only when digging or placing things)
2752 if(action == 0 || action == 2 || action == 3)
2754 float d = player_pos.getDistanceFrom(pointed_pos_under);
2755 float max_d = BS * 14; // Just some large enough value
2757 actionstream<<"Player "<<player->getName()
2758 <<" tried to access "<<pointed.dump()
2760 <<"d="<<d<<", max_d="<<max_d
2761 <<". ignoring."<<std::endl;
2762 // Re-send block to revert change on client-side
2763 RemoteClient *client = getClient(peer_id);
2764 v3s16 blockpos = getNodeBlockPos(floatToInt(pointed_pos_under, BS));
2765 client->SetBlockNotSent(blockpos);
2772 Make sure the player is allowed to do it
2774 if(!checkPriv(player->getName(), "interact"))
2776 actionstream<<player->getName()<<" attempted to interact with "
2777 <<pointed.dump()<<" without 'interact' privilege"
2779 // Re-send block to revert change on client-side
2780 RemoteClient *client = getClient(peer_id);
2781 // Digging completed -> under
2783 v3s16 blockpos = getNodeBlockPos(floatToInt(pointed_pos_under, BS));
2784 client->SetBlockNotSent(blockpos);
2786 // Placement -> above
2788 v3s16 blockpos = getNodeBlockPos(floatToInt(pointed_pos_above, BS));
2789 client->SetBlockNotSent(blockpos);
2795 If something goes wrong, this player is to blame
2797 RollbackScopeActor rollback_scope(m_rollback,
2798 std::string("player:")+player->getName());
2801 0: start digging or punch object
2805 if(pointed.type == POINTEDTHING_NODE)
2808 NOTE: This can be used in the future to check if
2809 somebody is cheating, by checking the timing.
2811 MapNode n(CONTENT_IGNORE);
2814 n = m_env->getMap().getNode(p_under);
2816 catch(InvalidPositionException &e)
2818 infostream<<"Server: Not punching: Node not found."
2819 <<" Adding block to emerge queue."
2821 m_emerge->enqueueBlockEmerge(peer_id, getNodeBlockPos(p_above), false);
2823 if(n.getContent() != CONTENT_IGNORE)
2824 scriptapi_node_on_punch(m_lua, p_under, n, playersao);
2826 playersao->noCheatDigStart(p_under);
2828 else if(pointed.type == POINTEDTHING_OBJECT)
2830 // Skip if object has been removed
2831 if(pointed_object->m_removed)
2834 actionstream<<player->getName()<<" punches object "
2835 <<pointed.object_id<<": "
2836 <<pointed_object->getDescription()<<std::endl;
2838 ItemStack punchitem = playersao->getWieldedItem();
2839 ToolCapabilities toolcap =
2840 punchitem.getToolCapabilities(m_itemdef);
2841 v3f dir = (pointed_object->getBasePosition() -
2842 (player->getPosition() + player->getEyeOffset())
2844 float time_from_last_punch =
2845 playersao->resetTimeFromLastPunch();
2846 pointed_object->punch(dir, &toolcap, playersao,
2847 time_from_last_punch);
2855 else if(action == 1)
2860 2: Digging completed
2862 else if(action == 2)
2864 // Only digging of nodes
2865 if(pointed.type == POINTEDTHING_NODE)
2867 MapNode n(CONTENT_IGNORE);
2870 n = m_env->getMap().getNode(p_under);
2872 catch(InvalidPositionException &e)
2874 infostream<<"Server: Not finishing digging: Node not found."
2875 <<" Adding block to emerge queue."
2877 m_emerge->enqueueBlockEmerge(peer_id, getNodeBlockPos(p_above), false);
2880 /* Cheat prevention */
2881 bool is_valid_dig = true;
2882 if(!isSingleplayer() && !g_settings->getBool("disable_anticheat"))
2884 v3s16 nocheat_p = playersao->getNoCheatDigPos();
2885 float nocheat_t = playersao->getNoCheatDigTime();
2886 playersao->noCheatDigEnd();
2887 // If player didn't start digging this, ignore dig
2888 if(nocheat_p != p_under){
2889 infostream<<"Server: NoCheat: "<<player->getName()
2890 <<" started digging "
2891 <<PP(nocheat_p)<<" and completed digging "
2892 <<PP(p_under)<<"; not digging."<<std::endl;
2893 is_valid_dig = false;
2895 // Get player's wielded item
2896 ItemStack playeritem;
2897 InventoryList *mlist = playersao->getInventory()->getList("main");
2899 playeritem = mlist->getItem(playersao->getWieldIndex());
2900 ToolCapabilities playeritem_toolcap =
2901 playeritem.getToolCapabilities(m_itemdef);
2902 // Get diggability and expected digging time
2903 DigParams params = getDigParams(m_nodedef->get(n).groups,
2904 &playeritem_toolcap);
2905 // If can't dig, try hand
2906 if(!params.diggable){
2907 const ItemDefinition &hand = m_itemdef->get("");
2908 const ToolCapabilities *tp = hand.tool_capabilities;
2910 params = getDigParams(m_nodedef->get(n).groups, tp);
2912 // If can't dig, ignore dig
2913 if(!params.diggable){
2914 infostream<<"Server: NoCheat: "<<player->getName()
2915 <<" completed digging "<<PP(p_under)
2916 <<", which is not diggable with tool. not digging."
2918 is_valid_dig = false;
2920 // If time is considerably too short, ignore dig
2921 // Check time only for medium and slow timed digs
2922 if(params.diggable && params.time > 0.3 && nocheat_t < 0.5 * params.time){
2923 infostream<<"Server: NoCheat: "<<player->getName()
2924 <<" completed digging "
2925 <<PP(p_under)<<" in "<<nocheat_t<<"s; expected "
2926 <<params.time<<"s; not digging."<<std::endl;
2927 is_valid_dig = false;
2931 /* Actually dig node */
2933 if(is_valid_dig && n.getContent() != CONTENT_IGNORE)
2934 scriptapi_node_on_dig(m_lua, p_under, n, playersao);
2936 // Send unusual result (that is, node not being removed)
2937 if(m_env->getMap().getNodeNoEx(p_under).getContent() != CONTENT_AIR)
2939 // Re-send block to revert change on client-side
2940 RemoteClient *client = getClient(peer_id);
2941 v3s16 blockpos = getNodeBlockPos(floatToInt(pointed_pos_under, BS));
2942 client->SetBlockNotSent(blockpos);
2948 3: place block or right-click object
2950 else if(action == 3)
2952 ItemStack item = playersao->getWieldedItem();
2954 // Reset build time counter
2955 if(pointed.type == POINTEDTHING_NODE &&
2956 item.getDefinition(m_itemdef).type == ITEM_NODE)
2957 getClient(peer_id)->m_time_from_building = 0.0;
2959 if(pointed.type == POINTEDTHING_OBJECT)
2961 // Right click object
2963 // Skip if object has been removed
2964 if(pointed_object->m_removed)
2967 actionstream<<player->getName()<<" right-clicks object "
2968 <<pointed.object_id<<": "
2969 <<pointed_object->getDescription()<<std::endl;
2972 pointed_object->rightClick(playersao);
2974 else if(scriptapi_item_on_place(m_lua,
2975 item, playersao, pointed))
2977 // Placement was handled in lua
2979 // Apply returned ItemStack
2980 playersao->setWieldedItem(item);
2983 // If item has node placement prediction, always send the
2984 // blocks to make sure the client knows what exactly happened
2985 if(item.getDefinition(m_itemdef).node_placement_prediction != ""){
2986 RemoteClient *client = getClient(peer_id);
2987 v3s16 blockpos = getNodeBlockPos(floatToInt(pointed_pos_above, BS));
2988 client->SetBlockNotSent(blockpos);
2989 v3s16 blockpos2 = getNodeBlockPos(floatToInt(pointed_pos_under, BS));
2990 if(blockpos2 != blockpos){
2991 client->SetBlockNotSent(blockpos2);
2999 else if(action == 4)
3001 ItemStack item = playersao->getWieldedItem();
3003 actionstream<<player->getName()<<" uses "<<item.name
3004 <<", pointing at "<<pointed.dump()<<std::endl;
3006 if(scriptapi_item_on_use(m_lua,
3007 item, playersao, pointed))
3009 // Apply returned ItemStack
3010 playersao->setWieldedItem(item);
3017 Catch invalid actions
3021 infostream<<"WARNING: Server: Invalid action "
3022 <<action<<std::endl;
3025 else if(command == TOSERVER_REMOVED_SOUNDS)
3027 std::string datastring((char*)&data[2], datasize-2);
3028 std::istringstream is(datastring, std::ios_base::binary);
3030 int num = readU16(is);
3031 for(int k=0; k<num; k++){
3032 s32 id = readS32(is);
3033 std::map<s32, ServerPlayingSound>::iterator i =
3034 m_playing_sounds.find(id);
3035 if(i == m_playing_sounds.end())
3037 ServerPlayingSound &psound = i->second;
3038 psound.clients.erase(peer_id);
3039 if(psound.clients.size() == 0)
3040 m_playing_sounds.erase(i++);
3043 else if(command == TOSERVER_NODEMETA_FIELDS)
3045 std::string datastring((char*)&data[2], datasize-2);
3046 std::istringstream is(datastring, std::ios_base::binary);
3048 v3s16 p = readV3S16(is);
3049 std::string formname = deSerializeString(is);
3050 int num = readU16(is);
3051 std::map<std::string, std::string> fields;
3052 for(int k=0; k<num; k++){
3053 std::string fieldname = deSerializeString(is);
3054 std::string fieldvalue = deSerializeLongString(is);
3055 fields[fieldname] = fieldvalue;
3058 // If something goes wrong, this player is to blame
3059 RollbackScopeActor rollback_scope(m_rollback,
3060 std::string("player:")+player->getName());
3062 // Check the target node for rollback data; leave others unnoticed
3063 RollbackNode rn_old(&m_env->getMap(), p, this);
3065 scriptapi_node_on_receive_fields(m_lua, p, formname, fields,
3068 // Report rollback data
3069 RollbackNode rn_new(&m_env->getMap(), p, this);
3070 if(rollback() && rn_new != rn_old){
3071 RollbackAction action;
3072 action.setSetNode(p, rn_old, rn_new);
3073 rollback()->reportAction(action);
3076 else if(command == TOSERVER_INVENTORY_FIELDS)
3078 std::string datastring((char*)&data[2], datasize-2);
3079 std::istringstream is(datastring, std::ios_base::binary);
3081 std::string formname = deSerializeString(is);
3082 int num = readU16(is);
3083 std::map<std::string, std::string> fields;
3084 for(int k=0; k<num; k++){
3085 std::string fieldname = deSerializeString(is);
3086 std::string fieldvalue = deSerializeLongString(is);
3087 fields[fieldname] = fieldvalue;
3090 scriptapi_on_player_receive_fields(m_lua, playersao, formname, fields);
3094 infostream<<"Server::ProcessData(): Ignoring "
3095 "unknown command "<<command<<std::endl;
3099 catch(SendFailedException &e)
3101 errorstream<<"Server::ProcessData(): SendFailedException: "
3107 void Server::onMapEditEvent(MapEditEvent *event)
3109 //infostream<<"Server::onMapEditEvent()"<<std::endl;
3110 if(m_ignore_map_edit_events)
3112 if(m_ignore_map_edit_events_area.contains(event->getArea()))
3114 MapEditEvent *e = event->clone();
3115 m_unsent_map_edit_queue.push_back(e);
3118 Inventory* Server::getInventory(const InventoryLocation &loc)
3121 case InventoryLocation::UNDEFINED:
3124 case InventoryLocation::CURRENT_PLAYER:
3127 case InventoryLocation::PLAYER:
3129 Player *player = m_env->getPlayer(loc.name.c_str());
3132 PlayerSAO *playersao = player->getPlayerSAO();
3135 return playersao->getInventory();
3138 case InventoryLocation::NODEMETA:
3140 NodeMetadata *meta = m_env->getMap().getNodeMetadata(loc.p);
3143 return meta->getInventory();
3146 case InventoryLocation::DETACHED:
3148 if(m_detached_inventories.count(loc.name) == 0)
3150 return m_detached_inventories[loc.name];
3158 void Server::setInventoryModified(const InventoryLocation &loc)
3161 case InventoryLocation::UNDEFINED:
3164 case InventoryLocation::PLAYER:
3166 Player *player = m_env->getPlayer(loc.name.c_str());
3169 PlayerSAO *playersao = player->getPlayerSAO();
3172 playersao->m_inventory_not_sent = true;
3173 playersao->m_wielded_item_not_sent = true;
3176 case InventoryLocation::NODEMETA:
3178 v3s16 blockpos = getNodeBlockPos(loc.p);
3180 MapBlock *block = m_env->getMap().getBlockNoCreateNoEx(blockpos);
3182 block->raiseModified(MOD_STATE_WRITE_NEEDED);
3184 setBlockNotSent(blockpos);
3187 case InventoryLocation::DETACHED:
3189 sendDetachedInventoryToAll(loc.name);
3197 std::list<PlayerInfo> Server::getPlayerInfo()
3199 DSTACK(__FUNCTION_NAME);
3200 JMutexAutoLock envlock(m_env_mutex);
3201 JMutexAutoLock conlock(m_con_mutex);
3203 std::list<PlayerInfo> list;
3205 std::list<Player*> players = m_env->getPlayers();
3207 std::list<Player*>::iterator i;
3208 for(i = players.begin();
3209 i != players.end(); ++i)
3213 Player *player = *i;
3216 // Copy info from connection to info struct
3217 info.id = player->peer_id;
3218 info.address = m_con.GetPeerAddress(player->peer_id);
3219 info.avg_rtt = m_con.GetPeerAvgRTT(player->peer_id);
3221 catch(con::PeerNotFoundException &e)
3223 // Set dummy peer info
3225 info.address = Address(0,0,0,0,0);
3229 snprintf(info.name, PLAYERNAME_SIZE, "%s", player->getName());
3230 info.position = player->getPosition();
3232 list.push_back(info);
3239 void Server::peerAdded(con::Peer *peer)
3241 DSTACK(__FUNCTION_NAME);
3242 verbosestream<<"Server::peerAdded(): peer->id="
3243 <<peer->id<<std::endl;
3246 c.type = PEER_ADDED;
3247 c.peer_id = peer->id;
3249 m_peer_change_queue.push_back(c);
3252 void Server::deletingPeer(con::Peer *peer, bool timeout)
3254 DSTACK(__FUNCTION_NAME);
3255 verbosestream<<"Server::deletingPeer(): peer->id="
3256 <<peer->id<<", timeout="<<timeout<<std::endl;
3259 c.type = PEER_REMOVED;
3260 c.peer_id = peer->id;
3261 c.timeout = timeout;
3262 m_peer_change_queue.push_back(c);
3269 void Server::SendMovement(con::Connection &con, u16 peer_id)
3271 DSTACK(__FUNCTION_NAME);
3272 std::ostringstream os(std::ios_base::binary);
3274 writeU16(os, TOCLIENT_MOVEMENT);
3275 writeF1000(os, g_settings->getFloat("movement_acceleration_default"));
3276 writeF1000(os, g_settings->getFloat("movement_acceleration_air"));
3277 writeF1000(os, g_settings->getFloat("movement_acceleration_fast"));
3278 writeF1000(os, g_settings->getFloat("movement_speed_walk"));
3279 writeF1000(os, g_settings->getFloat("movement_speed_crouch"));
3280 writeF1000(os, g_settings->getFloat("movement_speed_fast"));
3281 writeF1000(os, g_settings->getFloat("movement_speed_climb"));
3282 writeF1000(os, g_settings->getFloat("movement_speed_jump"));
3283 writeF1000(os, g_settings->getFloat("movement_liquid_fluidity"));
3284 writeF1000(os, g_settings->getFloat("movement_liquid_fluidity_smooth"));
3285 writeF1000(os, g_settings->getFloat("movement_liquid_sink"));
3286 writeF1000(os, g_settings->getFloat("movement_gravity"));
3289 std::string s = os.str();
3290 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3292 con.Send(peer_id, 0, data, true);
3295 void Server::SendHP(con::Connection &con, u16 peer_id, u8 hp)
3297 DSTACK(__FUNCTION_NAME);
3298 std::ostringstream os(std::ios_base::binary);
3300 writeU16(os, TOCLIENT_HP);
3304 std::string s = os.str();
3305 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3307 con.Send(peer_id, 0, data, true);
3310 void Server::SendAccessDenied(con::Connection &con, u16 peer_id,
3311 const std::wstring &reason)
3313 DSTACK(__FUNCTION_NAME);
3314 std::ostringstream os(std::ios_base::binary);
3316 writeU16(os, TOCLIENT_ACCESS_DENIED);
3317 os<<serializeWideString(reason);
3320 std::string s = os.str();
3321 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3323 con.Send(peer_id, 0, data, true);
3326 void Server::SendDeathscreen(con::Connection &con, u16 peer_id,
3327 bool set_camera_point_target, v3f camera_point_target)
3329 DSTACK(__FUNCTION_NAME);
3330 std::ostringstream os(std::ios_base::binary);
3332 writeU16(os, TOCLIENT_DEATHSCREEN);
3333 writeU8(os, set_camera_point_target);
3334 writeV3F1000(os, camera_point_target);
3337 std::string s = os.str();
3338 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3340 con.Send(peer_id, 0, data, true);
3343 void Server::SendItemDef(con::Connection &con, u16 peer_id,
3344 IItemDefManager *itemdef, u16 protocol_version)
3346 DSTACK(__FUNCTION_NAME);
3347 std::ostringstream os(std::ios_base::binary);
3351 u32 length of the next item
3352 zlib-compressed serialized ItemDefManager
3354 writeU16(os, TOCLIENT_ITEMDEF);
3355 std::ostringstream tmp_os(std::ios::binary);
3356 itemdef->serialize(tmp_os, protocol_version);
3357 std::ostringstream tmp_os2(std::ios::binary);
3358 compressZlib(tmp_os.str(), tmp_os2);
3359 os<<serializeLongString(tmp_os2.str());
3362 std::string s = os.str();
3363 verbosestream<<"Server: Sending item definitions to id("<<peer_id
3364 <<"): size="<<s.size()<<std::endl;
3365 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3367 con.Send(peer_id, 0, data, true);
3370 void Server::SendNodeDef(con::Connection &con, u16 peer_id,
3371 INodeDefManager *nodedef, u16 protocol_version)
3373 DSTACK(__FUNCTION_NAME);
3374 std::ostringstream os(std::ios_base::binary);
3378 u32 length of the next item
3379 zlib-compressed serialized NodeDefManager
3381 writeU16(os, TOCLIENT_NODEDEF);
3382 std::ostringstream tmp_os(std::ios::binary);
3383 nodedef->serialize(tmp_os, protocol_version);
3384 std::ostringstream tmp_os2(std::ios::binary);
3385 compressZlib(tmp_os.str(), tmp_os2);
3386 os<<serializeLongString(tmp_os2.str());
3389 std::string s = os.str();
3390 verbosestream<<"Server: Sending node definitions to id("<<peer_id
3391 <<"): size="<<s.size()<<std::endl;
3392 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3394 con.Send(peer_id, 0, data, true);
3398 Non-static send methods
3401 void Server::SendInventory(u16 peer_id)
3403 DSTACK(__FUNCTION_NAME);
3405 PlayerSAO *playersao = getPlayerSAO(peer_id);
3408 playersao->m_inventory_not_sent = false;
3414 std::ostringstream os;
3415 playersao->getInventory()->serialize(os);
3417 std::string s = os.str();
3419 SharedBuffer<u8> data(s.size()+2);
3420 writeU16(&data[0], TOCLIENT_INVENTORY);
3421 memcpy(&data[2], s.c_str(), s.size());
3424 m_con.Send(peer_id, 0, data, true);
3427 void Server::SendChatMessage(u16 peer_id, const std::wstring &message)
3429 DSTACK(__FUNCTION_NAME);
3431 std::ostringstream os(std::ios_base::binary);
3435 writeU16(buf, TOCLIENT_CHAT_MESSAGE);
3436 os.write((char*)buf, 2);
3439 writeU16(buf, message.size());
3440 os.write((char*)buf, 2);
3443 for(u32 i=0; i<message.size(); i++)
3447 os.write((char*)buf, 2);
3451 std::string s = os.str();
3452 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3454 m_con.Send(peer_id, 0, data, true);
3457 void Server::SendShowFormspecMessage(u16 peer_id, const std::string formspec,
3458 const std::string formname)
3460 DSTACK(__FUNCTION_NAME);
3462 std::ostringstream os(std::ios_base::binary);
3466 writeU16(buf, TOCLIENT_SHOW_FORMSPEC);
3467 os.write((char*)buf, 2);
3468 os<<serializeLongString(formspec);
3469 os<<serializeString(formname);
3472 std::string s = os.str();
3473 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3475 m_con.Send(peer_id, 0, data, true);
3478 // Spawns a particle on peer with peer_id
3479 void Server::SendSpawnParticle(u16 peer_id, v3f pos, v3f velocity, v3f acceleration,
3480 float expirationtime, float size, bool collisiondetection,
3481 std::string texture)
3483 DSTACK(__FUNCTION_NAME);
3485 std::ostringstream os(std::ios_base::binary);
3486 writeU16(os, TOCLIENT_SPAWN_PARTICLE);
3487 writeV3F1000(os, pos);
3488 writeV3F1000(os, velocity);
3489 writeV3F1000(os, acceleration);
3490 writeF1000(os, expirationtime);
3491 writeF1000(os, size);
3492 writeU8(os, collisiondetection);
3493 os<<serializeLongString(texture);
3496 std::string s = os.str();
3497 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3499 m_con.Send(peer_id, 0, data, true);
3502 // Spawns a particle on all peers
3503 void Server::SendSpawnParticleAll(v3f pos, v3f velocity, v3f acceleration,
3504 float expirationtime, float size, bool collisiondetection,
3505 std::string texture)
3507 for(std::map<u16, RemoteClient*>::iterator
3508 i = m_clients.begin();
3509 i != m_clients.end(); i++)
3511 // Get client and check that it is valid
3512 RemoteClient *client = i->second;
3513 assert(client->peer_id == i->first);
3514 if(client->serialization_version == SER_FMT_VER_INVALID)
3517 SendSpawnParticle(client->peer_id, pos, velocity, acceleration,
3518 expirationtime, size, collisiondetection, texture);
3522 // Adds a ParticleSpawner on peer with peer_id
3523 void Server::SendAddParticleSpawner(u16 peer_id, u16 amount, float spawntime, v3f minpos, v3f maxpos,
3524 v3f minvel, v3f maxvel, v3f minacc, v3f maxacc, float minexptime, float maxexptime,
3525 float minsize, float maxsize, bool collisiondetection, std::string texture, u32 id)
3527 DSTACK(__FUNCTION_NAME);
3529 std::ostringstream os(std::ios_base::binary);
3530 writeU16(os, TOCLIENT_ADD_PARTICLESPAWNER);
3532 writeU16(os, amount);
3533 writeF1000(os, spawntime);
3534 writeV3F1000(os, minpos);
3535 writeV3F1000(os, maxpos);
3536 writeV3F1000(os, minvel);
3537 writeV3F1000(os, maxvel);
3538 writeV3F1000(os, minacc);
3539 writeV3F1000(os, maxacc);
3540 writeF1000(os, minexptime);
3541 writeF1000(os, maxexptime);
3542 writeF1000(os, minsize);
3543 writeF1000(os, maxsize);
3544 writeU8(os, collisiondetection);
3545 os<<serializeLongString(texture);
3549 std::string s = os.str();
3550 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3552 m_con.Send(peer_id, 0, data, true);
3555 // Adds a ParticleSpawner on all peers
3556 void Server::SendAddParticleSpawnerAll(u16 amount, float spawntime, v3f minpos, v3f maxpos,
3557 v3f minvel, v3f maxvel, v3f minacc, v3f maxacc, float minexptime, float maxexptime,
3558 float minsize, float maxsize, bool collisiondetection, std::string texture, u32 id)
3560 for(std::map<u16, RemoteClient*>::iterator
3561 i = m_clients.begin();
3562 i != m_clients.end(); i++)
3564 // Get client and check that it is valid
3565 RemoteClient *client = i->second;
3566 assert(client->peer_id == i->first);
3567 if(client->serialization_version == SER_FMT_VER_INVALID)
3570 SendAddParticleSpawner(client->peer_id, amount, spawntime,
3571 minpos, maxpos, minvel, maxvel, minacc, maxacc,
3572 minexptime, maxexptime, minsize, maxsize, collisiondetection, texture, id);
3576 void Server::SendDeleteParticleSpawner(u16 peer_id, u32 id)
3578 DSTACK(__FUNCTION_NAME);
3580 std::ostringstream os(std::ios_base::binary);
3581 writeU16(os, TOCLIENT_DELETE_PARTICLESPAWNER);
3586 std::string s = os.str();
3587 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3589 m_con.Send(peer_id, 0, data, true);
3592 void Server::SendDeleteParticleSpawnerAll(u32 id)
3594 for(std::map<u16, RemoteClient*>::iterator
3595 i = m_clients.begin();
3596 i != m_clients.end(); i++)
3598 // Get client and check that it is valid
3599 RemoteClient *client = i->second;
3600 assert(client->peer_id == i->first);
3601 if(client->serialization_version == SER_FMT_VER_INVALID)
3604 SendDeleteParticleSpawner(client->peer_id, id);
3608 void Server::SendHUDAdd(u16 peer_id, u32 id, HudElement *form)
3610 std::ostringstream os(std::ios_base::binary);
3613 writeU16(os, TOCLIENT_HUDADD);
3615 writeU8(os, (u8)form->type);
3616 writeV2F1000(os, form->pos);
3617 os << serializeString(form->name);
3618 writeV2F1000(os, form->scale);
3619 os << serializeString(form->text);
3620 writeU32(os, form->number);
3621 writeU32(os, form->item);
3622 writeU32(os, form->dir);
3623 writeV2F1000(os, form->align);
3624 writeV2F1000(os, form->offset);
3627 std::string s = os.str();
3628 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3630 m_con.Send(peer_id, 0, data, true);
3633 void Server::SendHUDRemove(u16 peer_id, u32 id)
3635 std::ostringstream os(std::ios_base::binary);
3638 writeU16(os, TOCLIENT_HUDRM);
3642 std::string s = os.str();
3643 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3645 m_con.Send(peer_id, 0, data, true);
3648 void Server::SendHUDChange(u16 peer_id, u32 id, HudElementStat stat, void *value)
3650 std::ostringstream os(std::ios_base::binary);
3653 writeU16(os, TOCLIENT_HUDCHANGE);
3655 writeU8(os, (u8)stat);
3658 case HUD_STAT_SCALE:
3659 case HUD_STAT_ALIGN:
3660 case HUD_STAT_OFFSET:
3661 writeV2F1000(os, *(v2f *)value);
3665 os << serializeString(*(std::string *)value);
3667 case HUD_STAT_NUMBER:
3671 writeU32(os, *(u32 *)value);
3676 std::string s = os.str();
3677 SharedBuffer<u8> data((u8 *)s.c_str(), s.size());
3679 m_con.Send(peer_id, 0, data, true);
3682 void Server::SendHUDSetFlags(u16 peer_id, u32 flags, u32 mask)
3684 std::ostringstream os(std::ios_base::binary);
3687 writeU16(os, TOCLIENT_HUD_SET_FLAGS);
3688 writeU32(os, flags);
3692 std::string s = os.str();
3693 SharedBuffer<u8> data((u8 *)s.c_str(), s.size());
3695 m_con.Send(peer_id, 0, data, true);
3698 void Server::BroadcastChatMessage(const std::wstring &message)
3700 for(std::map<u16, RemoteClient*>::iterator
3701 i = m_clients.begin();
3702 i != m_clients.end(); ++i)
3704 // Get client and check that it is valid
3705 RemoteClient *client = i->second;
3706 assert(client->peer_id == i->first);
3707 if(client->serialization_version == SER_FMT_VER_INVALID)
3710 SendChatMessage(client->peer_id, message);
3714 void Server::SendPlayerHP(u16 peer_id)
3716 DSTACK(__FUNCTION_NAME);
3717 PlayerSAO *playersao = getPlayerSAO(peer_id);
3719 playersao->m_hp_not_sent = false;
3720 SendHP(m_con, peer_id, playersao->getHP());
3723 void Server::SendMovePlayer(u16 peer_id)
3725 DSTACK(__FUNCTION_NAME);
3726 Player *player = m_env->getPlayer(peer_id);
3729 std::ostringstream os(std::ios_base::binary);
3730 writeU16(os, TOCLIENT_MOVE_PLAYER);
3731 writeV3F1000(os, player->getPosition());
3732 writeF1000(os, player->getPitch());
3733 writeF1000(os, player->getYaw());
3736 v3f pos = player->getPosition();
3737 f32 pitch = player->getPitch();
3738 f32 yaw = player->getYaw();
3739 verbosestream<<"Server: Sending TOCLIENT_MOVE_PLAYER"
3740 <<" pos=("<<pos.X<<","<<pos.Y<<","<<pos.Z<<")"
3747 std::string s = os.str();
3748 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3750 m_con.Send(peer_id, 0, data, true);
3753 void Server::SendPlayerPrivileges(u16 peer_id)
3755 Player *player = m_env->getPlayer(peer_id);
3757 if(player->peer_id == PEER_ID_INEXISTENT)
3760 std::set<std::string> privs;
3761 scriptapi_get_auth(m_lua, player->getName(), NULL, &privs);
3763 std::ostringstream os(std::ios_base::binary);
3764 writeU16(os, TOCLIENT_PRIVILEGES);
3765 writeU16(os, privs.size());
3766 for(std::set<std::string>::const_iterator i = privs.begin();
3767 i != privs.end(); i++){
3768 os<<serializeString(*i);
3772 std::string s = os.str();
3773 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3775 m_con.Send(peer_id, 0, data, true);
3778 void Server::SendPlayerInventoryFormspec(u16 peer_id)
3780 Player *player = m_env->getPlayer(peer_id);
3782 if(player->peer_id == PEER_ID_INEXISTENT)
3785 std::ostringstream os(std::ios_base::binary);
3786 writeU16(os, TOCLIENT_INVENTORY_FORMSPEC);
3787 os<<serializeLongString(player->inventory_formspec);
3790 std::string s = os.str();
3791 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3793 m_con.Send(peer_id, 0, data, true);
3796 s32 Server::playSound(const SimpleSoundSpec &spec,
3797 const ServerSoundParams ¶ms)
3799 // Find out initial position of sound
3800 bool pos_exists = false;
3801 v3f pos = params.getPos(m_env, &pos_exists);
3802 // If position is not found while it should be, cancel sound
3803 if(pos_exists != (params.type != ServerSoundParams::SSP_LOCAL))
3805 // Filter destination clients
3806 std::set<RemoteClient*> dst_clients;
3807 if(params.to_player != "")
3809 Player *player = m_env->getPlayer(params.to_player.c_str());
3811 infostream<<"Server::playSound: Player \""<<params.to_player
3812 <<"\" not found"<<std::endl;
3815 if(player->peer_id == PEER_ID_INEXISTENT){
3816 infostream<<"Server::playSound: Player \""<<params.to_player
3817 <<"\" not connected"<<std::endl;
3820 RemoteClient *client = getClient(player->peer_id);
3821 dst_clients.insert(client);
3825 for(std::map<u16, RemoteClient*>::iterator
3826 i = m_clients.begin(); i != m_clients.end(); ++i)
3828 RemoteClient *client = i->second;
3829 Player *player = m_env->getPlayer(client->peer_id);
3833 if(player->getPosition().getDistanceFrom(pos) >
3834 params.max_hear_distance)
3837 dst_clients.insert(client);
3840 if(dst_clients.size() == 0)
3843 s32 id = m_next_sound_id++;
3844 // The sound will exist as a reference in m_playing_sounds
3845 m_playing_sounds[id] = ServerPlayingSound();
3846 ServerPlayingSound &psound = m_playing_sounds[id];
3847 psound.params = params;
3848 for(std::set<RemoteClient*>::iterator i = dst_clients.begin();
3849 i != dst_clients.end(); i++)
3850 psound.clients.insert((*i)->peer_id);
3852 std::ostringstream os(std::ios_base::binary);
3853 writeU16(os, TOCLIENT_PLAY_SOUND);
3855 os<<serializeString(spec.name);
3856 writeF1000(os, spec.gain * params.gain);
3857 writeU8(os, params.type);
3858 writeV3F1000(os, pos);
3859 writeU16(os, params.object);
3860 writeU8(os, params.loop);
3862 std::string s = os.str();
3863 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3865 for(std::set<RemoteClient*>::iterator i = dst_clients.begin();
3866 i != dst_clients.end(); i++){
3868 m_con.Send((*i)->peer_id, 0, data, true);
3872 void Server::stopSound(s32 handle)
3874 // Get sound reference
3875 std::map<s32, ServerPlayingSound>::iterator i =
3876 m_playing_sounds.find(handle);
3877 if(i == m_playing_sounds.end())
3879 ServerPlayingSound &psound = i->second;
3881 std::ostringstream os(std::ios_base::binary);
3882 writeU16(os, TOCLIENT_STOP_SOUND);
3883 writeS32(os, handle);
3885 std::string s = os.str();
3886 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3888 for(std::set<u16>::iterator i = psound.clients.begin();
3889 i != psound.clients.end(); i++){
3891 m_con.Send(*i, 0, data, true);
3893 // Remove sound reference
3894 m_playing_sounds.erase(i);
3897 void Server::sendRemoveNode(v3s16 p, u16 ignore_id,
3898 std::list<u16> *far_players, float far_d_nodes)
3900 float maxd = far_d_nodes*BS;
3901 v3f p_f = intToFloat(p, BS);
3905 SharedBuffer<u8> reply(replysize);
3906 writeU16(&reply[0], TOCLIENT_REMOVENODE);
3907 writeS16(&reply[2], p.X);
3908 writeS16(&reply[4], p.Y);
3909 writeS16(&reply[6], p.Z);
3911 for(std::map<u16, RemoteClient*>::iterator
3912 i = m_clients.begin();
3913 i != m_clients.end(); ++i)
3915 // Get client and check that it is valid
3916 RemoteClient *client = i->second;
3917 assert(client->peer_id == i->first);
3918 if(client->serialization_version == SER_FMT_VER_INVALID)
3921 // Don't send if it's the same one
3922 if(client->peer_id == ignore_id)
3928 Player *player = m_env->getPlayer(client->peer_id);
3931 // If player is far away, only set modified blocks not sent
3932 v3f player_pos = player->getPosition();
3933 if(player_pos.getDistanceFrom(p_f) > maxd)
3935 far_players->push_back(client->peer_id);
3942 m_con.Send(client->peer_id, 0, reply, true);
3946 void Server::sendAddNode(v3s16 p, MapNode n, u16 ignore_id,
3947 std::list<u16> *far_players, float far_d_nodes)
3949 float maxd = far_d_nodes*BS;
3950 v3f p_f = intToFloat(p, BS);
3952 for(std::map<u16, RemoteClient*>::iterator
3953 i = m_clients.begin();
3954 i != m_clients.end(); ++i)
3956 // Get client and check that it is valid
3957 RemoteClient *client = i->second;
3958 assert(client->peer_id == i->first);
3959 if(client->serialization_version == SER_FMT_VER_INVALID)
3962 // Don't send if it's the same one
3963 if(client->peer_id == ignore_id)
3969 Player *player = m_env->getPlayer(client->peer_id);
3972 // If player is far away, only set modified blocks not sent
3973 v3f player_pos = player->getPosition();
3974 if(player_pos.getDistanceFrom(p_f) > maxd)
3976 far_players->push_back(client->peer_id);
3983 u32 replysize = 8 + MapNode::serializedLength(client->serialization_version);
3984 SharedBuffer<u8> reply(replysize);
3985 writeU16(&reply[0], TOCLIENT_ADDNODE);
3986 writeS16(&reply[2], p.X);
3987 writeS16(&reply[4], p.Y);
3988 writeS16(&reply[6], p.Z);
3989 n.serialize(&reply[8], client->serialization_version);
3992 m_con.Send(client->peer_id, 0, reply, true);
3996 void Server::setBlockNotSent(v3s16 p)
3998 for(std::map<u16, RemoteClient*>::iterator
3999 i = m_clients.begin();
4000 i != m_clients.end(); ++i)
4002 RemoteClient *client = i->second;
4003 client->SetBlockNotSent(p);
4007 void Server::SendBlockNoLock(u16 peer_id, MapBlock *block, u8 ver)
4009 DSTACK(__FUNCTION_NAME);
4011 v3s16 p = block->getPos();
4015 bool completely_air = true;
4016 for(s16 z0=0; z0<MAP_BLOCKSIZE; z0++)
4017 for(s16 x0=0; x0<MAP_BLOCKSIZE; x0++)
4018 for(s16 y0=0; y0<MAP_BLOCKSIZE; y0++)
4020 if(block->getNodeNoEx(v3s16(x0,y0,z0)).d != CONTENT_AIR)
4022 completely_air = false;
4023 x0 = y0 = z0 = MAP_BLOCKSIZE; // Break out
4028 infostream<<"Server: Sending block ("<<p.X<<","<<p.Y<<","<<p.Z<<"): ";
4030 infostream<<"[completely air] ";
4031 infostream<<std::endl;
4035 Create a packet with the block in the right format
4038 std::ostringstream os(std::ios_base::binary);
4039 block->serialize(os, ver, false);
4040 std::string s = os.str();
4041 SharedBuffer<u8> blockdata((u8*)s.c_str(), s.size());
4043 u32 replysize = 8 + blockdata.getSize();
4044 SharedBuffer<u8> reply(replysize);
4045 writeU16(&reply[0], TOCLIENT_BLOCKDATA);
4046 writeS16(&reply[2], p.X);
4047 writeS16(&reply[4], p.Y);
4048 writeS16(&reply[6], p.Z);
4049 memcpy(&reply[8], *blockdata, blockdata.getSize());
4051 /*infostream<<"Server: Sending block ("<<p.X<<","<<p.Y<<","<<p.Z<<")"
4052 <<": \tpacket size: "<<replysize<<std::endl;*/
4057 m_con.Send(peer_id, 1, reply, true);
4060 void Server::SendBlocks(float dtime)
4062 DSTACK(__FUNCTION_NAME);
4064 JMutexAutoLock envlock(m_env_mutex);
4065 JMutexAutoLock conlock(m_con_mutex);
4067 ScopeProfiler sp(g_profiler, "Server: sel and send blocks to clients");
4069 std::vector<PrioritySortedBlockTransfer> queue;
4071 s32 total_sending = 0;
4074 ScopeProfiler sp(g_profiler, "Server: selecting blocks for sending");
4076 for(std::map<u16, RemoteClient*>::iterator
4077 i = m_clients.begin();
4078 i != m_clients.end(); ++i)
4080 RemoteClient *client = i->second;
4081 assert(client->peer_id == i->first);
4083 // If definitions and textures have not been sent, don't
4084 // send MapBlocks either
4085 if(!client->definitions_sent)
4088 total_sending += client->SendingCount();
4090 if(client->serialization_version == SER_FMT_VER_INVALID)
4093 client->GetNextBlocks(this, dtime, queue);
4098 // Lowest priority number comes first.
4099 // Lowest is most important.
4100 std::sort(queue.begin(), queue.end());
4102 for(u32 i=0; i<queue.size(); i++)
4104 //TODO: Calculate limit dynamically
4105 if(total_sending >= g_settings->getS32
4106 ("max_simultaneous_block_sends_server_total"))
4109 PrioritySortedBlockTransfer q = queue[i];
4111 MapBlock *block = NULL;
4114 block = m_env->getMap().getBlockNoCreate(q.pos);
4116 catch(InvalidPositionException &e)
4121 RemoteClient *client = getClient(q.peer_id);
4123 SendBlockNoLock(q.peer_id, block, client->serialization_version);
4125 client->SentBlock(q.pos);
4131 void Server::fillMediaCache()
4133 DSTACK(__FUNCTION_NAME);
4135 infostream<<"Server: Calculating media file checksums"<<std::endl;
4137 // Collect all media file paths
4138 std::list<std::string> paths;
4139 for(std::vector<ModSpec>::iterator i = m_mods.begin();
4140 i != m_mods.end(); i++){
4141 const ModSpec &mod = *i;
4142 paths.push_back(mod.path + DIR_DELIM + "textures");
4143 paths.push_back(mod.path + DIR_DELIM + "sounds");
4144 paths.push_back(mod.path + DIR_DELIM + "media");
4145 paths.push_back(mod.path + DIR_DELIM + "models");
4147 std::string path_all = "textures";
4148 paths.push_back(path_all + DIR_DELIM + "all");
4150 // Collect media file information from paths into cache
4151 for(std::list<std::string>::iterator i = paths.begin();
4152 i != paths.end(); i++)
4154 std::string mediapath = *i;
4155 std::vector<fs::DirListNode> dirlist = fs::GetDirListing(mediapath);
4156 for(u32 j=0; j<dirlist.size(); j++){
4157 if(dirlist[j].dir) // Ignode dirs
4159 std::string filename = dirlist[j].name;
4160 // If name contains illegal characters, ignore the file
4161 if(!string_allowed(filename, TEXTURENAME_ALLOWED_CHARS)){
4162 infostream<<"Server: ignoring illegal file name: \""
4163 <<filename<<"\""<<std::endl;
4166 // If name is not in a supported format, ignore it
4167 const char *supported_ext[] = {
4168 ".png", ".jpg", ".bmp", ".tga",
4169 ".pcx", ".ppm", ".psd", ".wal", ".rgb",
4171 ".x", ".b3d", ".md2", ".obj",
4174 if(removeStringEnd(filename, supported_ext) == ""){
4175 infostream<<"Server: ignoring unsupported file extension: \""
4176 <<filename<<"\""<<std::endl;
4179 // Ok, attempt to load the file and add to cache
4180 std::string filepath = mediapath + DIR_DELIM + filename;
4182 std::ifstream fis(filepath.c_str(), std::ios_base::binary);
4183 if(fis.good() == false){
4184 errorstream<<"Server::fillMediaCache(): Could not open \""
4185 <<filename<<"\" for reading"<<std::endl;
4188 std::ostringstream tmp_os(std::ios_base::binary);
4192 fis.read(buf, 1024);
4193 std::streamsize len = fis.gcount();
4194 tmp_os.write(buf, len);
4203 errorstream<<"Server::fillMediaCache(): Failed to read \""
4204 <<filename<<"\""<<std::endl;
4207 if(tmp_os.str().length() == 0){
4208 errorstream<<"Server::fillMediaCache(): Empty file \""
4209 <<filepath<<"\""<<std::endl;
4214 sha1.addBytes(tmp_os.str().c_str(), tmp_os.str().length());
4216 unsigned char *digest = sha1.getDigest();
4217 std::string sha1_base64 = base64_encode(digest, 20);
4218 std::string sha1_hex = hex_encode((char*)digest, 20);
4222 this->m_media[filename] = MediaInfo(filepath, sha1_base64);
4223 verbosestream<<"Server: "<<sha1_hex<<" is "<<filename<<std::endl;
4228 struct SendableMediaAnnouncement
4231 std::string sha1_digest;
4233 SendableMediaAnnouncement(const std::string name_="",
4234 const std::string sha1_digest_=""):
4236 sha1_digest(sha1_digest_)
4240 void Server::sendMediaAnnouncement(u16 peer_id)
4242 DSTACK(__FUNCTION_NAME);
4244 verbosestream<<"Server: Announcing files to id("<<peer_id<<")"
4247 std::list<SendableMediaAnnouncement> file_announcements;
4249 for(std::map<std::string, MediaInfo>::iterator i = m_media.begin();
4250 i != m_media.end(); i++){
4252 file_announcements.push_back(
4253 SendableMediaAnnouncement(i->first, i->second.sha1_digest));
4257 std::ostringstream os(std::ios_base::binary);
4265 u16 length of sha1_digest
4270 writeU16(os, TOCLIENT_ANNOUNCE_MEDIA);
4271 writeU16(os, file_announcements.size());
4273 for(std::list<SendableMediaAnnouncement>::iterator
4274 j = file_announcements.begin();
4275 j != file_announcements.end(); ++j){
4276 os<<serializeString(j->name);
4277 os<<serializeString(j->sha1_digest);
4279 os<<serializeString(g_settings->get("remote_media"));
4282 std::string s = os.str();
4283 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
4286 m_con.Send(peer_id, 0, data, true);
4289 struct SendableMedia
4295 SendableMedia(const std::string &name_="", const std::string path_="",
4296 const std::string &data_=""):
4303 void Server::sendRequestedMedia(u16 peer_id,
4304 const std::list<MediaRequest> &tosend)
4306 DSTACK(__FUNCTION_NAME);
4308 verbosestream<<"Server::sendRequestedMedia(): "
4309 <<"Sending files to client"<<std::endl;
4313 // Put 5kB in one bunch (this is not accurate)
4314 u32 bytes_per_bunch = 5000;
4316 std::vector< std::list<SendableMedia> > file_bunches;
4317 file_bunches.push_back(std::list<SendableMedia>());
4319 u32 file_size_bunch_total = 0;
4321 for(std::list<MediaRequest>::const_iterator i = tosend.begin();
4322 i != tosend.end(); ++i)
4324 if(m_media.find(i->name) == m_media.end()){
4325 errorstream<<"Server::sendRequestedMedia(): Client asked for "
4326 <<"unknown file \""<<(i->name)<<"\""<<std::endl;
4330 //TODO get path + name
4331 std::string tpath = m_media[(*i).name].path;
4334 std::ifstream fis(tpath.c_str(), std::ios_base::binary);
4335 if(fis.good() == false){
4336 errorstream<<"Server::sendRequestedMedia(): Could not open \""
4337 <<tpath<<"\" for reading"<<std::endl;
4340 std::ostringstream tmp_os(std::ios_base::binary);
4344 fis.read(buf, 1024);
4345 std::streamsize len = fis.gcount();
4346 tmp_os.write(buf, len);
4347 file_size_bunch_total += len;
4356 errorstream<<"Server::sendRequestedMedia(): Failed to read \""
4357 <<(*i).name<<"\""<<std::endl;
4360 /*infostream<<"Server::sendRequestedMedia(): Loaded \""
4361 <<tname<<"\""<<std::endl;*/
4363 file_bunches[file_bunches.size()-1].push_back(
4364 SendableMedia((*i).name, tpath, tmp_os.str()));
4366 // Start next bunch if got enough data
4367 if(file_size_bunch_total >= bytes_per_bunch){
4368 file_bunches.push_back(std::list<SendableMedia>());
4369 file_size_bunch_total = 0;
4374 /* Create and send packets */
4376 u32 num_bunches = file_bunches.size();
4377 for(u32 i=0; i<num_bunches; i++)
4379 std::ostringstream os(std::ios_base::binary);
4383 u16 total number of texture bunches
4384 u16 index of this bunch
4385 u32 number of files in this bunch
4394 writeU16(os, TOCLIENT_MEDIA);
4395 writeU16(os, num_bunches);
4397 writeU32(os, file_bunches[i].size());
4399 for(std::list<SendableMedia>::iterator
4400 j = file_bunches[i].begin();
4401 j != file_bunches[i].end(); ++j){
4402 os<<serializeString(j->name);
4403 os<<serializeLongString(j->data);
4407 std::string s = os.str();
4408 verbosestream<<"Server::sendRequestedMedia(): bunch "
4409 <<i<<"/"<<num_bunches
4410 <<" files="<<file_bunches[i].size()
4411 <<" size=" <<s.size()<<std::endl;
4412 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
4414 m_con.Send(peer_id, 0, data, true);
4418 void Server::sendDetachedInventory(const std::string &name, u16 peer_id)
4420 if(m_detached_inventories.count(name) == 0){
4421 errorstream<<__FUNCTION_NAME<<": \""<<name<<"\" not found"<<std::endl;
4424 Inventory *inv = m_detached_inventories[name];
4426 std::ostringstream os(std::ios_base::binary);
4427 writeU16(os, TOCLIENT_DETACHED_INVENTORY);
4428 os<<serializeString(name);
4432 std::string s = os.str();
4433 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
4435 m_con.Send(peer_id, 0, data, true);
4438 void Server::sendDetachedInventoryToAll(const std::string &name)
4440 DSTACK(__FUNCTION_NAME);
4442 for(std::map<u16, RemoteClient*>::iterator
4443 i = m_clients.begin();
4444 i != m_clients.end(); ++i){
4445 RemoteClient *client = i->second;
4446 sendDetachedInventory(name, client->peer_id);
4450 void Server::sendDetachedInventories(u16 peer_id)
4452 DSTACK(__FUNCTION_NAME);
4454 for(std::map<std::string, Inventory*>::iterator
4455 i = m_detached_inventories.begin();
4456 i != m_detached_inventories.end(); i++){
4457 const std::string &name = i->first;
4458 //Inventory *inv = i->second;
4459 sendDetachedInventory(name, peer_id);
4467 void Server::DiePlayer(u16 peer_id)
4469 DSTACK(__FUNCTION_NAME);
4471 PlayerSAO *playersao = getPlayerSAO(peer_id);
4474 infostream<<"Server::DiePlayer(): Player "
4475 <<playersao->getPlayer()->getName()
4476 <<" dies"<<std::endl;
4478 playersao->setHP(0);
4480 // Trigger scripted stuff
4481 scriptapi_on_dieplayer(m_lua, playersao);
4483 SendPlayerHP(peer_id);
4484 SendDeathscreen(m_con, peer_id, false, v3f(0,0,0));
4487 void Server::RespawnPlayer(u16 peer_id)
4489 DSTACK(__FUNCTION_NAME);
4491 PlayerSAO *playersao = getPlayerSAO(peer_id);
4494 infostream<<"Server::RespawnPlayer(): Player "
4495 <<playersao->getPlayer()->getName()
4496 <<" respawns"<<std::endl;
4498 playersao->setHP(PLAYER_MAX_HP);
4500 bool repositioned = scriptapi_on_respawnplayer(m_lua, playersao);
4502 v3f pos = findSpawnPos(m_env->getServerMap());
4503 playersao->setPos(pos);
4507 void Server::UpdateCrafting(u16 peer_id)
4509 DSTACK(__FUNCTION_NAME);
4511 Player* player = m_env->getPlayer(peer_id);
4514 // Get a preview for crafting
4516 getCraftingResult(&player->inventory, preview, false, this);
4518 // Put the new preview in
4519 InventoryList *plist = player->inventory.getList("craftpreview");
4521 assert(plist->getSize() >= 1);
4522 plist->changeItem(0, preview);
4525 RemoteClient* Server::getClient(u16 peer_id)
4527 DSTACK(__FUNCTION_NAME);
4528 //JMutexAutoLock lock(m_con_mutex);
4529 std::map<u16, RemoteClient*>::iterator n;
4530 n = m_clients.find(peer_id);
4531 // A client should exist for all peers
4532 assert(n != m_clients.end());
4536 std::wstring Server::getStatusString()
4538 std::wostringstream os(std::ios_base::binary);
4541 os<<L"version="<<narrow_to_wide(VERSION_STRING);
4543 os<<L", uptime="<<m_uptime.get();
4544 // Information about clients
4545 std::map<u16, RemoteClient*>::iterator i;
4548 for(i = m_clients.begin(), first = true;
4549 i != m_clients.end(); ++i)
4551 // Get client and check that it is valid
4552 RemoteClient *client = i->second;
4553 assert(client->peer_id == i->first);
4554 if(client->serialization_version == SER_FMT_VER_INVALID)
4557 Player *player = m_env->getPlayer(client->peer_id);
4558 // Get name of player
4559 std::wstring name = L"unknown";
4561 name = narrow_to_wide(player->getName());
4562 // Add name to information string
4570 if(((ServerMap*)(&m_env->getMap()))->isSavingEnabled() == false)
4571 os<<std::endl<<L"# Server: "<<" WARNING: Map saving is disabled.";
4572 if(g_settings->get("motd") != "")
4573 os<<std::endl<<L"# Server: "<<narrow_to_wide(g_settings->get("motd"));
4577 std::set<std::string> Server::getPlayerEffectivePrivs(const std::string &name)
4579 std::set<std::string> privs;
4580 scriptapi_get_auth(m_lua, name, NULL, &privs);
4584 bool Server::checkPriv(const std::string &name, const std::string &priv)
4586 std::set<std::string> privs = getPlayerEffectivePrivs(name);
4587 return (privs.count(priv) != 0);
4590 void Server::reportPrivsModified(const std::string &name)
4593 for(std::map<u16, RemoteClient*>::iterator
4594 i = m_clients.begin();
4595 i != m_clients.end(); ++i){
4596 RemoteClient *client = i->second;
4597 Player *player = m_env->getPlayer(client->peer_id);
4598 reportPrivsModified(player->getName());
4601 Player *player = m_env->getPlayer(name.c_str());
4604 SendPlayerPrivileges(player->peer_id);
4605 PlayerSAO *sao = player->getPlayerSAO();
4608 sao->updatePrivileges(
4609 getPlayerEffectivePrivs(name),
4614 void Server::reportInventoryFormspecModified(const std::string &name)
4616 Player *player = m_env->getPlayer(name.c_str());
4619 SendPlayerInventoryFormspec(player->peer_id);
4622 // Saves g_settings to configpath given at initialization
4623 void Server::saveConfig()
4625 if(m_path_config != "")
4626 g_settings->updateConfigFile(m_path_config.c_str());
4629 void Server::notifyPlayer(const char *name, const std::wstring msg, const bool prepend = true)
4631 Player *player = m_env->getPlayer(name);
4635 SendChatMessage(player->peer_id, std::wstring(L"Server -!- ")+msg);
4637 SendChatMessage(player->peer_id, msg);
4640 bool Server::showFormspec(const char *playername, const std::string &formspec, const std::string &formname)
4642 Player *player = m_env->getPlayer(playername);
4646 infostream<<"showFormspec: couldn't find player:"<<playername<<std::endl;
4650 SendShowFormspecMessage(player->peer_id, formspec, formname);
4654 u32 Server::hudAdd(Player *player, HudElement *form) {
4658 u32 id = hud_get_free_id(player);
4659 if (id < player->hud.size())
4660 player->hud[id] = form;
4662 player->hud.push_back(form);
4664 SendHUDAdd(player->peer_id, id, form);
4668 bool Server::hudRemove(Player *player, u32 id) {
4669 if (!player || id >= player->hud.size() || !player->hud[id])
4672 delete player->hud[id];
4673 player->hud[id] = NULL;
4675 SendHUDRemove(player->peer_id, id);
4679 bool Server::hudChange(Player *player, u32 id, HudElementStat stat, void *data) {
4683 SendHUDChange(player->peer_id, id, stat, data);
4687 bool Server::hudSetFlags(Player *player, u32 flags, u32 mask) {
4691 SendHUDSetFlags(player->peer_id, flags, mask);
4695 void Server::notifyPlayers(const std::wstring msg)
4697 BroadcastChatMessage(msg);
4700 void Server::spawnParticle(const char *playername, v3f pos,
4701 v3f velocity, v3f acceleration,
4702 float expirationtime, float size, bool
4703 collisiondetection, std::string texture)
4705 Player *player = m_env->getPlayer(playername);
4708 SendSpawnParticle(player->peer_id, pos, velocity, acceleration,
4709 expirationtime, size, collisiondetection, texture);
4712 void Server::spawnParticleAll(v3f pos, v3f velocity, v3f acceleration,
4713 float expirationtime, float size,
4714 bool collisiondetection, std::string texture)
4716 SendSpawnParticleAll(pos, velocity, acceleration,
4717 expirationtime, size, collisiondetection, texture);
4720 u32 Server::addParticleSpawner(const char *playername,
4721 u16 amount, float spawntime,
4722 v3f minpos, v3f maxpos,
4723 v3f minvel, v3f maxvel,
4724 v3f minacc, v3f maxacc,
4725 float minexptime, float maxexptime,
4726 float minsize, float maxsize,
4727 bool collisiondetection, std::string texture)
4729 Player *player = m_env->getPlayer(playername);
4734 for(;;) // look for unused particlespawner id
4737 if (std::find(m_particlespawner_ids.begin(),
4738 m_particlespawner_ids.end(), id)
4739 == m_particlespawner_ids.end())
4741 m_particlespawner_ids.push_back(id);
4746 SendAddParticleSpawner(player->peer_id, amount, spawntime,
4747 minpos, maxpos, minvel, maxvel, minacc, maxacc,
4748 minexptime, maxexptime, minsize, maxsize,
4749 collisiondetection, texture, id);
4754 u32 Server::addParticleSpawnerAll(u16 amount, float spawntime,
4755 v3f minpos, v3f maxpos,
4756 v3f minvel, v3f maxvel,
4757 v3f minacc, v3f maxacc,
4758 float minexptime, float maxexptime,
4759 float minsize, float maxsize,
4760 bool collisiondetection, std::string texture)
4763 for(;;) // look for unused particlespawner id
4766 if (std::find(m_particlespawner_ids.begin(),
4767 m_particlespawner_ids.end(), id)
4768 == m_particlespawner_ids.end())
4770 m_particlespawner_ids.push_back(id);
4775 SendAddParticleSpawnerAll(amount, spawntime,
4776 minpos, maxpos, minvel, maxvel, minacc, maxacc,
4777 minexptime, maxexptime, minsize, maxsize,
4778 collisiondetection, texture, id);
4783 void Server::deleteParticleSpawner(const char *playername, u32 id)
4785 Player *player = m_env->getPlayer(playername);
4789 m_particlespawner_ids.erase(
4790 std::remove(m_particlespawner_ids.begin(),
4791 m_particlespawner_ids.end(), id),
4792 m_particlespawner_ids.end());
4793 SendDeleteParticleSpawner(player->peer_id, id);
4796 void Server::deleteParticleSpawnerAll(u32 id)
4798 m_particlespawner_ids.erase(
4799 std::remove(m_particlespawner_ids.begin(),
4800 m_particlespawner_ids.end(), id),
4801 m_particlespawner_ids.end());
4802 SendDeleteParticleSpawnerAll(id);
4805 void Server::queueBlockEmerge(v3s16 blockpos, bool allow_generate)
4807 m_emerge->enqueueBlockEmerge(PEER_ID_INEXISTENT, blockpos, allow_generate);
4810 Inventory* Server::createDetachedInventory(const std::string &name)
4812 if(m_detached_inventories.count(name) > 0){
4813 infostream<<"Server clearing detached inventory \""<<name<<"\""<<std::endl;
4814 delete m_detached_inventories[name];
4816 infostream<<"Server creating detached inventory \""<<name<<"\""<<std::endl;
4818 Inventory *inv = new Inventory(m_itemdef);
4820 m_detached_inventories[name] = inv;
4821 sendDetachedInventoryToAll(name);
4828 BoolScopeSet(bool *dst, bool val):
4831 m_orig_state = *m_dst;
4836 *m_dst = m_orig_state;
4843 // actions: time-reversed list
4844 // Return value: success/failure
4845 bool Server::rollbackRevertActions(const std::list<RollbackAction> &actions,
4846 std::list<std::string> *log)
4848 infostream<<"Server::rollbackRevertActions(len="<<actions.size()<<")"<<std::endl;
4849 ServerMap *map = (ServerMap*)(&m_env->getMap());
4850 // Disable rollback report sink while reverting
4851 BoolScopeSet rollback_scope_disable(&m_rollback_sink_enabled, false);
4853 // Fail if no actions to handle
4854 if(actions.empty()){
4855 log->push_back("Nothing to do.");
4862 for(std::list<RollbackAction>::const_iterator
4863 i = actions.begin();
4864 i != actions.end(); i++)
4866 const RollbackAction &action = *i;
4868 bool success = action.applyRevert(map, this, this);
4871 std::ostringstream os;
4872 os<<"Revert of step ("<<num_tried<<") "<<action.toString()<<" failed";
4873 infostream<<"Map::rollbackRevertActions(): "<<os.str()<<std::endl;
4875 log->push_back(os.str());
4877 std::ostringstream os;
4878 os<<"Successfully reverted step ("<<num_tried<<") "<<action.toString();
4879 infostream<<"Map::rollbackRevertActions(): "<<os.str()<<std::endl;
4881 log->push_back(os.str());
4885 infostream<<"Map::rollbackRevertActions(): "<<num_failed<<"/"<<num_tried
4886 <<" failed"<<std::endl;
4888 // Call it done if less than half failed
4889 return num_failed <= num_tried/2;
4892 // IGameDef interface
4894 IItemDefManager* Server::getItemDefManager()
4898 INodeDefManager* Server::getNodeDefManager()
4902 ICraftDefManager* Server::getCraftDefManager()
4906 ITextureSource* Server::getTextureSource()
4910 IShaderSource* Server::getShaderSource()
4914 u16 Server::allocateUnknownNodeId(const std::string &name)
4916 return m_nodedef->allocateDummy(name);
4918 ISoundManager* Server::getSoundManager()
4920 return &dummySoundManager;
4922 MtEventManager* Server::getEventManager()
4926 IRollbackReportSink* Server::getRollbackReportSink()
4928 if(!m_enable_rollback_recording)
4930 if(!m_rollback_sink_enabled)
4935 IWritableItemDefManager* Server::getWritableItemDefManager()
4939 IWritableNodeDefManager* Server::getWritableNodeDefManager()
4943 IWritableCraftDefManager* Server::getWritableCraftDefManager()
4948 const ModSpec* Server::getModSpec(const std::string &modname)
4950 for(std::vector<ModSpec>::iterator i = m_mods.begin();
4951 i != m_mods.end(); i++){
4952 const ModSpec &mod = *i;
4953 if(mod.name == modname)
4958 void Server::getModNames(std::list<std::string> &modlist)
4960 for(std::vector<ModSpec>::iterator i = m_mods.begin(); i != m_mods.end(); i++)
4962 modlist.push_back(i->name);
4965 std::string Server::getBuiltinLuaPath()
4967 return porting::path_share + DIR_DELIM + "builtin";
4970 v3f findSpawnPos(ServerMap &map)
4972 //return v3f(50,50,50)*BS;
4977 nodepos = v2s16(0,0);
4982 s16 water_level = map.m_mgparams->water_level;
4984 // Try to find a good place a few times
4985 for(s32 i=0; i<1000; i++)
4988 // We're going to try to throw the player to this position
4989 v2s16 nodepos2d = v2s16(
4990 -range + (myrand() % (range * 2)),
4991 -range + (myrand() % (range * 2)));
4993 // Get ground height at point
4994 s16 groundheight = map.findGroundLevel(nodepos2d);
4995 if (groundheight <= water_level) // Don't go underwater
4997 if (groundheight > water_level + 6) // Don't go to high places
5000 nodepos = v3s16(nodepos2d.X, groundheight, nodepos2d.Y);
5001 bool is_good = false;
5003 for (s32 i = 0; i < 10; i++) {
5004 v3s16 blockpos = getNodeBlockPos(nodepos);
5005 map.emergeBlock(blockpos, true);
5006 content_t c = map.getNodeNoEx(nodepos).getContent();
5007 if (c == CONTENT_AIR || c == CONTENT_IGNORE) {
5009 if (air_count >= 2){
5017 // Found a good place
5018 //infostream<<"Searched through "<<i<<" places."<<std::endl;
5024 return intToFloat(nodepos, BS);
5027 PlayerSAO* Server::emergePlayer(const char *name, u16 peer_id)
5029 RemotePlayer *player = NULL;
5030 bool newplayer = false;
5033 Try to get an existing player
5035 player = static_cast<RemotePlayer*>(m_env->getPlayer(name));
5037 // If player is already connected, cancel
5038 if(player != NULL && player->peer_id != 0)
5040 infostream<<"emergePlayer(): Player already connected"<<std::endl;
5045 If player with the wanted peer_id already exists, cancel.
5047 if(m_env->getPlayer(peer_id) != NULL)
5049 infostream<<"emergePlayer(): Player with wrong name but same"
5050 " peer_id already exists"<<std::endl;
5055 Create a new player if it doesn't exist yet
5060 player = new RemotePlayer(this);
5061 player->updateName(name);
5063 /* Set player position */
5064 infostream<<"Server: Finding spawn place for player \""
5065 <<name<<"\""<<std::endl;
5066 v3f pos = findSpawnPos(m_env->getServerMap());
5067 player->setPosition(pos);
5069 /* Add player to environment */
5070 m_env->addPlayer(player);
5074 Create a new player active object
5076 PlayerSAO *playersao = new PlayerSAO(m_env, player, peer_id,
5077 getPlayerEffectivePrivs(player->getName()),
5080 /* Add object to environment */
5081 m_env->addActiveObject(playersao);
5085 scriptapi_on_newplayer(m_lua, playersao);
5087 scriptapi_on_joinplayer(m_lua, playersao);
5092 void Server::handlePeerChange(PeerChange &c)
5094 JMutexAutoLock envlock(m_env_mutex);
5095 JMutexAutoLock conlock(m_con_mutex);
5097 if(c.type == PEER_ADDED)
5104 std::map<u16, RemoteClient*>::iterator n;
5105 n = m_clients.find(c.peer_id);
5106 // The client shouldn't already exist
5107 assert(n == m_clients.end());
5110 RemoteClient *client = new RemoteClient();
5111 client->peer_id = c.peer_id;
5112 m_clients[client->peer_id] = client;
5115 else if(c.type == PEER_REMOVED)
5122 std::map<u16, RemoteClient*>::iterator n;
5123 n = m_clients.find(c.peer_id);
5124 // The client should exist
5125 assert(n != m_clients.end());
5128 Mark objects to be not known by the client
5130 RemoteClient *client = n->second;
5132 for(std::set<u16>::iterator
5133 i = client->m_known_objects.begin();
5134 i != client->m_known_objects.end(); ++i)
5138 ServerActiveObject* obj = m_env->getActiveObject(id);
5140 if(obj && obj->m_known_by_count > 0)
5141 obj->m_known_by_count--;
5145 Clear references to playing sounds
5147 for(std::map<s32, ServerPlayingSound>::iterator
5148 i = m_playing_sounds.begin();
5149 i != m_playing_sounds.end();)
5151 ServerPlayingSound &psound = i->second;
5152 psound.clients.erase(c.peer_id);
5153 if(psound.clients.size() == 0)
5154 m_playing_sounds.erase(i++);
5159 Player *player = m_env->getPlayer(c.peer_id);
5161 // Collect information about leaving in chat
5162 std::wstring message;
5166 std::wstring name = narrow_to_wide(player->getName());
5169 message += L" left the game.";
5171 message += L" (timed out)";
5175 /* Run scripts and remove from environment */
5179 PlayerSAO *playersao = player->getPlayerSAO();
5182 scriptapi_on_leaveplayer(m_lua, playersao);
5184 playersao->disconnected();
5194 std::ostringstream os(std::ios_base::binary);
5195 for(std::map<u16, RemoteClient*>::iterator
5196 i = m_clients.begin();
5197 i != m_clients.end(); ++i)
5199 RemoteClient *client = i->second;
5200 assert(client->peer_id == i->first);
5201 if(client->serialization_version == SER_FMT_VER_INVALID)
5204 Player *player = m_env->getPlayer(client->peer_id);
5207 // Get name of player
5208 os<<player->getName()<<" ";
5211 actionstream<<player->getName()<<" "
5212 <<(c.timeout?"times out.":"leaves game.")
5213 <<" List of players: "
5214 <<os.str()<<std::endl;
5219 delete m_clients[c.peer_id];
5220 m_clients.erase(c.peer_id);
5222 // Send player info to all remaining clients
5223 //SendPlayerInfos();
5225 // Send leave chat message to all remaining clients
5226 if(message.length() != 0)
5227 BroadcastChatMessage(message);
5236 void Server::handlePeerChanges()
5238 while(m_peer_change_queue.size() > 0)
5240 PeerChange c = m_peer_change_queue.pop_front();
5242 verbosestream<<"Server: Handling peer change: "
5243 <<"id="<<c.peer_id<<", timeout="<<c.timeout
5246 handlePeerChange(c);
5250 void dedicated_server_loop(Server &server, bool &kill)
5252 DSTACK(__FUNCTION_NAME);
5254 verbosestream<<"dedicated_server_loop()"<<std::endl;
5256 IntervalLimiter m_profiler_interval;
5260 float steplen = g_settings->getFloat("dedicated_server_step");
5261 // This is kind of a hack but can be done like this
5262 // because server.step() is very light
5264 ScopeProfiler sp(g_profiler, "dedicated server sleep");
5265 sleep_ms((int)(steplen*1000.0));
5267 server.step(steplen);
5269 if(server.getShutdownRequested() || kill)
5271 infostream<<"Dedicated server quitting"<<std::endl;
5273 if(g_settings->getBool("server_announce") == true)
5274 ServerList::sendAnnounce("delete");
5282 float profiler_print_interval =
5283 g_settings->getFloat("profiler_print_interval");
5284 if(profiler_print_interval != 0)
5286 if(m_profiler_interval.step(steplen, profiler_print_interval))
5288 infostream<<"Profiler:"<<std::endl;
5289 g_profiler->print(infostream);
5290 g_profiler->clear();