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);
3621 std::string s = os.str();
3622 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3624 m_con.Send(peer_id, 0, data, true);
3627 void Server::SendHUDRemove(u16 peer_id, u32 id)
3629 std::ostringstream os(std::ios_base::binary);
3632 writeU16(os, TOCLIENT_HUDRM);
3636 std::string s = os.str();
3637 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3639 m_con.Send(peer_id, 0, data, true);
3642 void Server::SendHUDChange(u16 peer_id, u32 id, HudElementStat stat, void *value)
3644 std::ostringstream os(std::ios_base::binary);
3647 writeU16(os, TOCLIENT_HUDCHANGE);
3649 writeU8(os, (u8)stat);
3652 case HUD_STAT_SCALE:
3653 writeV2F1000(os, *(v2f *)value);
3657 os << serializeString(*(std::string *)value);
3659 case HUD_STAT_NUMBER:
3663 writeU32(os, *(u32 *)value);
3668 std::string s = os.str();
3669 SharedBuffer<u8> data((u8 *)s.c_str(), s.size());
3671 m_con.Send(peer_id, 0, data, true);
3674 void Server::BroadcastChatMessage(const std::wstring &message)
3676 for(std::map<u16, RemoteClient*>::iterator
3677 i = m_clients.begin();
3678 i != m_clients.end(); ++i)
3680 // Get client and check that it is valid
3681 RemoteClient *client = i->second;
3682 assert(client->peer_id == i->first);
3683 if(client->serialization_version == SER_FMT_VER_INVALID)
3686 SendChatMessage(client->peer_id, message);
3690 void Server::SendPlayerHP(u16 peer_id)
3692 DSTACK(__FUNCTION_NAME);
3693 PlayerSAO *playersao = getPlayerSAO(peer_id);
3695 playersao->m_hp_not_sent = false;
3696 SendHP(m_con, peer_id, playersao->getHP());
3699 void Server::SendMovePlayer(u16 peer_id)
3701 DSTACK(__FUNCTION_NAME);
3702 Player *player = m_env->getPlayer(peer_id);
3705 std::ostringstream os(std::ios_base::binary);
3706 writeU16(os, TOCLIENT_MOVE_PLAYER);
3707 writeV3F1000(os, player->getPosition());
3708 writeF1000(os, player->getPitch());
3709 writeF1000(os, player->getYaw());
3712 v3f pos = player->getPosition();
3713 f32 pitch = player->getPitch();
3714 f32 yaw = player->getYaw();
3715 verbosestream<<"Server: Sending TOCLIENT_MOVE_PLAYER"
3716 <<" pos=("<<pos.X<<","<<pos.Y<<","<<pos.Z<<")"
3723 std::string s = os.str();
3724 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3726 m_con.Send(peer_id, 0, data, true);
3729 void Server::SendPlayerPrivileges(u16 peer_id)
3731 Player *player = m_env->getPlayer(peer_id);
3733 if(player->peer_id == PEER_ID_INEXISTENT)
3736 std::set<std::string> privs;
3737 scriptapi_get_auth(m_lua, player->getName(), NULL, &privs);
3739 std::ostringstream os(std::ios_base::binary);
3740 writeU16(os, TOCLIENT_PRIVILEGES);
3741 writeU16(os, privs.size());
3742 for(std::set<std::string>::const_iterator i = privs.begin();
3743 i != privs.end(); i++){
3744 os<<serializeString(*i);
3748 std::string s = os.str();
3749 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3751 m_con.Send(peer_id, 0, data, true);
3754 void Server::SendPlayerInventoryFormspec(u16 peer_id)
3756 Player *player = m_env->getPlayer(peer_id);
3758 if(player->peer_id == PEER_ID_INEXISTENT)
3761 std::ostringstream os(std::ios_base::binary);
3762 writeU16(os, TOCLIENT_INVENTORY_FORMSPEC);
3763 os<<serializeLongString(player->inventory_formspec);
3766 std::string s = os.str();
3767 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3769 m_con.Send(peer_id, 0, data, true);
3772 s32 Server::playSound(const SimpleSoundSpec &spec,
3773 const ServerSoundParams ¶ms)
3775 // Find out initial position of sound
3776 bool pos_exists = false;
3777 v3f pos = params.getPos(m_env, &pos_exists);
3778 // If position is not found while it should be, cancel sound
3779 if(pos_exists != (params.type != ServerSoundParams::SSP_LOCAL))
3781 // Filter destination clients
3782 std::set<RemoteClient*> dst_clients;
3783 if(params.to_player != "")
3785 Player *player = m_env->getPlayer(params.to_player.c_str());
3787 infostream<<"Server::playSound: Player \""<<params.to_player
3788 <<"\" not found"<<std::endl;
3791 if(player->peer_id == PEER_ID_INEXISTENT){
3792 infostream<<"Server::playSound: Player \""<<params.to_player
3793 <<"\" not connected"<<std::endl;
3796 RemoteClient *client = getClient(player->peer_id);
3797 dst_clients.insert(client);
3801 for(std::map<u16, RemoteClient*>::iterator
3802 i = m_clients.begin(); i != m_clients.end(); ++i)
3804 RemoteClient *client = i->second;
3805 Player *player = m_env->getPlayer(client->peer_id);
3809 if(player->getPosition().getDistanceFrom(pos) >
3810 params.max_hear_distance)
3813 dst_clients.insert(client);
3816 if(dst_clients.size() == 0)
3819 s32 id = m_next_sound_id++;
3820 // The sound will exist as a reference in m_playing_sounds
3821 m_playing_sounds[id] = ServerPlayingSound();
3822 ServerPlayingSound &psound = m_playing_sounds[id];
3823 psound.params = params;
3824 for(std::set<RemoteClient*>::iterator i = dst_clients.begin();
3825 i != dst_clients.end(); i++)
3826 psound.clients.insert((*i)->peer_id);
3828 std::ostringstream os(std::ios_base::binary);
3829 writeU16(os, TOCLIENT_PLAY_SOUND);
3831 os<<serializeString(spec.name);
3832 writeF1000(os, spec.gain * params.gain);
3833 writeU8(os, params.type);
3834 writeV3F1000(os, pos);
3835 writeU16(os, params.object);
3836 writeU8(os, params.loop);
3838 std::string s = os.str();
3839 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3841 for(std::set<RemoteClient*>::iterator i = dst_clients.begin();
3842 i != dst_clients.end(); i++){
3844 m_con.Send((*i)->peer_id, 0, data, true);
3848 void Server::stopSound(s32 handle)
3850 // Get sound reference
3851 std::map<s32, ServerPlayingSound>::iterator i =
3852 m_playing_sounds.find(handle);
3853 if(i == m_playing_sounds.end())
3855 ServerPlayingSound &psound = i->second;
3857 std::ostringstream os(std::ios_base::binary);
3858 writeU16(os, TOCLIENT_STOP_SOUND);
3859 writeS32(os, handle);
3861 std::string s = os.str();
3862 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3864 for(std::set<u16>::iterator i = psound.clients.begin();
3865 i != psound.clients.end(); i++){
3867 m_con.Send(*i, 0, data, true);
3869 // Remove sound reference
3870 m_playing_sounds.erase(i);
3873 void Server::sendRemoveNode(v3s16 p, u16 ignore_id,
3874 std::list<u16> *far_players, float far_d_nodes)
3876 float maxd = far_d_nodes*BS;
3877 v3f p_f = intToFloat(p, BS);
3881 SharedBuffer<u8> reply(replysize);
3882 writeU16(&reply[0], TOCLIENT_REMOVENODE);
3883 writeS16(&reply[2], p.X);
3884 writeS16(&reply[4], p.Y);
3885 writeS16(&reply[6], p.Z);
3887 for(std::map<u16, RemoteClient*>::iterator
3888 i = m_clients.begin();
3889 i != m_clients.end(); ++i)
3891 // Get client and check that it is valid
3892 RemoteClient *client = i->second;
3893 assert(client->peer_id == i->first);
3894 if(client->serialization_version == SER_FMT_VER_INVALID)
3897 // Don't send if it's the same one
3898 if(client->peer_id == ignore_id)
3904 Player *player = m_env->getPlayer(client->peer_id);
3907 // If player is far away, only set modified blocks not sent
3908 v3f player_pos = player->getPosition();
3909 if(player_pos.getDistanceFrom(p_f) > maxd)
3911 far_players->push_back(client->peer_id);
3918 m_con.Send(client->peer_id, 0, reply, true);
3922 void Server::sendAddNode(v3s16 p, MapNode n, u16 ignore_id,
3923 std::list<u16> *far_players, float far_d_nodes)
3925 float maxd = far_d_nodes*BS;
3926 v3f p_f = intToFloat(p, BS);
3928 for(std::map<u16, RemoteClient*>::iterator
3929 i = m_clients.begin();
3930 i != m_clients.end(); ++i)
3932 // Get client and check that it is valid
3933 RemoteClient *client = i->second;
3934 assert(client->peer_id == i->first);
3935 if(client->serialization_version == SER_FMT_VER_INVALID)
3938 // Don't send if it's the same one
3939 if(client->peer_id == ignore_id)
3945 Player *player = m_env->getPlayer(client->peer_id);
3948 // If player is far away, only set modified blocks not sent
3949 v3f player_pos = player->getPosition();
3950 if(player_pos.getDistanceFrom(p_f) > maxd)
3952 far_players->push_back(client->peer_id);
3959 u32 replysize = 8 + MapNode::serializedLength(client->serialization_version);
3960 SharedBuffer<u8> reply(replysize);
3961 writeU16(&reply[0], TOCLIENT_ADDNODE);
3962 writeS16(&reply[2], p.X);
3963 writeS16(&reply[4], p.Y);
3964 writeS16(&reply[6], p.Z);
3965 n.serialize(&reply[8], client->serialization_version);
3968 m_con.Send(client->peer_id, 0, reply, true);
3972 void Server::setBlockNotSent(v3s16 p)
3974 for(std::map<u16, RemoteClient*>::iterator
3975 i = m_clients.begin();
3976 i != m_clients.end(); ++i)
3978 RemoteClient *client = i->second;
3979 client->SetBlockNotSent(p);
3983 void Server::SendBlockNoLock(u16 peer_id, MapBlock *block, u8 ver)
3985 DSTACK(__FUNCTION_NAME);
3987 v3s16 p = block->getPos();
3991 bool completely_air = true;
3992 for(s16 z0=0; z0<MAP_BLOCKSIZE; z0++)
3993 for(s16 x0=0; x0<MAP_BLOCKSIZE; x0++)
3994 for(s16 y0=0; y0<MAP_BLOCKSIZE; y0++)
3996 if(block->getNodeNoEx(v3s16(x0,y0,z0)).d != CONTENT_AIR)
3998 completely_air = false;
3999 x0 = y0 = z0 = MAP_BLOCKSIZE; // Break out
4004 infostream<<"Server: Sending block ("<<p.X<<","<<p.Y<<","<<p.Z<<"): ";
4006 infostream<<"[completely air] ";
4007 infostream<<std::endl;
4011 Create a packet with the block in the right format
4014 std::ostringstream os(std::ios_base::binary);
4015 block->serialize(os, ver, false);
4016 std::string s = os.str();
4017 SharedBuffer<u8> blockdata((u8*)s.c_str(), s.size());
4019 u32 replysize = 8 + blockdata.getSize();
4020 SharedBuffer<u8> reply(replysize);
4021 writeU16(&reply[0], TOCLIENT_BLOCKDATA);
4022 writeS16(&reply[2], p.X);
4023 writeS16(&reply[4], p.Y);
4024 writeS16(&reply[6], p.Z);
4025 memcpy(&reply[8], *blockdata, blockdata.getSize());
4027 /*infostream<<"Server: Sending block ("<<p.X<<","<<p.Y<<","<<p.Z<<")"
4028 <<": \tpacket size: "<<replysize<<std::endl;*/
4033 m_con.Send(peer_id, 1, reply, true);
4036 void Server::SendBlocks(float dtime)
4038 DSTACK(__FUNCTION_NAME);
4040 JMutexAutoLock envlock(m_env_mutex);
4041 JMutexAutoLock conlock(m_con_mutex);
4043 ScopeProfiler sp(g_profiler, "Server: sel and send blocks to clients");
4045 std::vector<PrioritySortedBlockTransfer> queue;
4047 s32 total_sending = 0;
4050 ScopeProfiler sp(g_profiler, "Server: selecting blocks for sending");
4052 for(std::map<u16, RemoteClient*>::iterator
4053 i = m_clients.begin();
4054 i != m_clients.end(); ++i)
4056 RemoteClient *client = i->second;
4057 assert(client->peer_id == i->first);
4059 // If definitions and textures have not been sent, don't
4060 // send MapBlocks either
4061 if(!client->definitions_sent)
4064 total_sending += client->SendingCount();
4066 if(client->serialization_version == SER_FMT_VER_INVALID)
4069 client->GetNextBlocks(this, dtime, queue);
4074 // Lowest priority number comes first.
4075 // Lowest is most important.
4076 std::sort(queue.begin(), queue.end());
4078 for(u32 i=0; i<queue.size(); i++)
4080 //TODO: Calculate limit dynamically
4081 if(total_sending >= g_settings->getS32
4082 ("max_simultaneous_block_sends_server_total"))
4085 PrioritySortedBlockTransfer q = queue[i];
4087 MapBlock *block = NULL;
4090 block = m_env->getMap().getBlockNoCreate(q.pos);
4092 catch(InvalidPositionException &e)
4097 RemoteClient *client = getClient(q.peer_id);
4099 SendBlockNoLock(q.peer_id, block, client->serialization_version);
4101 client->SentBlock(q.pos);
4107 void Server::fillMediaCache()
4109 DSTACK(__FUNCTION_NAME);
4111 infostream<<"Server: Calculating media file checksums"<<std::endl;
4113 // Collect all media file paths
4114 std::list<std::string> paths;
4115 for(std::vector<ModSpec>::iterator i = m_mods.begin();
4116 i != m_mods.end(); i++){
4117 const ModSpec &mod = *i;
4118 paths.push_back(mod.path + DIR_DELIM + "textures");
4119 paths.push_back(mod.path + DIR_DELIM + "sounds");
4120 paths.push_back(mod.path + DIR_DELIM + "media");
4121 paths.push_back(mod.path + DIR_DELIM + "models");
4123 std::string path_all = "textures";
4124 paths.push_back(path_all + DIR_DELIM + "all");
4126 // Collect media file information from paths into cache
4127 for(std::list<std::string>::iterator i = paths.begin();
4128 i != paths.end(); i++)
4130 std::string mediapath = *i;
4131 std::vector<fs::DirListNode> dirlist = fs::GetDirListing(mediapath);
4132 for(u32 j=0; j<dirlist.size(); j++){
4133 if(dirlist[j].dir) // Ignode dirs
4135 std::string filename = dirlist[j].name;
4136 // If name contains illegal characters, ignore the file
4137 if(!string_allowed(filename, TEXTURENAME_ALLOWED_CHARS)){
4138 infostream<<"Server: ignoring illegal file name: \""
4139 <<filename<<"\""<<std::endl;
4142 // If name is not in a supported format, ignore it
4143 const char *supported_ext[] = {
4144 ".png", ".jpg", ".bmp", ".tga",
4145 ".pcx", ".ppm", ".psd", ".wal", ".rgb",
4147 ".x", ".b3d", ".md2", ".obj",
4150 if(removeStringEnd(filename, supported_ext) == ""){
4151 infostream<<"Server: ignoring unsupported file extension: \""
4152 <<filename<<"\""<<std::endl;
4155 // Ok, attempt to load the file and add to cache
4156 std::string filepath = mediapath + DIR_DELIM + filename;
4158 std::ifstream fis(filepath.c_str(), std::ios_base::binary);
4159 if(fis.good() == false){
4160 errorstream<<"Server::fillMediaCache(): Could not open \""
4161 <<filename<<"\" for reading"<<std::endl;
4164 std::ostringstream tmp_os(std::ios_base::binary);
4168 fis.read(buf, 1024);
4169 std::streamsize len = fis.gcount();
4170 tmp_os.write(buf, len);
4179 errorstream<<"Server::fillMediaCache(): Failed to read \""
4180 <<filename<<"\""<<std::endl;
4183 if(tmp_os.str().length() == 0){
4184 errorstream<<"Server::fillMediaCache(): Empty file \""
4185 <<filepath<<"\""<<std::endl;
4190 sha1.addBytes(tmp_os.str().c_str(), tmp_os.str().length());
4192 unsigned char *digest = sha1.getDigest();
4193 std::string sha1_base64 = base64_encode(digest, 20);
4194 std::string sha1_hex = hex_encode((char*)digest, 20);
4198 this->m_media[filename] = MediaInfo(filepath, sha1_base64);
4199 verbosestream<<"Server: "<<sha1_hex<<" is "<<filename<<std::endl;
4204 struct SendableMediaAnnouncement
4207 std::string sha1_digest;
4209 SendableMediaAnnouncement(const std::string name_="",
4210 const std::string sha1_digest_=""):
4212 sha1_digest(sha1_digest_)
4216 void Server::sendMediaAnnouncement(u16 peer_id)
4218 DSTACK(__FUNCTION_NAME);
4220 verbosestream<<"Server: Announcing files to id("<<peer_id<<")"
4223 std::list<SendableMediaAnnouncement> file_announcements;
4225 for(std::map<std::string, MediaInfo>::iterator i = m_media.begin();
4226 i != m_media.end(); i++){
4228 file_announcements.push_back(
4229 SendableMediaAnnouncement(i->first, i->second.sha1_digest));
4233 std::ostringstream os(std::ios_base::binary);
4241 u16 length of sha1_digest
4246 writeU16(os, TOCLIENT_ANNOUNCE_MEDIA);
4247 writeU16(os, file_announcements.size());
4249 for(std::list<SendableMediaAnnouncement>::iterator
4250 j = file_announcements.begin();
4251 j != file_announcements.end(); ++j){
4252 os<<serializeString(j->name);
4253 os<<serializeString(j->sha1_digest);
4255 os<<serializeString(g_settings->get("remote_media"));
4258 std::string s = os.str();
4259 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
4262 m_con.Send(peer_id, 0, data, true);
4265 struct SendableMedia
4271 SendableMedia(const std::string &name_="", const std::string path_="",
4272 const std::string &data_=""):
4279 void Server::sendRequestedMedia(u16 peer_id,
4280 const std::list<MediaRequest> &tosend)
4282 DSTACK(__FUNCTION_NAME);
4284 verbosestream<<"Server::sendRequestedMedia(): "
4285 <<"Sending files to client"<<std::endl;
4289 // Put 5kB in one bunch (this is not accurate)
4290 u32 bytes_per_bunch = 5000;
4292 std::vector< std::list<SendableMedia> > file_bunches;
4293 file_bunches.push_back(std::list<SendableMedia>());
4295 u32 file_size_bunch_total = 0;
4297 for(std::list<MediaRequest>::const_iterator i = tosend.begin();
4298 i != tosend.end(); ++i)
4300 if(m_media.find(i->name) == m_media.end()){
4301 errorstream<<"Server::sendRequestedMedia(): Client asked for "
4302 <<"unknown file \""<<(i->name)<<"\""<<std::endl;
4306 //TODO get path + name
4307 std::string tpath = m_media[(*i).name].path;
4310 std::ifstream fis(tpath.c_str(), std::ios_base::binary);
4311 if(fis.good() == false){
4312 errorstream<<"Server::sendRequestedMedia(): Could not open \""
4313 <<tpath<<"\" for reading"<<std::endl;
4316 std::ostringstream tmp_os(std::ios_base::binary);
4320 fis.read(buf, 1024);
4321 std::streamsize len = fis.gcount();
4322 tmp_os.write(buf, len);
4323 file_size_bunch_total += len;
4332 errorstream<<"Server::sendRequestedMedia(): Failed to read \""
4333 <<(*i).name<<"\""<<std::endl;
4336 /*infostream<<"Server::sendRequestedMedia(): Loaded \""
4337 <<tname<<"\""<<std::endl;*/
4339 file_bunches[file_bunches.size()-1].push_back(
4340 SendableMedia((*i).name, tpath, tmp_os.str()));
4342 // Start next bunch if got enough data
4343 if(file_size_bunch_total >= bytes_per_bunch){
4344 file_bunches.push_back(std::list<SendableMedia>());
4345 file_size_bunch_total = 0;
4350 /* Create and send packets */
4352 u32 num_bunches = file_bunches.size();
4353 for(u32 i=0; i<num_bunches; i++)
4355 std::ostringstream os(std::ios_base::binary);
4359 u16 total number of texture bunches
4360 u16 index of this bunch
4361 u32 number of files in this bunch
4370 writeU16(os, TOCLIENT_MEDIA);
4371 writeU16(os, num_bunches);
4373 writeU32(os, file_bunches[i].size());
4375 for(std::list<SendableMedia>::iterator
4376 j = file_bunches[i].begin();
4377 j != file_bunches[i].end(); ++j){
4378 os<<serializeString(j->name);
4379 os<<serializeLongString(j->data);
4383 std::string s = os.str();
4384 verbosestream<<"Server::sendRequestedMedia(): bunch "
4385 <<i<<"/"<<num_bunches
4386 <<" files="<<file_bunches[i].size()
4387 <<" size=" <<s.size()<<std::endl;
4388 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
4390 m_con.Send(peer_id, 0, data, true);
4394 void Server::sendDetachedInventory(const std::string &name, u16 peer_id)
4396 if(m_detached_inventories.count(name) == 0){
4397 errorstream<<__FUNCTION_NAME<<": \""<<name<<"\" not found"<<std::endl;
4400 Inventory *inv = m_detached_inventories[name];
4402 std::ostringstream os(std::ios_base::binary);
4403 writeU16(os, TOCLIENT_DETACHED_INVENTORY);
4404 os<<serializeString(name);
4408 std::string s = os.str();
4409 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
4411 m_con.Send(peer_id, 0, data, true);
4414 void Server::sendDetachedInventoryToAll(const std::string &name)
4416 DSTACK(__FUNCTION_NAME);
4418 for(std::map<u16, RemoteClient*>::iterator
4419 i = m_clients.begin();
4420 i != m_clients.end(); ++i){
4421 RemoteClient *client = i->second;
4422 sendDetachedInventory(name, client->peer_id);
4426 void Server::sendDetachedInventories(u16 peer_id)
4428 DSTACK(__FUNCTION_NAME);
4430 for(std::map<std::string, Inventory*>::iterator
4431 i = m_detached_inventories.begin();
4432 i != m_detached_inventories.end(); i++){
4433 const std::string &name = i->first;
4434 //Inventory *inv = i->second;
4435 sendDetachedInventory(name, peer_id);
4443 void Server::DiePlayer(u16 peer_id)
4445 DSTACK(__FUNCTION_NAME);
4447 PlayerSAO *playersao = getPlayerSAO(peer_id);
4450 infostream<<"Server::DiePlayer(): Player "
4451 <<playersao->getPlayer()->getName()
4452 <<" dies"<<std::endl;
4454 playersao->setHP(0);
4456 // Trigger scripted stuff
4457 scriptapi_on_dieplayer(m_lua, playersao);
4459 SendPlayerHP(peer_id);
4460 SendDeathscreen(m_con, peer_id, false, v3f(0,0,0));
4463 void Server::RespawnPlayer(u16 peer_id)
4465 DSTACK(__FUNCTION_NAME);
4467 PlayerSAO *playersao = getPlayerSAO(peer_id);
4470 infostream<<"Server::RespawnPlayer(): Player "
4471 <<playersao->getPlayer()->getName()
4472 <<" respawns"<<std::endl;
4474 playersao->setHP(PLAYER_MAX_HP);
4476 bool repositioned = scriptapi_on_respawnplayer(m_lua, playersao);
4478 v3f pos = findSpawnPos(m_env->getServerMap());
4479 playersao->setPos(pos);
4483 void Server::UpdateCrafting(u16 peer_id)
4485 DSTACK(__FUNCTION_NAME);
4487 Player* player = m_env->getPlayer(peer_id);
4490 // Get a preview for crafting
4492 getCraftingResult(&player->inventory, preview, false, this);
4494 // Put the new preview in
4495 InventoryList *plist = player->inventory.getList("craftpreview");
4497 assert(plist->getSize() >= 1);
4498 plist->changeItem(0, preview);
4501 RemoteClient* Server::getClient(u16 peer_id)
4503 DSTACK(__FUNCTION_NAME);
4504 //JMutexAutoLock lock(m_con_mutex);
4505 std::map<u16, RemoteClient*>::iterator n;
4506 n = m_clients.find(peer_id);
4507 // A client should exist for all peers
4508 assert(n != m_clients.end());
4512 std::wstring Server::getStatusString()
4514 std::wostringstream os(std::ios_base::binary);
4517 os<<L"version="<<narrow_to_wide(VERSION_STRING);
4519 os<<L", uptime="<<m_uptime.get();
4520 // Information about clients
4521 std::map<u16, RemoteClient*>::iterator i;
4524 for(i = m_clients.begin(), first = true;
4525 i != m_clients.end(); ++i)
4527 // Get client and check that it is valid
4528 RemoteClient *client = i->second;
4529 assert(client->peer_id == i->first);
4530 if(client->serialization_version == SER_FMT_VER_INVALID)
4533 Player *player = m_env->getPlayer(client->peer_id);
4534 // Get name of player
4535 std::wstring name = L"unknown";
4537 name = narrow_to_wide(player->getName());
4538 // Add name to information string
4546 if(((ServerMap*)(&m_env->getMap()))->isSavingEnabled() == false)
4547 os<<std::endl<<L"# Server: "<<" WARNING: Map saving is disabled.";
4548 if(g_settings->get("motd") != "")
4549 os<<std::endl<<L"# Server: "<<narrow_to_wide(g_settings->get("motd"));
4553 std::set<std::string> Server::getPlayerEffectivePrivs(const std::string &name)
4555 std::set<std::string> privs;
4556 scriptapi_get_auth(m_lua, name, NULL, &privs);
4560 bool Server::checkPriv(const std::string &name, const std::string &priv)
4562 std::set<std::string> privs = getPlayerEffectivePrivs(name);
4563 return (privs.count(priv) != 0);
4566 void Server::reportPrivsModified(const std::string &name)
4569 for(std::map<u16, RemoteClient*>::iterator
4570 i = m_clients.begin();
4571 i != m_clients.end(); ++i){
4572 RemoteClient *client = i->second;
4573 Player *player = m_env->getPlayer(client->peer_id);
4574 reportPrivsModified(player->getName());
4577 Player *player = m_env->getPlayer(name.c_str());
4580 SendPlayerPrivileges(player->peer_id);
4581 PlayerSAO *sao = player->getPlayerSAO();
4584 sao->updatePrivileges(
4585 getPlayerEffectivePrivs(name),
4590 void Server::reportInventoryFormspecModified(const std::string &name)
4592 Player *player = m_env->getPlayer(name.c_str());
4595 SendPlayerInventoryFormspec(player->peer_id);
4598 // Saves g_settings to configpath given at initialization
4599 void Server::saveConfig()
4601 if(m_path_config != "")
4602 g_settings->updateConfigFile(m_path_config.c_str());
4605 void Server::notifyPlayer(const char *name, const std::wstring msg)
4607 Player *player = m_env->getPlayer(name);
4610 SendChatMessage(player->peer_id, std::wstring(L"Server: -!- ")+msg);
4613 bool Server::showFormspec(const char *playername, const std::string &formspec, const std::string &formname)
4615 Player *player = m_env->getPlayer(playername);
4619 infostream<<"showFormspec: couldn't find player:"<<playername<<std::endl;
4623 SendShowFormspecMessage(player->peer_id, formspec, formname);
4627 u32 Server::hudAdd(Player *player, HudElement *form) {
4631 u32 id = hud_get_free_id(player);
4632 if (id < player->hud.size())
4633 player->hud[id] = form;
4635 player->hud.push_back(form);
4637 SendHUDAdd(player->peer_id, id, form);
4641 bool Server::hudRemove(Player *player, u32 id) {
4642 if (!player || id >= player->hud.size() || !player->hud[id])
4645 delete player->hud[id];
4646 player->hud[id] = NULL;
4648 SendHUDRemove(player->peer_id, id);
4652 bool Server::hudChange(Player *player, u32 id, HudElementStat stat, void *data) {
4656 SendHUDChange(player->peer_id, id, stat, data);
4660 void Server::notifyPlayers(const std::wstring msg)
4662 BroadcastChatMessage(msg);
4665 void Server::spawnParticle(const char *playername, v3f pos,
4666 v3f velocity, v3f acceleration,
4667 float expirationtime, float size, bool
4668 collisiondetection, std::string texture)
4670 Player *player = m_env->getPlayer(playername);
4673 SendSpawnParticle(player->peer_id, pos, velocity, acceleration,
4674 expirationtime, size, collisiondetection, texture);
4677 void Server::spawnParticleAll(v3f pos, v3f velocity, v3f acceleration,
4678 float expirationtime, float size,
4679 bool collisiondetection, std::string texture)
4681 SendSpawnParticleAll(pos, velocity, acceleration,
4682 expirationtime, size, collisiondetection, texture);
4685 u32 Server::addParticleSpawner(const char *playername,
4686 u16 amount, float spawntime,
4687 v3f minpos, v3f maxpos,
4688 v3f minvel, v3f maxvel,
4689 v3f minacc, v3f maxacc,
4690 float minexptime, float maxexptime,
4691 float minsize, float maxsize,
4692 bool collisiondetection, std::string texture)
4694 Player *player = m_env->getPlayer(playername);
4699 for(;;) // look for unused particlespawner id
4702 if (std::find(m_particlespawner_ids.begin(),
4703 m_particlespawner_ids.end(), id)
4704 == m_particlespawner_ids.end())
4706 m_particlespawner_ids.push_back(id);
4711 SendAddParticleSpawner(player->peer_id, amount, spawntime,
4712 minpos, maxpos, minvel, maxvel, minacc, maxacc,
4713 minexptime, maxexptime, minsize, maxsize,
4714 collisiondetection, texture, id);
4719 u32 Server::addParticleSpawnerAll(u16 amount, float spawntime,
4720 v3f minpos, v3f maxpos,
4721 v3f minvel, v3f maxvel,
4722 v3f minacc, v3f maxacc,
4723 float minexptime, float maxexptime,
4724 float minsize, float maxsize,
4725 bool collisiondetection, std::string texture)
4728 for(;;) // look for unused particlespawner id
4731 if (std::find(m_particlespawner_ids.begin(),
4732 m_particlespawner_ids.end(), id)
4733 == m_particlespawner_ids.end())
4735 m_particlespawner_ids.push_back(id);
4740 SendAddParticleSpawnerAll(amount, spawntime,
4741 minpos, maxpos, minvel, maxvel, minacc, maxacc,
4742 minexptime, maxexptime, minsize, maxsize,
4743 collisiondetection, texture, id);
4748 void Server::deleteParticleSpawner(const char *playername, u32 id)
4750 Player *player = m_env->getPlayer(playername);
4754 m_particlespawner_ids.erase(
4755 std::remove(m_particlespawner_ids.begin(),
4756 m_particlespawner_ids.end(), id),
4757 m_particlespawner_ids.end());
4758 SendDeleteParticleSpawner(player->peer_id, id);
4761 void Server::deleteParticleSpawnerAll(u32 id)
4763 m_particlespawner_ids.erase(
4764 std::remove(m_particlespawner_ids.begin(),
4765 m_particlespawner_ids.end(), id),
4766 m_particlespawner_ids.end());
4767 SendDeleteParticleSpawnerAll(id);
4770 void Server::queueBlockEmerge(v3s16 blockpos, bool allow_generate)
4772 m_emerge->enqueueBlockEmerge(PEER_ID_INEXISTENT, blockpos, allow_generate);
4775 Inventory* Server::createDetachedInventory(const std::string &name)
4777 if(m_detached_inventories.count(name) > 0){
4778 infostream<<"Server clearing detached inventory \""<<name<<"\""<<std::endl;
4779 delete m_detached_inventories[name];
4781 infostream<<"Server creating detached inventory \""<<name<<"\""<<std::endl;
4783 Inventory *inv = new Inventory(m_itemdef);
4785 m_detached_inventories[name] = inv;
4786 sendDetachedInventoryToAll(name);
4793 BoolScopeSet(bool *dst, bool val):
4796 m_orig_state = *m_dst;
4801 *m_dst = m_orig_state;
4808 // actions: time-reversed list
4809 // Return value: success/failure
4810 bool Server::rollbackRevertActions(const std::list<RollbackAction> &actions,
4811 std::list<std::string> *log)
4813 infostream<<"Server::rollbackRevertActions(len="<<actions.size()<<")"<<std::endl;
4814 ServerMap *map = (ServerMap*)(&m_env->getMap());
4815 // Disable rollback report sink while reverting
4816 BoolScopeSet rollback_scope_disable(&m_rollback_sink_enabled, false);
4818 // Fail if no actions to handle
4819 if(actions.empty()){
4820 log->push_back("Nothing to do.");
4827 for(std::list<RollbackAction>::const_iterator
4828 i = actions.begin();
4829 i != actions.end(); i++)
4831 const RollbackAction &action = *i;
4833 bool success = action.applyRevert(map, this, this);
4836 std::ostringstream os;
4837 os<<"Revert of step ("<<num_tried<<") "<<action.toString()<<" failed";
4838 infostream<<"Map::rollbackRevertActions(): "<<os.str()<<std::endl;
4840 log->push_back(os.str());
4842 std::ostringstream os;
4843 os<<"Successfully reverted step ("<<num_tried<<") "<<action.toString();
4844 infostream<<"Map::rollbackRevertActions(): "<<os.str()<<std::endl;
4846 log->push_back(os.str());
4850 infostream<<"Map::rollbackRevertActions(): "<<num_failed<<"/"<<num_tried
4851 <<" failed"<<std::endl;
4853 // Call it done if less than half failed
4854 return num_failed <= num_tried/2;
4857 // IGameDef interface
4859 IItemDefManager* Server::getItemDefManager()
4863 INodeDefManager* Server::getNodeDefManager()
4867 ICraftDefManager* Server::getCraftDefManager()
4871 ITextureSource* Server::getTextureSource()
4875 IShaderSource* Server::getShaderSource()
4879 u16 Server::allocateUnknownNodeId(const std::string &name)
4881 return m_nodedef->allocateDummy(name);
4883 ISoundManager* Server::getSoundManager()
4885 return &dummySoundManager;
4887 MtEventManager* Server::getEventManager()
4891 IRollbackReportSink* Server::getRollbackReportSink()
4893 if(!m_enable_rollback_recording)
4895 if(!m_rollback_sink_enabled)
4900 IWritableItemDefManager* Server::getWritableItemDefManager()
4904 IWritableNodeDefManager* Server::getWritableNodeDefManager()
4908 IWritableCraftDefManager* Server::getWritableCraftDefManager()
4913 const ModSpec* Server::getModSpec(const std::string &modname)
4915 for(std::vector<ModSpec>::iterator i = m_mods.begin();
4916 i != m_mods.end(); i++){
4917 const ModSpec &mod = *i;
4918 if(mod.name == modname)
4923 void Server::getModNames(std::list<std::string> &modlist)
4925 for(std::vector<ModSpec>::iterator i = m_mods.begin(); i != m_mods.end(); i++)
4927 modlist.push_back(i->name);
4930 std::string Server::getBuiltinLuaPath()
4932 return porting::path_share + DIR_DELIM + "builtin";
4935 v3f findSpawnPos(ServerMap &map)
4937 //return v3f(50,50,50)*BS;
4942 nodepos = v2s16(0,0);
4947 s16 water_level = map.m_mgparams->water_level;
4949 // Try to find a good place a few times
4950 for(s32 i=0; i<1000; i++)
4953 // We're going to try to throw the player to this position
4954 v2s16 nodepos2d = v2s16(-range + (myrand()%(range*2)),
4955 -range + (myrand()%(range*2)));
4956 //v2s16 sectorpos = getNodeSectorPos(nodepos2d);
4957 // Get ground height at point (fallbacks to heightmap function)
4958 s16 groundheight = map.findGroundLevel(nodepos2d);
4959 // Don't go underwater
4960 if(groundheight <= water_level)
4962 //infostream<<"-> Underwater"<<std::endl;
4965 // Don't go to high places
4966 if(groundheight > water_level + 6)
4968 //infostream<<"-> Underwater"<<std::endl;
4972 nodepos = v3s16(nodepos2d.X, groundheight-2, nodepos2d.Y);
4973 bool is_good = false;
4975 for(s32 i=0; i<10; i++){
4976 v3s16 blockpos = getNodeBlockPos(nodepos);
4977 map.emergeBlock(blockpos, true);
4978 MapNode n = map.getNodeNoEx(nodepos);
4979 if(n.getContent() == CONTENT_AIR){
4990 // Found a good place
4991 //infostream<<"Searched through "<<i<<" places."<<std::endl;
4997 return intToFloat(nodepos, BS);
5000 PlayerSAO* Server::emergePlayer(const char *name, u16 peer_id)
5002 RemotePlayer *player = NULL;
5003 bool newplayer = false;
5006 Try to get an existing player
5008 player = static_cast<RemotePlayer*>(m_env->getPlayer(name));
5010 // If player is already connected, cancel
5011 if(player != NULL && player->peer_id != 0)
5013 infostream<<"emergePlayer(): Player already connected"<<std::endl;
5018 If player with the wanted peer_id already exists, cancel.
5020 if(m_env->getPlayer(peer_id) != NULL)
5022 infostream<<"emergePlayer(): Player with wrong name but same"
5023 " peer_id already exists"<<std::endl;
5028 Create a new player if it doesn't exist yet
5033 player = new RemotePlayer(this);
5034 player->updateName(name);
5036 /* Set player position */
5037 infostream<<"Server: Finding spawn place for player \""
5038 <<name<<"\""<<std::endl;
5039 v3f pos = findSpawnPos(m_env->getServerMap());
5040 player->setPosition(pos);
5042 /* Add player to environment */
5043 m_env->addPlayer(player);
5047 Create a new player active object
5049 PlayerSAO *playersao = new PlayerSAO(m_env, player, peer_id,
5050 getPlayerEffectivePrivs(player->getName()),
5053 /* Add object to environment */
5054 m_env->addActiveObject(playersao);
5058 scriptapi_on_newplayer(m_lua, playersao);
5060 scriptapi_on_joinplayer(m_lua, playersao);
5065 void Server::handlePeerChange(PeerChange &c)
5067 JMutexAutoLock envlock(m_env_mutex);
5068 JMutexAutoLock conlock(m_con_mutex);
5070 if(c.type == PEER_ADDED)
5077 std::map<u16, RemoteClient*>::iterator n;
5078 n = m_clients.find(c.peer_id);
5079 // The client shouldn't already exist
5080 assert(n == m_clients.end());
5083 RemoteClient *client = new RemoteClient();
5084 client->peer_id = c.peer_id;
5085 m_clients[client->peer_id] = client;
5088 else if(c.type == PEER_REMOVED)
5095 std::map<u16, RemoteClient*>::iterator n;
5096 n = m_clients.find(c.peer_id);
5097 // The client should exist
5098 assert(n != m_clients.end());
5101 Mark objects to be not known by the client
5103 RemoteClient *client = n->second;
5105 for(std::set<u16>::iterator
5106 i = client->m_known_objects.begin();
5107 i != client->m_known_objects.end(); ++i)
5111 ServerActiveObject* obj = m_env->getActiveObject(id);
5113 if(obj && obj->m_known_by_count > 0)
5114 obj->m_known_by_count--;
5118 Clear references to playing sounds
5120 for(std::map<s32, ServerPlayingSound>::iterator
5121 i = m_playing_sounds.begin();
5122 i != m_playing_sounds.end();)
5124 ServerPlayingSound &psound = i->second;
5125 psound.clients.erase(c.peer_id);
5126 if(psound.clients.size() == 0)
5127 m_playing_sounds.erase(i++);
5132 Player *player = m_env->getPlayer(c.peer_id);
5134 // Collect information about leaving in chat
5135 std::wstring message;
5139 std::wstring name = narrow_to_wide(player->getName());
5142 message += L" left the game.";
5144 message += L" (timed out)";
5148 /* Run scripts and remove from environment */
5152 PlayerSAO *playersao = player->getPlayerSAO();
5155 scriptapi_on_leaveplayer(m_lua, playersao);
5157 playersao->disconnected();
5167 std::ostringstream os(std::ios_base::binary);
5168 for(std::map<u16, RemoteClient*>::iterator
5169 i = m_clients.begin();
5170 i != m_clients.end(); ++i)
5172 RemoteClient *client = i->second;
5173 assert(client->peer_id == i->first);
5174 if(client->serialization_version == SER_FMT_VER_INVALID)
5177 Player *player = m_env->getPlayer(client->peer_id);
5180 // Get name of player
5181 os<<player->getName()<<" ";
5184 actionstream<<player->getName()<<" "
5185 <<(c.timeout?"times out.":"leaves game.")
5186 <<" List of players: "
5187 <<os.str()<<std::endl;
5192 delete m_clients[c.peer_id];
5193 m_clients.erase(c.peer_id);
5195 // Send player info to all remaining clients
5196 //SendPlayerInfos();
5198 // Send leave chat message to all remaining clients
5199 if(message.length() != 0)
5200 BroadcastChatMessage(message);
5209 void Server::handlePeerChanges()
5211 while(m_peer_change_queue.size() > 0)
5213 PeerChange c = m_peer_change_queue.pop_front();
5215 verbosestream<<"Server: Handling peer change: "
5216 <<"id="<<c.peer_id<<", timeout="<<c.timeout
5219 handlePeerChange(c);
5223 void dedicated_server_loop(Server &server, bool &kill)
5225 DSTACK(__FUNCTION_NAME);
5227 verbosestream<<"dedicated_server_loop()"<<std::endl;
5229 IntervalLimiter m_profiler_interval;
5233 float steplen = g_settings->getFloat("dedicated_server_step");
5234 // This is kind of a hack but can be done like this
5235 // because server.step() is very light
5237 ScopeProfiler sp(g_profiler, "dedicated server sleep");
5238 sleep_ms((int)(steplen*1000.0));
5240 server.step(steplen);
5242 if(server.getShutdownRequested() || kill)
5244 infostream<<"Dedicated server quitting"<<std::endl;
5246 if(g_settings->getBool("server_announce") == true)
5247 ServerList::sendAnnounce("delete");
5255 float profiler_print_interval =
5256 g_settings->getFloat("profiler_print_interval");
5257 if(profiler_print_interval != 0)
5259 if(m_profiler_interval.step(steplen, profiler_print_interval))
5261 infostream<<"Profiler:"<<std::endl;
5262 g_profiler->print(infostream);
5263 g_profiler->clear();