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 above
2984 // node 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);
2995 else if(action == 4)
2997 ItemStack item = playersao->getWieldedItem();
2999 actionstream<<player->getName()<<" uses "<<item.name
3000 <<", pointing at "<<pointed.dump()<<std::endl;
3002 if(scriptapi_item_on_use(m_lua,
3003 item, playersao, pointed))
3005 // Apply returned ItemStack
3006 playersao->setWieldedItem(item);
3013 Catch invalid actions
3017 infostream<<"WARNING: Server: Invalid action "
3018 <<action<<std::endl;
3021 else if(command == TOSERVER_REMOVED_SOUNDS)
3023 std::string datastring((char*)&data[2], datasize-2);
3024 std::istringstream is(datastring, std::ios_base::binary);
3026 int num = readU16(is);
3027 for(int k=0; k<num; k++){
3028 s32 id = readS32(is);
3029 std::map<s32, ServerPlayingSound>::iterator i =
3030 m_playing_sounds.find(id);
3031 if(i == m_playing_sounds.end())
3033 ServerPlayingSound &psound = i->second;
3034 psound.clients.erase(peer_id);
3035 if(psound.clients.size() == 0)
3036 m_playing_sounds.erase(i++);
3039 else if(command == TOSERVER_NODEMETA_FIELDS)
3041 std::string datastring((char*)&data[2], datasize-2);
3042 std::istringstream is(datastring, std::ios_base::binary);
3044 v3s16 p = readV3S16(is);
3045 std::string formname = deSerializeString(is);
3046 int num = readU16(is);
3047 std::map<std::string, std::string> fields;
3048 for(int k=0; k<num; k++){
3049 std::string fieldname = deSerializeString(is);
3050 std::string fieldvalue = deSerializeLongString(is);
3051 fields[fieldname] = fieldvalue;
3054 // If something goes wrong, this player is to blame
3055 RollbackScopeActor rollback_scope(m_rollback,
3056 std::string("player:")+player->getName());
3058 // Check the target node for rollback data; leave others unnoticed
3059 RollbackNode rn_old(&m_env->getMap(), p, this);
3061 scriptapi_node_on_receive_fields(m_lua, p, formname, fields,
3064 // Report rollback data
3065 RollbackNode rn_new(&m_env->getMap(), p, this);
3066 if(rollback() && rn_new != rn_old){
3067 RollbackAction action;
3068 action.setSetNode(p, rn_old, rn_new);
3069 rollback()->reportAction(action);
3072 else if(command == TOSERVER_INVENTORY_FIELDS)
3074 std::string datastring((char*)&data[2], datasize-2);
3075 std::istringstream is(datastring, std::ios_base::binary);
3077 std::string formname = deSerializeString(is);
3078 int num = readU16(is);
3079 std::map<std::string, std::string> fields;
3080 for(int k=0; k<num; k++){
3081 std::string fieldname = deSerializeString(is);
3082 std::string fieldvalue = deSerializeLongString(is);
3083 fields[fieldname] = fieldvalue;
3086 scriptapi_on_player_receive_fields(m_lua, playersao, formname, fields);
3090 infostream<<"Server::ProcessData(): Ignoring "
3091 "unknown command "<<command<<std::endl;
3095 catch(SendFailedException &e)
3097 errorstream<<"Server::ProcessData(): SendFailedException: "
3103 void Server::onMapEditEvent(MapEditEvent *event)
3105 //infostream<<"Server::onMapEditEvent()"<<std::endl;
3106 if(m_ignore_map_edit_events)
3108 if(m_ignore_map_edit_events_area.contains(event->getArea()))
3110 MapEditEvent *e = event->clone();
3111 m_unsent_map_edit_queue.push_back(e);
3114 Inventory* Server::getInventory(const InventoryLocation &loc)
3117 case InventoryLocation::UNDEFINED:
3120 case InventoryLocation::CURRENT_PLAYER:
3123 case InventoryLocation::PLAYER:
3125 Player *player = m_env->getPlayer(loc.name.c_str());
3128 PlayerSAO *playersao = player->getPlayerSAO();
3131 return playersao->getInventory();
3134 case InventoryLocation::NODEMETA:
3136 NodeMetadata *meta = m_env->getMap().getNodeMetadata(loc.p);
3139 return meta->getInventory();
3142 case InventoryLocation::DETACHED:
3144 if(m_detached_inventories.count(loc.name) == 0)
3146 return m_detached_inventories[loc.name];
3154 void Server::setInventoryModified(const InventoryLocation &loc)
3157 case InventoryLocation::UNDEFINED:
3160 case InventoryLocation::PLAYER:
3162 Player *player = m_env->getPlayer(loc.name.c_str());
3165 PlayerSAO *playersao = player->getPlayerSAO();
3168 playersao->m_inventory_not_sent = true;
3169 playersao->m_wielded_item_not_sent = true;
3172 case InventoryLocation::NODEMETA:
3174 v3s16 blockpos = getNodeBlockPos(loc.p);
3176 MapBlock *block = m_env->getMap().getBlockNoCreateNoEx(blockpos);
3178 block->raiseModified(MOD_STATE_WRITE_NEEDED);
3180 setBlockNotSent(blockpos);
3183 case InventoryLocation::DETACHED:
3185 sendDetachedInventoryToAll(loc.name);
3193 std::list<PlayerInfo> Server::getPlayerInfo()
3195 DSTACK(__FUNCTION_NAME);
3196 JMutexAutoLock envlock(m_env_mutex);
3197 JMutexAutoLock conlock(m_con_mutex);
3199 std::list<PlayerInfo> list;
3201 std::list<Player*> players = m_env->getPlayers();
3203 std::list<Player*>::iterator i;
3204 for(i = players.begin();
3205 i != players.end(); ++i)
3209 Player *player = *i;
3212 // Copy info from connection to info struct
3213 info.id = player->peer_id;
3214 info.address = m_con.GetPeerAddress(player->peer_id);
3215 info.avg_rtt = m_con.GetPeerAvgRTT(player->peer_id);
3217 catch(con::PeerNotFoundException &e)
3219 // Set dummy peer info
3221 info.address = Address(0,0,0,0,0);
3225 snprintf(info.name, PLAYERNAME_SIZE, "%s", player->getName());
3226 info.position = player->getPosition();
3228 list.push_back(info);
3235 void Server::peerAdded(con::Peer *peer)
3237 DSTACK(__FUNCTION_NAME);
3238 verbosestream<<"Server::peerAdded(): peer->id="
3239 <<peer->id<<std::endl;
3242 c.type = PEER_ADDED;
3243 c.peer_id = peer->id;
3245 m_peer_change_queue.push_back(c);
3248 void Server::deletingPeer(con::Peer *peer, bool timeout)
3250 DSTACK(__FUNCTION_NAME);
3251 verbosestream<<"Server::deletingPeer(): peer->id="
3252 <<peer->id<<", timeout="<<timeout<<std::endl;
3255 c.type = PEER_REMOVED;
3256 c.peer_id = peer->id;
3257 c.timeout = timeout;
3258 m_peer_change_queue.push_back(c);
3265 void Server::SendMovement(con::Connection &con, u16 peer_id)
3267 DSTACK(__FUNCTION_NAME);
3268 std::ostringstream os(std::ios_base::binary);
3270 writeU16(os, TOCLIENT_MOVEMENT);
3271 writeF1000(os, g_settings->getFloat("movement_acceleration_default"));
3272 writeF1000(os, g_settings->getFloat("movement_acceleration_air"));
3273 writeF1000(os, g_settings->getFloat("movement_acceleration_fast"));
3274 writeF1000(os, g_settings->getFloat("movement_speed_walk"));
3275 writeF1000(os, g_settings->getFloat("movement_speed_crouch"));
3276 writeF1000(os, g_settings->getFloat("movement_speed_fast"));
3277 writeF1000(os, g_settings->getFloat("movement_speed_climb"));
3278 writeF1000(os, g_settings->getFloat("movement_speed_jump"));
3279 writeF1000(os, g_settings->getFloat("movement_liquid_fluidity"));
3280 writeF1000(os, g_settings->getFloat("movement_liquid_fluidity_smooth"));
3281 writeF1000(os, g_settings->getFloat("movement_liquid_sink"));
3282 writeF1000(os, g_settings->getFloat("movement_gravity"));
3285 std::string s = os.str();
3286 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3288 con.Send(peer_id, 0, data, true);
3291 void Server::SendHP(con::Connection &con, u16 peer_id, u8 hp)
3293 DSTACK(__FUNCTION_NAME);
3294 std::ostringstream os(std::ios_base::binary);
3296 writeU16(os, TOCLIENT_HP);
3300 std::string s = os.str();
3301 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3303 con.Send(peer_id, 0, data, true);
3306 void Server::SendAccessDenied(con::Connection &con, u16 peer_id,
3307 const std::wstring &reason)
3309 DSTACK(__FUNCTION_NAME);
3310 std::ostringstream os(std::ios_base::binary);
3312 writeU16(os, TOCLIENT_ACCESS_DENIED);
3313 os<<serializeWideString(reason);
3316 std::string s = os.str();
3317 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3319 con.Send(peer_id, 0, data, true);
3322 void Server::SendDeathscreen(con::Connection &con, u16 peer_id,
3323 bool set_camera_point_target, v3f camera_point_target)
3325 DSTACK(__FUNCTION_NAME);
3326 std::ostringstream os(std::ios_base::binary);
3328 writeU16(os, TOCLIENT_DEATHSCREEN);
3329 writeU8(os, set_camera_point_target);
3330 writeV3F1000(os, camera_point_target);
3333 std::string s = os.str();
3334 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3336 con.Send(peer_id, 0, data, true);
3339 void Server::SendItemDef(con::Connection &con, u16 peer_id,
3340 IItemDefManager *itemdef, u16 protocol_version)
3342 DSTACK(__FUNCTION_NAME);
3343 std::ostringstream os(std::ios_base::binary);
3347 u32 length of the next item
3348 zlib-compressed serialized ItemDefManager
3350 writeU16(os, TOCLIENT_ITEMDEF);
3351 std::ostringstream tmp_os(std::ios::binary);
3352 itemdef->serialize(tmp_os, protocol_version);
3353 std::ostringstream tmp_os2(std::ios::binary);
3354 compressZlib(tmp_os.str(), tmp_os2);
3355 os<<serializeLongString(tmp_os2.str());
3358 std::string s = os.str();
3359 verbosestream<<"Server: Sending item definitions to id("<<peer_id
3360 <<"): size="<<s.size()<<std::endl;
3361 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3363 con.Send(peer_id, 0, data, true);
3366 void Server::SendNodeDef(con::Connection &con, u16 peer_id,
3367 INodeDefManager *nodedef, u16 protocol_version)
3369 DSTACK(__FUNCTION_NAME);
3370 std::ostringstream os(std::ios_base::binary);
3374 u32 length of the next item
3375 zlib-compressed serialized NodeDefManager
3377 writeU16(os, TOCLIENT_NODEDEF);
3378 std::ostringstream tmp_os(std::ios::binary);
3379 nodedef->serialize(tmp_os, protocol_version);
3380 std::ostringstream tmp_os2(std::ios::binary);
3381 compressZlib(tmp_os.str(), tmp_os2);
3382 os<<serializeLongString(tmp_os2.str());
3385 std::string s = os.str();
3386 verbosestream<<"Server: Sending node definitions to id("<<peer_id
3387 <<"): size="<<s.size()<<std::endl;
3388 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3390 con.Send(peer_id, 0, data, true);
3394 Non-static send methods
3397 void Server::SendInventory(u16 peer_id)
3399 DSTACK(__FUNCTION_NAME);
3401 PlayerSAO *playersao = getPlayerSAO(peer_id);
3404 playersao->m_inventory_not_sent = false;
3410 std::ostringstream os;
3411 playersao->getInventory()->serialize(os);
3413 std::string s = os.str();
3415 SharedBuffer<u8> data(s.size()+2);
3416 writeU16(&data[0], TOCLIENT_INVENTORY);
3417 memcpy(&data[2], s.c_str(), s.size());
3420 m_con.Send(peer_id, 0, data, true);
3423 void Server::SendChatMessage(u16 peer_id, const std::wstring &message)
3425 DSTACK(__FUNCTION_NAME);
3427 std::ostringstream os(std::ios_base::binary);
3431 writeU16(buf, TOCLIENT_CHAT_MESSAGE);
3432 os.write((char*)buf, 2);
3435 writeU16(buf, message.size());
3436 os.write((char*)buf, 2);
3439 for(u32 i=0; i<message.size(); i++)
3443 os.write((char*)buf, 2);
3447 std::string s = os.str();
3448 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3450 m_con.Send(peer_id, 0, data, true);
3453 void Server::SendShowFormspecMessage(u16 peer_id, const std::string formspec,
3454 const std::string formname)
3456 DSTACK(__FUNCTION_NAME);
3458 std::ostringstream os(std::ios_base::binary);
3462 writeU16(buf, TOCLIENT_SHOW_FORMSPEC);
3463 os.write((char*)buf, 2);
3464 os<<serializeLongString(formspec);
3465 os<<serializeString(formname);
3468 std::string s = os.str();
3469 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3471 m_con.Send(peer_id, 0, data, true);
3474 // Spawns a particle on peer with peer_id
3475 void Server::SendSpawnParticle(u16 peer_id, v3f pos, v3f velocity, v3f acceleration,
3476 float expirationtime, float size, bool collisiondetection,
3477 std::string texture)
3479 DSTACK(__FUNCTION_NAME);
3481 std::ostringstream os(std::ios_base::binary);
3482 writeU16(os, TOCLIENT_SPAWN_PARTICLE);
3483 writeV3F1000(os, pos);
3484 writeV3F1000(os, velocity);
3485 writeV3F1000(os, acceleration);
3486 writeF1000(os, expirationtime);
3487 writeF1000(os, size);
3488 writeU8(os, collisiondetection);
3489 os<<serializeLongString(texture);
3492 std::string s = os.str();
3493 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3495 m_con.Send(peer_id, 0, data, true);
3498 // Spawns a particle on all peers
3499 void Server::SendSpawnParticleAll(v3f pos, v3f velocity, v3f acceleration,
3500 float expirationtime, float size, bool collisiondetection,
3501 std::string texture)
3503 for(std::map<u16, RemoteClient*>::iterator
3504 i = m_clients.begin();
3505 i != m_clients.end(); i++)
3507 // Get client and check that it is valid
3508 RemoteClient *client = i->second;
3509 assert(client->peer_id == i->first);
3510 if(client->serialization_version == SER_FMT_VER_INVALID)
3513 SendSpawnParticle(client->peer_id, pos, velocity, acceleration,
3514 expirationtime, size, collisiondetection, texture);
3518 // Adds a ParticleSpawner on peer with peer_id
3519 void Server::SendAddParticleSpawner(u16 peer_id, u16 amount, float spawntime, v3f minpos, v3f maxpos,
3520 v3f minvel, v3f maxvel, v3f minacc, v3f maxacc, float minexptime, float maxexptime,
3521 float minsize, float maxsize, bool collisiondetection, std::string texture, u32 id)
3523 DSTACK(__FUNCTION_NAME);
3525 std::ostringstream os(std::ios_base::binary);
3526 writeU16(os, TOCLIENT_ADD_PARTICLESPAWNER);
3528 writeU16(os, amount);
3529 writeF1000(os, spawntime);
3530 writeV3F1000(os, minpos);
3531 writeV3F1000(os, maxpos);
3532 writeV3F1000(os, minvel);
3533 writeV3F1000(os, maxvel);
3534 writeV3F1000(os, minacc);
3535 writeV3F1000(os, maxacc);
3536 writeF1000(os, minexptime);
3537 writeF1000(os, maxexptime);
3538 writeF1000(os, minsize);
3539 writeF1000(os, maxsize);
3540 writeU8(os, collisiondetection);
3541 os<<serializeLongString(texture);
3545 std::string s = os.str();
3546 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3548 m_con.Send(peer_id, 0, data, true);
3551 // Adds a ParticleSpawner on all peers
3552 void Server::SendAddParticleSpawnerAll(u16 amount, float spawntime, v3f minpos, v3f maxpos,
3553 v3f minvel, v3f maxvel, v3f minacc, v3f maxacc, float minexptime, float maxexptime,
3554 float minsize, float maxsize, bool collisiondetection, std::string texture, u32 id)
3556 for(std::map<u16, RemoteClient*>::iterator
3557 i = m_clients.begin();
3558 i != m_clients.end(); i++)
3560 // Get client and check that it is valid
3561 RemoteClient *client = i->second;
3562 assert(client->peer_id == i->first);
3563 if(client->serialization_version == SER_FMT_VER_INVALID)
3566 SendAddParticleSpawner(client->peer_id, amount, spawntime,
3567 minpos, maxpos, minvel, maxvel, minacc, maxacc,
3568 minexptime, maxexptime, minsize, maxsize, collisiondetection, texture, id);
3572 void Server::SendDeleteParticleSpawner(u16 peer_id, u32 id)
3574 DSTACK(__FUNCTION_NAME);
3576 std::ostringstream os(std::ios_base::binary);
3577 writeU16(os, TOCLIENT_DELETE_PARTICLESPAWNER);
3582 std::string s = os.str();
3583 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3585 m_con.Send(peer_id, 0, data, true);
3588 void Server::SendDeleteParticleSpawnerAll(u32 id)
3590 for(std::map<u16, RemoteClient*>::iterator
3591 i = m_clients.begin();
3592 i != m_clients.end(); i++)
3594 // Get client and check that it is valid
3595 RemoteClient *client = i->second;
3596 assert(client->peer_id == i->first);
3597 if(client->serialization_version == SER_FMT_VER_INVALID)
3600 SendDeleteParticleSpawner(client->peer_id, id);
3604 void Server::SendHUDAdd(u16 peer_id, u32 id, HudElement *form)
3606 std::ostringstream os(std::ios_base::binary);
3609 writeU16(os, TOCLIENT_HUDADD);
3611 writeU8(os, (u8)form->type);
3612 writeV2F1000(os, form->pos);
3613 os << serializeString(form->name);
3614 writeV2F1000(os, form->scale);
3615 os << serializeString(form->text);
3616 writeU32(os, form->number);
3617 writeU32(os, form->item);
3618 writeU32(os, form->dir);
3619 writeV2F1000(os, form->align);
3620 writeV2F1000(os, form->offset);
3623 std::string s = os.str();
3624 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3626 m_con.Send(peer_id, 0, data, true);
3629 void Server::SendHUDRemove(u16 peer_id, u32 id)
3631 std::ostringstream os(std::ios_base::binary);
3634 writeU16(os, TOCLIENT_HUDRM);
3638 std::string s = os.str();
3639 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3641 m_con.Send(peer_id, 0, data, true);
3644 void Server::SendHUDChange(u16 peer_id, u32 id, HudElementStat stat, void *value)
3646 std::ostringstream os(std::ios_base::binary);
3649 writeU16(os, TOCLIENT_HUDCHANGE);
3651 writeU8(os, (u8)stat);
3654 case HUD_STAT_SCALE:
3655 case HUD_STAT_ALIGN:
3656 case HUD_STAT_OFFSET:
3657 writeV2F1000(os, *(v2f *)value);
3661 os << serializeString(*(std::string *)value);
3663 case HUD_STAT_NUMBER:
3667 writeU32(os, *(u32 *)value);
3672 std::string s = os.str();
3673 SharedBuffer<u8> data((u8 *)s.c_str(), s.size());
3675 m_con.Send(peer_id, 0, data, true);
3678 void Server::SendHUDSetFlags(u16 peer_id, u32 flags, u32 mask)
3680 std::ostringstream os(std::ios_base::binary);
3683 writeU16(os, TOCLIENT_HUD_SET_FLAGS);
3684 writeU32(os, flags);
3688 std::string s = os.str();
3689 SharedBuffer<u8> data((u8 *)s.c_str(), s.size());
3691 m_con.Send(peer_id, 0, data, true);
3694 void Server::BroadcastChatMessage(const std::wstring &message)
3696 for(std::map<u16, RemoteClient*>::iterator
3697 i = m_clients.begin();
3698 i != m_clients.end(); ++i)
3700 // Get client and check that it is valid
3701 RemoteClient *client = i->second;
3702 assert(client->peer_id == i->first);
3703 if(client->serialization_version == SER_FMT_VER_INVALID)
3706 SendChatMessage(client->peer_id, message);
3710 void Server::SendPlayerHP(u16 peer_id)
3712 DSTACK(__FUNCTION_NAME);
3713 PlayerSAO *playersao = getPlayerSAO(peer_id);
3715 playersao->m_hp_not_sent = false;
3716 SendHP(m_con, peer_id, playersao->getHP());
3719 void Server::SendMovePlayer(u16 peer_id)
3721 DSTACK(__FUNCTION_NAME);
3722 Player *player = m_env->getPlayer(peer_id);
3725 std::ostringstream os(std::ios_base::binary);
3726 writeU16(os, TOCLIENT_MOVE_PLAYER);
3727 writeV3F1000(os, player->getPosition());
3728 writeF1000(os, player->getPitch());
3729 writeF1000(os, player->getYaw());
3732 v3f pos = player->getPosition();
3733 f32 pitch = player->getPitch();
3734 f32 yaw = player->getYaw();
3735 verbosestream<<"Server: Sending TOCLIENT_MOVE_PLAYER"
3736 <<" pos=("<<pos.X<<","<<pos.Y<<","<<pos.Z<<")"
3743 std::string s = os.str();
3744 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3746 m_con.Send(peer_id, 0, data, true);
3749 void Server::SendPlayerPrivileges(u16 peer_id)
3751 Player *player = m_env->getPlayer(peer_id);
3753 if(player->peer_id == PEER_ID_INEXISTENT)
3756 std::set<std::string> privs;
3757 scriptapi_get_auth(m_lua, player->getName(), NULL, &privs);
3759 std::ostringstream os(std::ios_base::binary);
3760 writeU16(os, TOCLIENT_PRIVILEGES);
3761 writeU16(os, privs.size());
3762 for(std::set<std::string>::const_iterator i = privs.begin();
3763 i != privs.end(); i++){
3764 os<<serializeString(*i);
3768 std::string s = os.str();
3769 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3771 m_con.Send(peer_id, 0, data, true);
3774 void Server::SendPlayerInventoryFormspec(u16 peer_id)
3776 Player *player = m_env->getPlayer(peer_id);
3778 if(player->peer_id == PEER_ID_INEXISTENT)
3781 std::ostringstream os(std::ios_base::binary);
3782 writeU16(os, TOCLIENT_INVENTORY_FORMSPEC);
3783 os<<serializeLongString(player->inventory_formspec);
3786 std::string s = os.str();
3787 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3789 m_con.Send(peer_id, 0, data, true);
3792 s32 Server::playSound(const SimpleSoundSpec &spec,
3793 const ServerSoundParams ¶ms)
3795 // Find out initial position of sound
3796 bool pos_exists = false;
3797 v3f pos = params.getPos(m_env, &pos_exists);
3798 // If position is not found while it should be, cancel sound
3799 if(pos_exists != (params.type != ServerSoundParams::SSP_LOCAL))
3801 // Filter destination clients
3802 std::set<RemoteClient*> dst_clients;
3803 if(params.to_player != "")
3805 Player *player = m_env->getPlayer(params.to_player.c_str());
3807 infostream<<"Server::playSound: Player \""<<params.to_player
3808 <<"\" not found"<<std::endl;
3811 if(player->peer_id == PEER_ID_INEXISTENT){
3812 infostream<<"Server::playSound: Player \""<<params.to_player
3813 <<"\" not connected"<<std::endl;
3816 RemoteClient *client = getClient(player->peer_id);
3817 dst_clients.insert(client);
3821 for(std::map<u16, RemoteClient*>::iterator
3822 i = m_clients.begin(); i != m_clients.end(); ++i)
3824 RemoteClient *client = i->second;
3825 Player *player = m_env->getPlayer(client->peer_id);
3829 if(player->getPosition().getDistanceFrom(pos) >
3830 params.max_hear_distance)
3833 dst_clients.insert(client);
3836 if(dst_clients.size() == 0)
3839 s32 id = m_next_sound_id++;
3840 // The sound will exist as a reference in m_playing_sounds
3841 m_playing_sounds[id] = ServerPlayingSound();
3842 ServerPlayingSound &psound = m_playing_sounds[id];
3843 psound.params = params;
3844 for(std::set<RemoteClient*>::iterator i = dst_clients.begin();
3845 i != dst_clients.end(); i++)
3846 psound.clients.insert((*i)->peer_id);
3848 std::ostringstream os(std::ios_base::binary);
3849 writeU16(os, TOCLIENT_PLAY_SOUND);
3851 os<<serializeString(spec.name);
3852 writeF1000(os, spec.gain * params.gain);
3853 writeU8(os, params.type);
3854 writeV3F1000(os, pos);
3855 writeU16(os, params.object);
3856 writeU8(os, params.loop);
3858 std::string s = os.str();
3859 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3861 for(std::set<RemoteClient*>::iterator i = dst_clients.begin();
3862 i != dst_clients.end(); i++){
3864 m_con.Send((*i)->peer_id, 0, data, true);
3868 void Server::stopSound(s32 handle)
3870 // Get sound reference
3871 std::map<s32, ServerPlayingSound>::iterator i =
3872 m_playing_sounds.find(handle);
3873 if(i == m_playing_sounds.end())
3875 ServerPlayingSound &psound = i->second;
3877 std::ostringstream os(std::ios_base::binary);
3878 writeU16(os, TOCLIENT_STOP_SOUND);
3879 writeS32(os, handle);
3881 std::string s = os.str();
3882 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3884 for(std::set<u16>::iterator i = psound.clients.begin();
3885 i != psound.clients.end(); i++){
3887 m_con.Send(*i, 0, data, true);
3889 // Remove sound reference
3890 m_playing_sounds.erase(i);
3893 void Server::sendRemoveNode(v3s16 p, u16 ignore_id,
3894 std::list<u16> *far_players, float far_d_nodes)
3896 float maxd = far_d_nodes*BS;
3897 v3f p_f = intToFloat(p, BS);
3901 SharedBuffer<u8> reply(replysize);
3902 writeU16(&reply[0], TOCLIENT_REMOVENODE);
3903 writeS16(&reply[2], p.X);
3904 writeS16(&reply[4], p.Y);
3905 writeS16(&reply[6], p.Z);
3907 for(std::map<u16, RemoteClient*>::iterator
3908 i = m_clients.begin();
3909 i != m_clients.end(); ++i)
3911 // Get client and check that it is valid
3912 RemoteClient *client = i->second;
3913 assert(client->peer_id == i->first);
3914 if(client->serialization_version == SER_FMT_VER_INVALID)
3917 // Don't send if it's the same one
3918 if(client->peer_id == ignore_id)
3924 Player *player = m_env->getPlayer(client->peer_id);
3927 // If player is far away, only set modified blocks not sent
3928 v3f player_pos = player->getPosition();
3929 if(player_pos.getDistanceFrom(p_f) > maxd)
3931 far_players->push_back(client->peer_id);
3938 m_con.Send(client->peer_id, 0, reply, true);
3942 void Server::sendAddNode(v3s16 p, MapNode n, u16 ignore_id,
3943 std::list<u16> *far_players, float far_d_nodes)
3945 float maxd = far_d_nodes*BS;
3946 v3f p_f = intToFloat(p, BS);
3948 for(std::map<u16, RemoteClient*>::iterator
3949 i = m_clients.begin();
3950 i != m_clients.end(); ++i)
3952 // Get client and check that it is valid
3953 RemoteClient *client = i->second;
3954 assert(client->peer_id == i->first);
3955 if(client->serialization_version == SER_FMT_VER_INVALID)
3958 // Don't send if it's the same one
3959 if(client->peer_id == ignore_id)
3965 Player *player = m_env->getPlayer(client->peer_id);
3968 // If player is far away, only set modified blocks not sent
3969 v3f player_pos = player->getPosition();
3970 if(player_pos.getDistanceFrom(p_f) > maxd)
3972 far_players->push_back(client->peer_id);
3979 u32 replysize = 8 + MapNode::serializedLength(client->serialization_version);
3980 SharedBuffer<u8> reply(replysize);
3981 writeU16(&reply[0], TOCLIENT_ADDNODE);
3982 writeS16(&reply[2], p.X);
3983 writeS16(&reply[4], p.Y);
3984 writeS16(&reply[6], p.Z);
3985 n.serialize(&reply[8], client->serialization_version);
3988 m_con.Send(client->peer_id, 0, reply, true);
3992 void Server::setBlockNotSent(v3s16 p)
3994 for(std::map<u16, RemoteClient*>::iterator
3995 i = m_clients.begin();
3996 i != m_clients.end(); ++i)
3998 RemoteClient *client = i->second;
3999 client->SetBlockNotSent(p);
4003 void Server::SendBlockNoLock(u16 peer_id, MapBlock *block, u8 ver)
4005 DSTACK(__FUNCTION_NAME);
4007 v3s16 p = block->getPos();
4011 bool completely_air = true;
4012 for(s16 z0=0; z0<MAP_BLOCKSIZE; z0++)
4013 for(s16 x0=0; x0<MAP_BLOCKSIZE; x0++)
4014 for(s16 y0=0; y0<MAP_BLOCKSIZE; y0++)
4016 if(block->getNodeNoEx(v3s16(x0,y0,z0)).d != CONTENT_AIR)
4018 completely_air = false;
4019 x0 = y0 = z0 = MAP_BLOCKSIZE; // Break out
4024 infostream<<"Server: Sending block ("<<p.X<<","<<p.Y<<","<<p.Z<<"): ";
4026 infostream<<"[completely air] ";
4027 infostream<<std::endl;
4031 Create a packet with the block in the right format
4034 std::ostringstream os(std::ios_base::binary);
4035 block->serialize(os, ver, false);
4036 std::string s = os.str();
4037 SharedBuffer<u8> blockdata((u8*)s.c_str(), s.size());
4039 u32 replysize = 8 + blockdata.getSize();
4040 SharedBuffer<u8> reply(replysize);
4041 writeU16(&reply[0], TOCLIENT_BLOCKDATA);
4042 writeS16(&reply[2], p.X);
4043 writeS16(&reply[4], p.Y);
4044 writeS16(&reply[6], p.Z);
4045 memcpy(&reply[8], *blockdata, blockdata.getSize());
4047 /*infostream<<"Server: Sending block ("<<p.X<<","<<p.Y<<","<<p.Z<<")"
4048 <<": \tpacket size: "<<replysize<<std::endl;*/
4053 m_con.Send(peer_id, 1, reply, true);
4056 void Server::SendBlocks(float dtime)
4058 DSTACK(__FUNCTION_NAME);
4060 JMutexAutoLock envlock(m_env_mutex);
4061 JMutexAutoLock conlock(m_con_mutex);
4063 ScopeProfiler sp(g_profiler, "Server: sel and send blocks to clients");
4065 std::vector<PrioritySortedBlockTransfer> queue;
4067 s32 total_sending = 0;
4070 ScopeProfiler sp(g_profiler, "Server: selecting blocks for sending");
4072 for(std::map<u16, RemoteClient*>::iterator
4073 i = m_clients.begin();
4074 i != m_clients.end(); ++i)
4076 RemoteClient *client = i->second;
4077 assert(client->peer_id == i->first);
4079 // If definitions and textures have not been sent, don't
4080 // send MapBlocks either
4081 if(!client->definitions_sent)
4084 total_sending += client->SendingCount();
4086 if(client->serialization_version == SER_FMT_VER_INVALID)
4089 client->GetNextBlocks(this, dtime, queue);
4094 // Lowest priority number comes first.
4095 // Lowest is most important.
4096 std::sort(queue.begin(), queue.end());
4098 for(u32 i=0; i<queue.size(); i++)
4100 //TODO: Calculate limit dynamically
4101 if(total_sending >= g_settings->getS32
4102 ("max_simultaneous_block_sends_server_total"))
4105 PrioritySortedBlockTransfer q = queue[i];
4107 MapBlock *block = NULL;
4110 block = m_env->getMap().getBlockNoCreate(q.pos);
4112 catch(InvalidPositionException &e)
4117 RemoteClient *client = getClient(q.peer_id);
4119 SendBlockNoLock(q.peer_id, block, client->serialization_version);
4121 client->SentBlock(q.pos);
4127 void Server::fillMediaCache()
4129 DSTACK(__FUNCTION_NAME);
4131 infostream<<"Server: Calculating media file checksums"<<std::endl;
4133 // Collect all media file paths
4134 std::list<std::string> paths;
4135 for(std::vector<ModSpec>::iterator i = m_mods.begin();
4136 i != m_mods.end(); i++){
4137 const ModSpec &mod = *i;
4138 paths.push_back(mod.path + DIR_DELIM + "textures");
4139 paths.push_back(mod.path + DIR_DELIM + "sounds");
4140 paths.push_back(mod.path + DIR_DELIM + "media");
4141 paths.push_back(mod.path + DIR_DELIM + "models");
4143 std::string path_all = "textures";
4144 paths.push_back(path_all + DIR_DELIM + "all");
4146 // Collect media file information from paths into cache
4147 for(std::list<std::string>::iterator i = paths.begin();
4148 i != paths.end(); i++)
4150 std::string mediapath = *i;
4151 std::vector<fs::DirListNode> dirlist = fs::GetDirListing(mediapath);
4152 for(u32 j=0; j<dirlist.size(); j++){
4153 if(dirlist[j].dir) // Ignode dirs
4155 std::string filename = dirlist[j].name;
4156 // If name contains illegal characters, ignore the file
4157 if(!string_allowed(filename, TEXTURENAME_ALLOWED_CHARS)){
4158 infostream<<"Server: ignoring illegal file name: \""
4159 <<filename<<"\""<<std::endl;
4162 // If name is not in a supported format, ignore it
4163 const char *supported_ext[] = {
4164 ".png", ".jpg", ".bmp", ".tga",
4165 ".pcx", ".ppm", ".psd", ".wal", ".rgb",
4167 ".x", ".b3d", ".md2", ".obj",
4170 if(removeStringEnd(filename, supported_ext) == ""){
4171 infostream<<"Server: ignoring unsupported file extension: \""
4172 <<filename<<"\""<<std::endl;
4175 // Ok, attempt to load the file and add to cache
4176 std::string filepath = mediapath + DIR_DELIM + filename;
4178 std::ifstream fis(filepath.c_str(), std::ios_base::binary);
4179 if(fis.good() == false){
4180 errorstream<<"Server::fillMediaCache(): Could not open \""
4181 <<filename<<"\" for reading"<<std::endl;
4184 std::ostringstream tmp_os(std::ios_base::binary);
4188 fis.read(buf, 1024);
4189 std::streamsize len = fis.gcount();
4190 tmp_os.write(buf, len);
4199 errorstream<<"Server::fillMediaCache(): Failed to read \""
4200 <<filename<<"\""<<std::endl;
4203 if(tmp_os.str().length() == 0){
4204 errorstream<<"Server::fillMediaCache(): Empty file \""
4205 <<filepath<<"\""<<std::endl;
4210 sha1.addBytes(tmp_os.str().c_str(), tmp_os.str().length());
4212 unsigned char *digest = sha1.getDigest();
4213 std::string sha1_base64 = base64_encode(digest, 20);
4214 std::string sha1_hex = hex_encode((char*)digest, 20);
4218 this->m_media[filename] = MediaInfo(filepath, sha1_base64);
4219 verbosestream<<"Server: "<<sha1_hex<<" is "<<filename<<std::endl;
4224 struct SendableMediaAnnouncement
4227 std::string sha1_digest;
4229 SendableMediaAnnouncement(const std::string name_="",
4230 const std::string sha1_digest_=""):
4232 sha1_digest(sha1_digest_)
4236 void Server::sendMediaAnnouncement(u16 peer_id)
4238 DSTACK(__FUNCTION_NAME);
4240 verbosestream<<"Server: Announcing files to id("<<peer_id<<")"
4243 std::list<SendableMediaAnnouncement> file_announcements;
4245 for(std::map<std::string, MediaInfo>::iterator i = m_media.begin();
4246 i != m_media.end(); i++){
4248 file_announcements.push_back(
4249 SendableMediaAnnouncement(i->first, i->second.sha1_digest));
4253 std::ostringstream os(std::ios_base::binary);
4261 u16 length of sha1_digest
4266 writeU16(os, TOCLIENT_ANNOUNCE_MEDIA);
4267 writeU16(os, file_announcements.size());
4269 for(std::list<SendableMediaAnnouncement>::iterator
4270 j = file_announcements.begin();
4271 j != file_announcements.end(); ++j){
4272 os<<serializeString(j->name);
4273 os<<serializeString(j->sha1_digest);
4275 os<<serializeString(g_settings->get("remote_media"));
4278 std::string s = os.str();
4279 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
4282 m_con.Send(peer_id, 0, data, true);
4285 struct SendableMedia
4291 SendableMedia(const std::string &name_="", const std::string path_="",
4292 const std::string &data_=""):
4299 void Server::sendRequestedMedia(u16 peer_id,
4300 const std::list<MediaRequest> &tosend)
4302 DSTACK(__FUNCTION_NAME);
4304 verbosestream<<"Server::sendRequestedMedia(): "
4305 <<"Sending files to client"<<std::endl;
4309 // Put 5kB in one bunch (this is not accurate)
4310 u32 bytes_per_bunch = 5000;
4312 std::vector< std::list<SendableMedia> > file_bunches;
4313 file_bunches.push_back(std::list<SendableMedia>());
4315 u32 file_size_bunch_total = 0;
4317 for(std::list<MediaRequest>::const_iterator i = tosend.begin();
4318 i != tosend.end(); ++i)
4320 if(m_media.find(i->name) == m_media.end()){
4321 errorstream<<"Server::sendRequestedMedia(): Client asked for "
4322 <<"unknown file \""<<(i->name)<<"\""<<std::endl;
4326 //TODO get path + name
4327 std::string tpath = m_media[(*i).name].path;
4330 std::ifstream fis(tpath.c_str(), std::ios_base::binary);
4331 if(fis.good() == false){
4332 errorstream<<"Server::sendRequestedMedia(): Could not open \""
4333 <<tpath<<"\" for reading"<<std::endl;
4336 std::ostringstream tmp_os(std::ios_base::binary);
4340 fis.read(buf, 1024);
4341 std::streamsize len = fis.gcount();
4342 tmp_os.write(buf, len);
4343 file_size_bunch_total += len;
4352 errorstream<<"Server::sendRequestedMedia(): Failed to read \""
4353 <<(*i).name<<"\""<<std::endl;
4356 /*infostream<<"Server::sendRequestedMedia(): Loaded \""
4357 <<tname<<"\""<<std::endl;*/
4359 file_bunches[file_bunches.size()-1].push_back(
4360 SendableMedia((*i).name, tpath, tmp_os.str()));
4362 // Start next bunch if got enough data
4363 if(file_size_bunch_total >= bytes_per_bunch){
4364 file_bunches.push_back(std::list<SendableMedia>());
4365 file_size_bunch_total = 0;
4370 /* Create and send packets */
4372 u32 num_bunches = file_bunches.size();
4373 for(u32 i=0; i<num_bunches; i++)
4375 std::ostringstream os(std::ios_base::binary);
4379 u16 total number of texture bunches
4380 u16 index of this bunch
4381 u32 number of files in this bunch
4390 writeU16(os, TOCLIENT_MEDIA);
4391 writeU16(os, num_bunches);
4393 writeU32(os, file_bunches[i].size());
4395 for(std::list<SendableMedia>::iterator
4396 j = file_bunches[i].begin();
4397 j != file_bunches[i].end(); ++j){
4398 os<<serializeString(j->name);
4399 os<<serializeLongString(j->data);
4403 std::string s = os.str();
4404 verbosestream<<"Server::sendRequestedMedia(): bunch "
4405 <<i<<"/"<<num_bunches
4406 <<" files="<<file_bunches[i].size()
4407 <<" size=" <<s.size()<<std::endl;
4408 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
4410 m_con.Send(peer_id, 0, data, true);
4414 void Server::sendDetachedInventory(const std::string &name, u16 peer_id)
4416 if(m_detached_inventories.count(name) == 0){
4417 errorstream<<__FUNCTION_NAME<<": \""<<name<<"\" not found"<<std::endl;
4420 Inventory *inv = m_detached_inventories[name];
4422 std::ostringstream os(std::ios_base::binary);
4423 writeU16(os, TOCLIENT_DETACHED_INVENTORY);
4424 os<<serializeString(name);
4428 std::string s = os.str();
4429 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
4431 m_con.Send(peer_id, 0, data, true);
4434 void Server::sendDetachedInventoryToAll(const std::string &name)
4436 DSTACK(__FUNCTION_NAME);
4438 for(std::map<u16, RemoteClient*>::iterator
4439 i = m_clients.begin();
4440 i != m_clients.end(); ++i){
4441 RemoteClient *client = i->second;
4442 sendDetachedInventory(name, client->peer_id);
4446 void Server::sendDetachedInventories(u16 peer_id)
4448 DSTACK(__FUNCTION_NAME);
4450 for(std::map<std::string, Inventory*>::iterator
4451 i = m_detached_inventories.begin();
4452 i != m_detached_inventories.end(); i++){
4453 const std::string &name = i->first;
4454 //Inventory *inv = i->second;
4455 sendDetachedInventory(name, peer_id);
4463 void Server::DiePlayer(u16 peer_id)
4465 DSTACK(__FUNCTION_NAME);
4467 PlayerSAO *playersao = getPlayerSAO(peer_id);
4470 infostream<<"Server::DiePlayer(): Player "
4471 <<playersao->getPlayer()->getName()
4472 <<" dies"<<std::endl;
4474 playersao->setHP(0);
4476 // Trigger scripted stuff
4477 scriptapi_on_dieplayer(m_lua, playersao);
4479 SendPlayerHP(peer_id);
4480 SendDeathscreen(m_con, peer_id, false, v3f(0,0,0));
4483 void Server::RespawnPlayer(u16 peer_id)
4485 DSTACK(__FUNCTION_NAME);
4487 PlayerSAO *playersao = getPlayerSAO(peer_id);
4490 infostream<<"Server::RespawnPlayer(): Player "
4491 <<playersao->getPlayer()->getName()
4492 <<" respawns"<<std::endl;
4494 playersao->setHP(PLAYER_MAX_HP);
4496 bool repositioned = scriptapi_on_respawnplayer(m_lua, playersao);
4498 v3f pos = findSpawnPos(m_env->getServerMap());
4499 playersao->setPos(pos);
4503 void Server::UpdateCrafting(u16 peer_id)
4505 DSTACK(__FUNCTION_NAME);
4507 Player* player = m_env->getPlayer(peer_id);
4510 // Get a preview for crafting
4512 getCraftingResult(&player->inventory, preview, false, this);
4514 // Put the new preview in
4515 InventoryList *plist = player->inventory.getList("craftpreview");
4517 assert(plist->getSize() >= 1);
4518 plist->changeItem(0, preview);
4521 RemoteClient* Server::getClient(u16 peer_id)
4523 DSTACK(__FUNCTION_NAME);
4524 //JMutexAutoLock lock(m_con_mutex);
4525 std::map<u16, RemoteClient*>::iterator n;
4526 n = m_clients.find(peer_id);
4527 // A client should exist for all peers
4528 assert(n != m_clients.end());
4532 std::wstring Server::getStatusString()
4534 std::wostringstream os(std::ios_base::binary);
4537 os<<L"version="<<narrow_to_wide(VERSION_STRING);
4539 os<<L", uptime="<<m_uptime.get();
4540 // Information about clients
4541 std::map<u16, RemoteClient*>::iterator i;
4544 for(i = m_clients.begin(), first = true;
4545 i != m_clients.end(); ++i)
4547 // Get client and check that it is valid
4548 RemoteClient *client = i->second;
4549 assert(client->peer_id == i->first);
4550 if(client->serialization_version == SER_FMT_VER_INVALID)
4553 Player *player = m_env->getPlayer(client->peer_id);
4554 // Get name of player
4555 std::wstring name = L"unknown";
4557 name = narrow_to_wide(player->getName());
4558 // Add name to information string
4566 if(((ServerMap*)(&m_env->getMap()))->isSavingEnabled() == false)
4567 os<<std::endl<<L"# Server: "<<" WARNING: Map saving is disabled.";
4568 if(g_settings->get("motd") != "")
4569 os<<std::endl<<L"# Server: "<<narrow_to_wide(g_settings->get("motd"));
4573 std::set<std::string> Server::getPlayerEffectivePrivs(const std::string &name)
4575 std::set<std::string> privs;
4576 scriptapi_get_auth(m_lua, name, NULL, &privs);
4580 bool Server::checkPriv(const std::string &name, const std::string &priv)
4582 std::set<std::string> privs = getPlayerEffectivePrivs(name);
4583 return (privs.count(priv) != 0);
4586 void Server::reportPrivsModified(const std::string &name)
4589 for(std::map<u16, RemoteClient*>::iterator
4590 i = m_clients.begin();
4591 i != m_clients.end(); ++i){
4592 RemoteClient *client = i->second;
4593 Player *player = m_env->getPlayer(client->peer_id);
4594 reportPrivsModified(player->getName());
4597 Player *player = m_env->getPlayer(name.c_str());
4600 SendPlayerPrivileges(player->peer_id);
4601 PlayerSAO *sao = player->getPlayerSAO();
4604 sao->updatePrivileges(
4605 getPlayerEffectivePrivs(name),
4610 void Server::reportInventoryFormspecModified(const std::string &name)
4612 Player *player = m_env->getPlayer(name.c_str());
4615 SendPlayerInventoryFormspec(player->peer_id);
4618 // Saves g_settings to configpath given at initialization
4619 void Server::saveConfig()
4621 if(m_path_config != "")
4622 g_settings->updateConfigFile(m_path_config.c_str());
4625 void Server::notifyPlayer(const char *name, const std::wstring msg, const bool prepend = true)
4627 Player *player = m_env->getPlayer(name);
4631 SendChatMessage(player->peer_id, std::wstring(L"Server -!- ")+msg);
4633 SendChatMessage(player->peer_id, msg);
4636 bool Server::showFormspec(const char *playername, const std::string &formspec, const std::string &formname)
4638 Player *player = m_env->getPlayer(playername);
4642 infostream<<"showFormspec: couldn't find player:"<<playername<<std::endl;
4646 SendShowFormspecMessage(player->peer_id, formspec, formname);
4650 u32 Server::hudAdd(Player *player, HudElement *form) {
4654 u32 id = hud_get_free_id(player);
4655 if (id < player->hud.size())
4656 player->hud[id] = form;
4658 player->hud.push_back(form);
4660 SendHUDAdd(player->peer_id, id, form);
4664 bool Server::hudRemove(Player *player, u32 id) {
4665 if (!player || id >= player->hud.size() || !player->hud[id])
4668 delete player->hud[id];
4669 player->hud[id] = NULL;
4671 SendHUDRemove(player->peer_id, id);
4675 bool Server::hudChange(Player *player, u32 id, HudElementStat stat, void *data) {
4679 SendHUDChange(player->peer_id, id, stat, data);
4683 bool Server::hudSetFlags(Player *player, u32 flags, u32 mask) {
4687 SendHUDSetFlags(player->peer_id, flags, mask);
4691 void Server::notifyPlayers(const std::wstring msg)
4693 BroadcastChatMessage(msg);
4696 void Server::spawnParticle(const char *playername, v3f pos,
4697 v3f velocity, v3f acceleration,
4698 float expirationtime, float size, bool
4699 collisiondetection, std::string texture)
4701 Player *player = m_env->getPlayer(playername);
4704 SendSpawnParticle(player->peer_id, pos, velocity, acceleration,
4705 expirationtime, size, collisiondetection, texture);
4708 void Server::spawnParticleAll(v3f pos, v3f velocity, v3f acceleration,
4709 float expirationtime, float size,
4710 bool collisiondetection, std::string texture)
4712 SendSpawnParticleAll(pos, velocity, acceleration,
4713 expirationtime, size, collisiondetection, texture);
4716 u32 Server::addParticleSpawner(const char *playername,
4717 u16 amount, float spawntime,
4718 v3f minpos, v3f maxpos,
4719 v3f minvel, v3f maxvel,
4720 v3f minacc, v3f maxacc,
4721 float minexptime, float maxexptime,
4722 float minsize, float maxsize,
4723 bool collisiondetection, std::string texture)
4725 Player *player = m_env->getPlayer(playername);
4730 for(;;) // look for unused particlespawner id
4733 if (std::find(m_particlespawner_ids.begin(),
4734 m_particlespawner_ids.end(), id)
4735 == m_particlespawner_ids.end())
4737 m_particlespawner_ids.push_back(id);
4742 SendAddParticleSpawner(player->peer_id, amount, spawntime,
4743 minpos, maxpos, minvel, maxvel, minacc, maxacc,
4744 minexptime, maxexptime, minsize, maxsize,
4745 collisiondetection, texture, id);
4750 u32 Server::addParticleSpawnerAll(u16 amount, float spawntime,
4751 v3f minpos, v3f maxpos,
4752 v3f minvel, v3f maxvel,
4753 v3f minacc, v3f maxacc,
4754 float minexptime, float maxexptime,
4755 float minsize, float maxsize,
4756 bool collisiondetection, std::string texture)
4759 for(;;) // look for unused particlespawner id
4762 if (std::find(m_particlespawner_ids.begin(),
4763 m_particlespawner_ids.end(), id)
4764 == m_particlespawner_ids.end())
4766 m_particlespawner_ids.push_back(id);
4771 SendAddParticleSpawnerAll(amount, spawntime,
4772 minpos, maxpos, minvel, maxvel, minacc, maxacc,
4773 minexptime, maxexptime, minsize, maxsize,
4774 collisiondetection, texture, id);
4779 void Server::deleteParticleSpawner(const char *playername, u32 id)
4781 Player *player = m_env->getPlayer(playername);
4785 m_particlespawner_ids.erase(
4786 std::remove(m_particlespawner_ids.begin(),
4787 m_particlespawner_ids.end(), id),
4788 m_particlespawner_ids.end());
4789 SendDeleteParticleSpawner(player->peer_id, id);
4792 void Server::deleteParticleSpawnerAll(u32 id)
4794 m_particlespawner_ids.erase(
4795 std::remove(m_particlespawner_ids.begin(),
4796 m_particlespawner_ids.end(), id),
4797 m_particlespawner_ids.end());
4798 SendDeleteParticleSpawnerAll(id);
4801 void Server::queueBlockEmerge(v3s16 blockpos, bool allow_generate)
4803 m_emerge->enqueueBlockEmerge(PEER_ID_INEXISTENT, blockpos, allow_generate);
4806 Inventory* Server::createDetachedInventory(const std::string &name)
4808 if(m_detached_inventories.count(name) > 0){
4809 infostream<<"Server clearing detached inventory \""<<name<<"\""<<std::endl;
4810 delete m_detached_inventories[name];
4812 infostream<<"Server creating detached inventory \""<<name<<"\""<<std::endl;
4814 Inventory *inv = new Inventory(m_itemdef);
4816 m_detached_inventories[name] = inv;
4817 sendDetachedInventoryToAll(name);
4824 BoolScopeSet(bool *dst, bool val):
4827 m_orig_state = *m_dst;
4832 *m_dst = m_orig_state;
4839 // actions: time-reversed list
4840 // Return value: success/failure
4841 bool Server::rollbackRevertActions(const std::list<RollbackAction> &actions,
4842 std::list<std::string> *log)
4844 infostream<<"Server::rollbackRevertActions(len="<<actions.size()<<")"<<std::endl;
4845 ServerMap *map = (ServerMap*)(&m_env->getMap());
4846 // Disable rollback report sink while reverting
4847 BoolScopeSet rollback_scope_disable(&m_rollback_sink_enabled, false);
4849 // Fail if no actions to handle
4850 if(actions.empty()){
4851 log->push_back("Nothing to do.");
4858 for(std::list<RollbackAction>::const_iterator
4859 i = actions.begin();
4860 i != actions.end(); i++)
4862 const RollbackAction &action = *i;
4864 bool success = action.applyRevert(map, this, this);
4867 std::ostringstream os;
4868 os<<"Revert of step ("<<num_tried<<") "<<action.toString()<<" failed";
4869 infostream<<"Map::rollbackRevertActions(): "<<os.str()<<std::endl;
4871 log->push_back(os.str());
4873 std::ostringstream os;
4874 os<<"Successfully reverted step ("<<num_tried<<") "<<action.toString();
4875 infostream<<"Map::rollbackRevertActions(): "<<os.str()<<std::endl;
4877 log->push_back(os.str());
4881 infostream<<"Map::rollbackRevertActions(): "<<num_failed<<"/"<<num_tried
4882 <<" failed"<<std::endl;
4884 // Call it done if less than half failed
4885 return num_failed <= num_tried/2;
4888 // IGameDef interface
4890 IItemDefManager* Server::getItemDefManager()
4894 INodeDefManager* Server::getNodeDefManager()
4898 ICraftDefManager* Server::getCraftDefManager()
4902 ITextureSource* Server::getTextureSource()
4906 IShaderSource* Server::getShaderSource()
4910 u16 Server::allocateUnknownNodeId(const std::string &name)
4912 return m_nodedef->allocateDummy(name);
4914 ISoundManager* Server::getSoundManager()
4916 return &dummySoundManager;
4918 MtEventManager* Server::getEventManager()
4922 IRollbackReportSink* Server::getRollbackReportSink()
4924 if(!m_enable_rollback_recording)
4926 if(!m_rollback_sink_enabled)
4931 IWritableItemDefManager* Server::getWritableItemDefManager()
4935 IWritableNodeDefManager* Server::getWritableNodeDefManager()
4939 IWritableCraftDefManager* Server::getWritableCraftDefManager()
4944 const ModSpec* Server::getModSpec(const std::string &modname)
4946 for(std::vector<ModSpec>::iterator i = m_mods.begin();
4947 i != m_mods.end(); i++){
4948 const ModSpec &mod = *i;
4949 if(mod.name == modname)
4954 void Server::getModNames(std::list<std::string> &modlist)
4956 for(std::vector<ModSpec>::iterator i = m_mods.begin(); i != m_mods.end(); i++)
4958 modlist.push_back(i->name);
4961 std::string Server::getBuiltinLuaPath()
4963 return porting::path_share + DIR_DELIM + "builtin";
4966 v3f findSpawnPos(ServerMap &map)
4968 //return v3f(50,50,50)*BS;
4973 nodepos = v2s16(0,0);
4978 s16 water_level = map.m_mgparams->water_level;
4980 // Try to find a good place a few times
4981 for(s32 i=0; i<1000; i++)
4984 // We're going to try to throw the player to this position
4985 v2s16 nodepos2d = v2s16(
4986 -range + (myrand() % (range * 2)),
4987 -range + (myrand() % (range * 2)));
4989 // Get ground height at point
4990 s16 groundheight = map.findGroundLevel(nodepos2d);
4991 if (groundheight <= water_level) // Don't go underwater
4993 if (groundheight > water_level + 6) // Don't go to high places
4996 nodepos = v3s16(nodepos2d.X, groundheight, nodepos2d.Y);
4997 bool is_good = false;
4999 for (s32 i = 0; i < 10; i++) {
5000 v3s16 blockpos = getNodeBlockPos(nodepos);
5001 map.emergeBlock(blockpos, true);
5002 content_t c = map.getNodeNoEx(nodepos).getContent();
5003 if (c == CONTENT_AIR || c == CONTENT_IGNORE) {
5005 if (air_count >= 2){
5013 // Found a good place
5014 //infostream<<"Searched through "<<i<<" places."<<std::endl;
5020 return intToFloat(nodepos, BS);
5023 PlayerSAO* Server::emergePlayer(const char *name, u16 peer_id)
5025 RemotePlayer *player = NULL;
5026 bool newplayer = false;
5029 Try to get an existing player
5031 player = static_cast<RemotePlayer*>(m_env->getPlayer(name));
5033 // If player is already connected, cancel
5034 if(player != NULL && player->peer_id != 0)
5036 infostream<<"emergePlayer(): Player already connected"<<std::endl;
5041 If player with the wanted peer_id already exists, cancel.
5043 if(m_env->getPlayer(peer_id) != NULL)
5045 infostream<<"emergePlayer(): Player with wrong name but same"
5046 " peer_id already exists"<<std::endl;
5051 Create a new player if it doesn't exist yet
5056 player = new RemotePlayer(this);
5057 player->updateName(name);
5059 /* Set player position */
5060 infostream<<"Server: Finding spawn place for player \""
5061 <<name<<"\""<<std::endl;
5062 v3f pos = findSpawnPos(m_env->getServerMap());
5063 player->setPosition(pos);
5065 /* Add player to environment */
5066 m_env->addPlayer(player);
5070 Create a new player active object
5072 PlayerSAO *playersao = new PlayerSAO(m_env, player, peer_id,
5073 getPlayerEffectivePrivs(player->getName()),
5076 /* Add object to environment */
5077 m_env->addActiveObject(playersao);
5081 scriptapi_on_newplayer(m_lua, playersao);
5083 scriptapi_on_joinplayer(m_lua, playersao);
5088 void Server::handlePeerChange(PeerChange &c)
5090 JMutexAutoLock envlock(m_env_mutex);
5091 JMutexAutoLock conlock(m_con_mutex);
5093 if(c.type == PEER_ADDED)
5100 std::map<u16, RemoteClient*>::iterator n;
5101 n = m_clients.find(c.peer_id);
5102 // The client shouldn't already exist
5103 assert(n == m_clients.end());
5106 RemoteClient *client = new RemoteClient();
5107 client->peer_id = c.peer_id;
5108 m_clients[client->peer_id] = client;
5111 else if(c.type == PEER_REMOVED)
5118 std::map<u16, RemoteClient*>::iterator n;
5119 n = m_clients.find(c.peer_id);
5120 // The client should exist
5121 assert(n != m_clients.end());
5124 Mark objects to be not known by the client
5126 RemoteClient *client = n->second;
5128 for(std::set<u16>::iterator
5129 i = client->m_known_objects.begin();
5130 i != client->m_known_objects.end(); ++i)
5134 ServerActiveObject* obj = m_env->getActiveObject(id);
5136 if(obj && obj->m_known_by_count > 0)
5137 obj->m_known_by_count--;
5141 Clear references to playing sounds
5143 for(std::map<s32, ServerPlayingSound>::iterator
5144 i = m_playing_sounds.begin();
5145 i != m_playing_sounds.end();)
5147 ServerPlayingSound &psound = i->second;
5148 psound.clients.erase(c.peer_id);
5149 if(psound.clients.size() == 0)
5150 m_playing_sounds.erase(i++);
5155 Player *player = m_env->getPlayer(c.peer_id);
5157 // Collect information about leaving in chat
5158 std::wstring message;
5162 std::wstring name = narrow_to_wide(player->getName());
5165 message += L" left the game.";
5167 message += L" (timed out)";
5171 /* Run scripts and remove from environment */
5175 PlayerSAO *playersao = player->getPlayerSAO();
5178 scriptapi_on_leaveplayer(m_lua, playersao);
5180 playersao->disconnected();
5190 std::ostringstream os(std::ios_base::binary);
5191 for(std::map<u16, RemoteClient*>::iterator
5192 i = m_clients.begin();
5193 i != m_clients.end(); ++i)
5195 RemoteClient *client = i->second;
5196 assert(client->peer_id == i->first);
5197 if(client->serialization_version == SER_FMT_VER_INVALID)
5200 Player *player = m_env->getPlayer(client->peer_id);
5203 // Get name of player
5204 os<<player->getName()<<" ";
5207 actionstream<<player->getName()<<" "
5208 <<(c.timeout?"times out.":"leaves game.")
5209 <<" List of players: "
5210 <<os.str()<<std::endl;
5215 delete m_clients[c.peer_id];
5216 m_clients.erase(c.peer_id);
5218 // Send player info to all remaining clients
5219 //SendPlayerInfos();
5221 // Send leave chat message to all remaining clients
5222 if(message.length() != 0)
5223 BroadcastChatMessage(message);
5232 void Server::handlePeerChanges()
5234 while(m_peer_change_queue.size() > 0)
5236 PeerChange c = m_peer_change_queue.pop_front();
5238 verbosestream<<"Server: Handling peer change: "
5239 <<"id="<<c.peer_id<<", timeout="<<c.timeout
5242 handlePeerChange(c);
5246 void dedicated_server_loop(Server &server, bool &kill)
5248 DSTACK(__FUNCTION_NAME);
5250 verbosestream<<"dedicated_server_loop()"<<std::endl;
5252 IntervalLimiter m_profiler_interval;
5256 float steplen = g_settings->getFloat("dedicated_server_step");
5257 // This is kind of a hack but can be done like this
5258 // because server.step() is very light
5260 ScopeProfiler sp(g_profiler, "dedicated server sleep");
5261 sleep_ms((int)(steplen*1000.0));
5263 server.step(steplen);
5265 if(server.getShutdownRequested() || kill)
5267 infostream<<"Dedicated server quitting"<<std::endl;
5269 if(g_settings->getBool("server_announce") == true)
5270 ServerList::sendAnnounce("delete");
5278 float profiler_print_interval =
5279 g_settings->getFloat("profiler_print_interval");
5280 if(profiler_print_interval != 0)
5282 if(m_profiler_interval.step(steplen, profiler_print_interval))
5284 infostream<<"Profiler:"<<std::endl;
5285 g_profiler->print(infostream);
5286 g_profiler->clear();