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),
651 m_itemdef(createItemDefManager()),
652 m_nodedef(createNodeDefManager()),
653 m_craftdef(createCraftDefManager()),
654 m_event(new EventManager()),
656 //m_emergethread(this),
657 m_time_of_day_send_timer(0),
659 m_shutdown_requested(false),
660 m_ignore_map_edit_events(false),
661 m_ignore_map_edit_events_peer_id(0)
663 m_liquid_transform_timer = 0.0;
664 m_liquid_transform_every = 1.0;
665 m_print_info_timer = 0.0;
666 m_masterserver_timer = 0.0;
667 m_objectdata_timer = 0.0;
668 m_emergethread_trigger_timer = 0.0;
669 m_savemap_timer = 0.0;
670 m_clients_number = 0;
674 m_step_dtime_mutex.Init();
678 throw ServerError("Supplied empty world path");
680 if(!gamespec.isValid())
681 throw ServerError("Supplied invalid gamespec");
683 infostream<<"Server created for gameid \""<<m_gamespec.id<<"\"";
684 if(m_simple_singleplayer_mode)
685 infostream<<" in simple singleplayer mode"<<std::endl;
687 infostream<<std::endl;
688 infostream<<"- world: "<<m_path_world<<std::endl;
689 infostream<<"- config: "<<m_path_config<<std::endl;
690 infostream<<"- game: "<<m_gamespec.path<<std::endl;
692 // Initialize default settings and override defaults with those provided
694 set_default_settings(g_settings);
695 Settings gamedefaults;
696 getGameMinetestConfig(gamespec.path, gamedefaults);
697 override_default_settings(g_settings, &gamedefaults);
699 // Create biome definition manager
700 m_biomedef = new BiomeDefManager(this);
702 // Create rollback manager
703 std::string rollback_path = m_path_world+DIR_DELIM+"rollback.txt";
704 m_rollback = createRollbackManager(rollback_path, this);
706 // Create world if it doesn't exist
707 if(!initializeWorld(m_path_world, m_gamespec.id))
708 throw ServerError("Failed to initialize world");
710 ModConfiguration modconf(m_path_world);
711 m_mods = modconf.getMods();
712 std::list<ModSpec> unsatisfied_mods = modconf.getUnsatisfiedMods();
713 // complain about mods with unsatisfied dependencies
714 if(!modconf.isConsistent())
716 for(std::list<ModSpec>::iterator it = unsatisfied_mods.begin();
717 it != unsatisfied_mods.end(); ++it)
720 errorstream << "mod \"" << mod.name << "\" has unsatisfied dependencies: ";
721 for(std::set<std::string>::iterator dep_it = mod.unsatisfied_depends.begin();
722 dep_it != mod.unsatisfied_depends.end(); ++dep_it)
723 errorstream << " \"" << *dep_it << "\"";
724 errorstream << std::endl;
728 Settings worldmt_settings;
729 std::string worldmt = m_path_world + DIR_DELIM + "world.mt";
730 worldmt_settings.readConfigFile(worldmt.c_str());
731 std::vector<std::string> names = worldmt_settings.getNames();
732 std::set<std::string> exclude_mod_names;
733 std::set<std::string> load_mod_names;
734 for(std::vector<std::string>::iterator it = names.begin();
735 it != names.end(); ++it)
737 std::string name = *it;
738 if (name.compare(0,9,"load_mod_")==0)
740 if(worldmt_settings.getBool(name))
741 load_mod_names.insert(name.substr(9));
743 exclude_mod_names.insert(name.substr(9));
746 // complain about mods declared to be loaded, but not found
747 for(std::vector<ModSpec>::iterator it = m_mods.begin();
748 it != m_mods.end(); ++it)
749 load_mod_names.erase((*it).name);
750 for(std::list<ModSpec>::iterator it = unsatisfied_mods.begin();
751 it != unsatisfied_mods.end(); ++it)
752 load_mod_names.erase((*it).name);
753 if(!load_mod_names.empty())
755 errorstream << "The following mods could not be found:";
756 for(std::set<std::string>::iterator it = load_mod_names.begin();
757 it != load_mod_names.end(); ++it)
758 errorstream << " \"" << (*it) << "\"";
759 errorstream << std::endl;
762 // Path to builtin.lua
763 std::string builtinpath = getBuiltinLuaPath() + DIR_DELIM + "builtin.lua";
766 JMutexAutoLock envlock(m_env_mutex);
767 JMutexAutoLock conlock(m_con_mutex);
769 // Initialize scripting
771 infostream<<"Server: Initializing Lua"<<std::endl;
772 m_lua = script_init();
775 scriptapi_export(m_lua, this);
776 // Load and run builtin.lua
777 infostream<<"Server: Loading builtin.lua [\""
778 <<builtinpath<<"\"]"<<std::endl;
779 bool success = scriptapi_loadmod(m_lua, builtinpath, "__builtin");
781 errorstream<<"Server: Failed to load and run "
782 <<builtinpath<<std::endl;
783 throw ModError("Failed to load and run "+builtinpath);
786 infostream<<"Server: Loading mods: ";
787 for(std::vector<ModSpec>::iterator i = m_mods.begin();
788 i != m_mods.end(); i++){
789 const ModSpec &mod = *i;
790 infostream<<mod.name<<" ";
792 infostream<<std::endl;
793 // Load and run "mod" scripts
794 for(std::vector<ModSpec>::iterator i = m_mods.begin();
795 i != m_mods.end(); i++){
796 const ModSpec &mod = *i;
797 std::string scriptpath = mod.path + DIR_DELIM + "init.lua";
798 infostream<<" ["<<padStringRight(mod.name, 12)<<"] [\""
799 <<scriptpath<<"\"]"<<std::endl;
800 bool success = scriptapi_loadmod(m_lua, scriptpath, mod.name);
802 errorstream<<"Server: Failed to load and run "
803 <<scriptpath<<std::endl;
804 throw ModError("Failed to load and run "+scriptpath);
808 // Read Textures and calculate sha1 sums
811 // Apply item aliases in the node definition manager
812 m_nodedef->updateAliases(m_itemdef);
814 // Add default biomes after nodedef had its aliases added
815 m_biomedef->addDefaultBiomes();
817 // Create emerge manager
818 m_emerge = new EmergeManager(this, m_biomedef);
820 // Initialize Environment
821 ServerMap *servermap = new ServerMap(path_world, this, m_emerge);
822 m_env = new ServerEnvironment(servermap, m_lua, this, this);
824 m_emerge->initMapgens(servermap->getMapgenParams());
826 // Give environment reference to scripting api
827 scriptapi_add_environment(m_lua, m_env);
829 // Register us to receive map edit events
830 servermap->addEventReceiver(this);
832 // If file exists, load environment metadata
833 if(fs::PathExists(m_path_world+DIR_DELIM+"env_meta.txt"))
835 infostream<<"Server: Loading environment metadata"<<std::endl;
836 m_env->loadMeta(m_path_world);
840 infostream<<"Server: Loading players"<<std::endl;
841 m_env->deSerializePlayers(m_path_world);
844 Add some test ActiveBlockModifiers to environment
846 add_legacy_abms(m_env, m_nodedef);
848 m_liquid_transform_every = g_settings->getFloat("liquid_update");
853 infostream<<"Server destructing"<<std::endl;
856 Send shutdown message
859 JMutexAutoLock conlock(m_con_mutex);
861 std::wstring line = L"*** Server shutting down";
864 Send the message to clients
866 for(std::map<u16, RemoteClient*>::iterator
867 i = m_clients.begin();
868 i != m_clients.end(); ++i)
870 // Get client and check that it is valid
871 RemoteClient *client = i->second;
872 assert(client->peer_id == i->first);
873 if(client->serialization_version == SER_FMT_VER_INVALID)
877 SendChatMessage(client->peer_id, line);
879 catch(con::PeerNotFoundException &e)
885 JMutexAutoLock envlock(m_env_mutex);
886 JMutexAutoLock conlock(m_con_mutex);
889 Execute script shutdown hooks
891 scriptapi_on_shutdown(m_lua);
895 JMutexAutoLock envlock(m_env_mutex);
900 infostream<<"Server: Saving players"<<std::endl;
901 m_env->serializePlayers(m_path_world);
904 Save environment metadata
906 infostream<<"Server: Saving environment metadata"<<std::endl;
907 m_env->saveMeta(m_path_world);
919 JMutexAutoLock clientslock(m_con_mutex);
921 for(std::map<u16, RemoteClient*>::iterator
922 i = m_clients.begin();
923 i != m_clients.end(); ++i)
931 // Delete things in the reverse order of creation
940 // Deinitialize scripting
941 infostream<<"Server: Deinitializing scripting"<<std::endl;
942 script_deinit(m_lua);
944 // Delete detached inventories
946 for(std::map<std::string, Inventory*>::iterator
947 i = m_detached_inventories.begin();
948 i != m_detached_inventories.end(); i++){
954 void Server::start(unsigned short port)
956 DSTACK(__FUNCTION_NAME);
957 infostream<<"Starting server on port "<<port<<"..."<<std::endl;
959 // Stop thread if already running
962 // Initialize connection
963 m_con.SetTimeoutMs(30);
967 m_thread.setRun(true);
970 // ASCII art for the win!
972 <<" .__ __ __ "<<std::endl
973 <<" _____ |__| ____ _____/ |_ ____ _______/ |_ "<<std::endl
974 <<" / \\| |/ \\_/ __ \\ __\\/ __ \\ / ___/\\ __\\"<<std::endl
975 <<"| Y Y \\ | | \\ ___/| | \\ ___/ \\___ \\ | | "<<std::endl
976 <<"|__|_| /__|___| /\\___ >__| \\___ >____ > |__| "<<std::endl
977 <<" \\/ \\/ \\/ \\/ \\/ "<<std::endl;
978 actionstream<<"World at ["<<m_path_world<<"]"<<std::endl;
979 actionstream<<"Server for gameid=\""<<m_gamespec.id
980 <<"\" listening on port "<<port<<"."<<std::endl;
985 DSTACK(__FUNCTION_NAME);
987 infostream<<"Server: Stopping and waiting threads"<<std::endl;
989 // Stop threads (set run=false first so both start stopping)
990 m_thread.setRun(false);
991 //m_emergethread.setRun(false);
993 //m_emergethread.stop();
995 infostream<<"Server: Threads stopped"<<std::endl;
998 void Server::step(float dtime)
1000 DSTACK(__FUNCTION_NAME);
1005 JMutexAutoLock lock(m_step_dtime_mutex);
1006 m_step_dtime += dtime;
1008 // Throw if fatal error occurred in thread
1009 std::string async_err = m_async_fatal_error.get();
1010 if(async_err != ""){
1011 throw ServerError(async_err);
1015 void Server::AsyncRunStep()
1017 DSTACK(__FUNCTION_NAME);
1019 g_profiler->add("Server::AsyncRunStep (num)", 1);
1023 JMutexAutoLock lock1(m_step_dtime_mutex);
1024 dtime = m_step_dtime;
1028 // Send blocks to clients
1035 g_profiler->add("Server::AsyncRunStep with dtime (num)", 1);
1037 //infostream<<"Server steps "<<dtime<<std::endl;
1038 //infostream<<"Server::AsyncRunStep(): dtime="<<dtime<<std::endl;
1041 JMutexAutoLock lock1(m_step_dtime_mutex);
1042 m_step_dtime -= dtime;
1049 m_uptime.set(m_uptime.get() + dtime);
1053 // Process connection's timeouts
1054 JMutexAutoLock lock2(m_con_mutex);
1055 ScopeProfiler sp(g_profiler, "Server: connection timeout processing");
1056 m_con.RunTimeouts(dtime);
1060 // This has to be called so that the client list gets synced
1061 // with the peer list of the connection
1062 handlePeerChanges();
1066 Update time of day and overall game time
1069 JMutexAutoLock envlock(m_env_mutex);
1071 m_env->setTimeOfDaySpeed(g_settings->getFloat("time_speed"));
1074 Send to clients at constant intervals
1077 m_time_of_day_send_timer -= dtime;
1078 if(m_time_of_day_send_timer < 0.0)
1080 m_time_of_day_send_timer = g_settings->getFloat("time_send_interval");
1082 //JMutexAutoLock envlock(m_env_mutex);
1083 JMutexAutoLock conlock(m_con_mutex);
1085 for(std::map<u16, RemoteClient*>::iterator
1086 i = m_clients.begin();
1087 i != m_clients.end(); ++i)
1089 RemoteClient *client = i->second;
1090 SharedBuffer<u8> data = makePacket_TOCLIENT_TIME_OF_DAY(
1091 m_env->getTimeOfDay(), g_settings->getFloat("time_speed"));
1093 m_con.Send(client->peer_id, 0, data, true);
1099 JMutexAutoLock lock(m_env_mutex);
1101 ScopeProfiler sp(g_profiler, "SEnv step");
1102 ScopeProfiler sp2(g_profiler, "SEnv step avg", SPT_AVG);
1106 const float map_timer_and_unload_dtime = 2.92;
1107 if(m_map_timer_and_unload_interval.step(dtime, map_timer_and_unload_dtime))
1109 JMutexAutoLock lock(m_env_mutex);
1110 // Run Map's timers and unload unused data
1111 ScopeProfiler sp(g_profiler, "Server: map timer and unload");
1112 m_env->getMap().timerUpdate(map_timer_and_unload_dtime,
1113 g_settings->getFloat("server_unload_unused_data_timeout"));
1124 JMutexAutoLock lock(m_env_mutex);
1125 JMutexAutoLock lock2(m_con_mutex);
1127 ScopeProfiler sp(g_profiler, "Server: handle players");
1129 for(std::map<u16, RemoteClient*>::iterator
1130 i = m_clients.begin();
1131 i != m_clients.end(); ++i)
1133 RemoteClient *client = i->second;
1134 PlayerSAO *playersao = getPlayerSAO(client->peer_id);
1135 if(playersao == NULL)
1139 Handle player HPs (die if hp=0)
1141 if(playersao->m_hp_not_sent && g_settings->getBool("enable_damage"))
1143 if(playersao->getHP() == 0)
1144 DiePlayer(client->peer_id);
1146 SendPlayerHP(client->peer_id);
1150 Send player inventories if necessary
1152 if(playersao->m_moved){
1153 SendMovePlayer(client->peer_id);
1154 playersao->m_moved = false;
1156 if(playersao->m_inventory_not_sent){
1157 UpdateCrafting(client->peer_id);
1158 SendInventory(client->peer_id);
1163 /* Transform liquids */
1164 m_liquid_transform_timer += dtime;
1165 if(m_liquid_transform_timer >= m_liquid_transform_every)
1167 m_liquid_transform_timer -= m_liquid_transform_every;
1169 JMutexAutoLock lock(m_env_mutex);
1171 ScopeProfiler sp(g_profiler, "Server: liquid transform");
1173 std::map<v3s16, MapBlock*> modified_blocks;
1174 m_env->getMap().transformLiquids(modified_blocks);
1179 core::map<v3s16, MapBlock*> lighting_modified_blocks;
1180 ServerMap &map = ((ServerMap&)m_env->getMap());
1181 map.updateLighting(modified_blocks, lighting_modified_blocks);
1183 // Add blocks modified by lighting to modified_blocks
1184 for(core::map<v3s16, MapBlock*>::Iterator
1185 i = lighting_modified_blocks.getIterator();
1186 i.atEnd() == false; i++)
1188 MapBlock *block = i.getNode()->getValue();
1189 modified_blocks.insert(block->getPos(), block);
1193 Set the modified blocks unsent for all the clients
1196 JMutexAutoLock lock2(m_con_mutex);
1198 for(std::map<u16, RemoteClient*>::iterator
1199 i = m_clients.begin();
1200 i != m_clients.end(); ++i)
1202 RemoteClient *client = i->second;
1204 if(modified_blocks.size() > 0)
1206 // Remove block from sent history
1207 client->SetBlocksNotSent(modified_blocks);
1212 // Periodically print some info
1214 float &counter = m_print_info_timer;
1220 JMutexAutoLock lock2(m_con_mutex);
1221 m_clients_number = 0;
1222 if(m_clients.size() != 0)
1223 infostream<<"Players:"<<std::endl;
1224 for(std::map<u16, RemoteClient*>::iterator
1225 i = m_clients.begin();
1226 i != m_clients.end(); ++i)
1228 //u16 peer_id = i.getNode()->getKey();
1229 RemoteClient *client = i->second;
1230 Player *player = m_env->getPlayer(client->peer_id);
1233 infostream<<"* "<<player->getName()<<"\t";
1234 client->PrintInfo(infostream);
1242 // send masterserver announce
1244 float &counter = m_masterserver_timer;
1245 if((!counter || counter >= 300.0) && g_settings->getBool("server_announce") == true)
1247 ServerList::sendAnnounce(!counter ? "start" : "update", m_clients_number);
1254 //if(g_settings->getBool("enable_experimental"))
1258 Check added and deleted active objects
1261 //infostream<<"Server: Checking added and deleted active objects"<<std::endl;
1262 JMutexAutoLock envlock(m_env_mutex);
1263 JMutexAutoLock conlock(m_con_mutex);
1265 ScopeProfiler sp(g_profiler, "Server: checking added and deleted objs");
1267 // Radius inside which objects are active
1268 s16 radius = g_settings->getS16("active_object_send_range_blocks");
1269 radius *= MAP_BLOCKSIZE;
1271 for(std::map<u16, RemoteClient*>::iterator
1272 i = m_clients.begin();
1273 i != m_clients.end(); ++i)
1275 RemoteClient *client = i->second;
1277 // If definitions and textures have not been sent, don't
1278 // send objects either
1279 if(!client->definitions_sent)
1282 Player *player = m_env->getPlayer(client->peer_id);
1285 // This can happen if the client timeouts somehow
1286 /*infostream<<"WARNING: "<<__FUNCTION_NAME<<": Client "
1288 <<" has no associated player"<<std::endl;*/
1291 v3s16 pos = floatToInt(player->getPosition(), BS);
1293 std::set<u16> removed_objects;
1294 std::set<u16> added_objects;
1295 m_env->getRemovedActiveObjects(pos, radius,
1296 client->m_known_objects, removed_objects);
1297 m_env->getAddedActiveObjects(pos, radius,
1298 client->m_known_objects, added_objects);
1300 // Ignore if nothing happened
1301 if(removed_objects.size() == 0 && added_objects.size() == 0)
1303 //infostream<<"active objects: none changed"<<std::endl;
1307 std::string data_buffer;
1311 // Handle removed objects
1312 writeU16((u8*)buf, removed_objects.size());
1313 data_buffer.append(buf, 2);
1314 for(std::set<u16>::iterator
1315 i = removed_objects.begin();
1316 i != removed_objects.end(); ++i)
1320 ServerActiveObject* obj = m_env->getActiveObject(id);
1322 // Add to data buffer for sending
1323 writeU16((u8*)buf, id);
1324 data_buffer.append(buf, 2);
1326 // Remove from known objects
1327 client->m_known_objects.erase(id);
1329 if(obj && obj->m_known_by_count > 0)
1330 obj->m_known_by_count--;
1333 // Handle added objects
1334 writeU16((u8*)buf, added_objects.size());
1335 data_buffer.append(buf, 2);
1336 for(std::set<u16>::iterator
1337 i = added_objects.begin();
1338 i != added_objects.end(); ++i)
1342 ServerActiveObject* obj = m_env->getActiveObject(id);
1345 u8 type = ACTIVEOBJECT_TYPE_INVALID;
1347 infostream<<"WARNING: "<<__FUNCTION_NAME
1348 <<": NULL object"<<std::endl;
1350 type = obj->getSendType();
1352 // Add to data buffer for sending
1353 writeU16((u8*)buf, id);
1354 data_buffer.append(buf, 2);
1355 writeU8((u8*)buf, type);
1356 data_buffer.append(buf, 1);
1359 data_buffer.append(serializeLongString(
1360 obj->getClientInitializationData(client->net_proto_version)));
1362 data_buffer.append(serializeLongString(""));
1364 // Add to known objects
1365 client->m_known_objects.insert(id);
1368 obj->m_known_by_count++;
1372 SharedBuffer<u8> reply(2 + data_buffer.size());
1373 writeU16(&reply[0], TOCLIENT_ACTIVE_OBJECT_REMOVE_ADD);
1374 memcpy((char*)&reply[2], data_buffer.c_str(),
1375 data_buffer.size());
1377 m_con.Send(client->peer_id, 0, reply, true);
1379 verbosestream<<"Server: Sent object remove/add: "
1380 <<removed_objects.size()<<" removed, "
1381 <<added_objects.size()<<" added, "
1382 <<"packet size is "<<reply.getSize()<<std::endl;
1387 Collect a list of all the objects known by the clients
1388 and report it back to the environment.
1391 core::map<u16, bool> all_known_objects;
1393 for(core::map<u16, RemoteClient*>::Iterator
1394 i = m_clients.getIterator();
1395 i.atEnd() == false; i++)
1397 RemoteClient *client = i.getNode()->getValue();
1398 // Go through all known objects of client
1399 for(core::map<u16, bool>::Iterator
1400 i = client->m_known_objects.getIterator();
1401 i.atEnd()==false; i++)
1403 u16 id = i.getNode()->getKey();
1404 all_known_objects[id] = true;
1408 m_env->setKnownActiveObjects(whatever);
1414 Send object messages
1417 JMutexAutoLock envlock(m_env_mutex);
1418 JMutexAutoLock conlock(m_con_mutex);
1420 ScopeProfiler sp(g_profiler, "Server: sending object messages");
1423 // Value = data sent by object
1424 std::map<u16, std::list<ActiveObjectMessage>* > buffered_messages;
1426 // Get active object messages from environment
1429 ActiveObjectMessage aom = m_env->getActiveObjectMessage();
1433 std::list<ActiveObjectMessage>* message_list = NULL;
1434 std::map<u16, std::list<ActiveObjectMessage>* >::iterator n;
1435 n = buffered_messages.find(aom.id);
1436 if(n == buffered_messages.end())
1438 message_list = new std::list<ActiveObjectMessage>;
1439 buffered_messages[aom.id] = message_list;
1443 message_list = n->second;
1445 message_list->push_back(aom);
1448 // Route data to every client
1449 for(std::map<u16, RemoteClient*>::iterator
1450 i = m_clients.begin();
1451 i != m_clients.end(); ++i)
1453 RemoteClient *client = i->second;
1454 std::string reliable_data;
1455 std::string unreliable_data;
1456 // Go through all objects in message buffer
1457 for(std::map<u16, std::list<ActiveObjectMessage>* >::iterator
1458 j = buffered_messages.begin();
1459 j != buffered_messages.end(); ++j)
1461 // If object is not known by client, skip it
1463 if(client->m_known_objects.find(id) == client->m_known_objects.end())
1465 // Get message list of object
1466 std::list<ActiveObjectMessage>* list = j->second;
1467 // Go through every message
1468 for(std::list<ActiveObjectMessage>::iterator
1469 k = list->begin(); k != list->end(); ++k)
1471 // Compose the full new data with header
1472 ActiveObjectMessage aom = *k;
1473 std::string new_data;
1476 writeU16((u8*)&buf[0], aom.id);
1477 new_data.append(buf, 2);
1479 new_data += serializeString(aom.datastring);
1480 // Add data to buffer
1482 reliable_data += new_data;
1484 unreliable_data += new_data;
1488 reliable_data and unreliable_data are now ready.
1491 if(reliable_data.size() > 0)
1493 SharedBuffer<u8> reply(2 + reliable_data.size());
1494 writeU16(&reply[0], TOCLIENT_ACTIVE_OBJECT_MESSAGES);
1495 memcpy((char*)&reply[2], reliable_data.c_str(),
1496 reliable_data.size());
1498 m_con.Send(client->peer_id, 0, reply, true);
1500 if(unreliable_data.size() > 0)
1502 SharedBuffer<u8> reply(2 + unreliable_data.size());
1503 writeU16(&reply[0], TOCLIENT_ACTIVE_OBJECT_MESSAGES);
1504 memcpy((char*)&reply[2], unreliable_data.c_str(),
1505 unreliable_data.size());
1506 // Send as unreliable
1507 m_con.Send(client->peer_id, 0, reply, false);
1510 /*if(reliable_data.size() > 0 || unreliable_data.size() > 0)
1512 infostream<<"Server: Size of object message data: "
1513 <<"reliable: "<<reliable_data.size()
1514 <<", unreliable: "<<unreliable_data.size()
1519 // Clear buffered_messages
1520 for(std::map<u16, std::list<ActiveObjectMessage>* >::iterator
1521 i = buffered_messages.begin();
1522 i != buffered_messages.end(); ++i)
1528 } // enable_experimental
1531 Send queued-for-sending map edit events.
1534 // We will be accessing the environment and the connection
1535 JMutexAutoLock lock(m_env_mutex);
1536 JMutexAutoLock conlock(m_con_mutex);
1538 // Don't send too many at a time
1541 // Single change sending is disabled if queue size is not small
1542 bool disable_single_change_sending = false;
1543 if(m_unsent_map_edit_queue.size() >= 4)
1544 disable_single_change_sending = true;
1546 int event_count = m_unsent_map_edit_queue.size();
1548 // We'll log the amount of each
1551 while(m_unsent_map_edit_queue.size() != 0)
1553 MapEditEvent* event = m_unsent_map_edit_queue.pop_front();
1555 // Players far away from the change are stored here.
1556 // Instead of sending the changes, MapBlocks are set not sent
1558 std::list<u16> far_players;
1560 if(event->type == MEET_ADDNODE)
1562 //infostream<<"Server: MEET_ADDNODE"<<std::endl;
1563 prof.add("MEET_ADDNODE", 1);
1564 if(disable_single_change_sending)
1565 sendAddNode(event->p, event->n, event->already_known_by_peer,
1568 sendAddNode(event->p, event->n, event->already_known_by_peer,
1571 else if(event->type == MEET_REMOVENODE)
1573 //infostream<<"Server: MEET_REMOVENODE"<<std::endl;
1574 prof.add("MEET_REMOVENODE", 1);
1575 if(disable_single_change_sending)
1576 sendRemoveNode(event->p, event->already_known_by_peer,
1579 sendRemoveNode(event->p, event->already_known_by_peer,
1582 else if(event->type == MEET_BLOCK_NODE_METADATA_CHANGED)
1584 infostream<<"Server: MEET_BLOCK_NODE_METADATA_CHANGED"<<std::endl;
1585 prof.add("MEET_BLOCK_NODE_METADATA_CHANGED", 1);
1586 setBlockNotSent(event->p);
1588 else if(event->type == MEET_OTHER)
1590 infostream<<"Server: MEET_OTHER"<<std::endl;
1591 prof.add("MEET_OTHER", 1);
1592 for(std::set<v3s16>::iterator
1593 i = event->modified_blocks.begin();
1594 i != event->modified_blocks.end(); ++i)
1596 setBlockNotSent(*i);
1601 prof.add("unknown", 1);
1602 infostream<<"WARNING: Server: Unknown MapEditEvent "
1603 <<((u32)event->type)<<std::endl;
1607 Set blocks not sent to far players
1609 if(far_players.size() > 0)
1611 // Convert list format to that wanted by SetBlocksNotSent
1612 std::map<v3s16, MapBlock*> modified_blocks2;
1613 for(std::set<v3s16>::iterator
1614 i = event->modified_blocks.begin();
1615 i != event->modified_blocks.end(); ++i)
1617 modified_blocks2[*i] =
1618 m_env->getMap().getBlockNoCreateNoEx(*i);
1620 // Set blocks not sent
1621 for(std::list<u16>::iterator
1622 i = far_players.begin();
1623 i != far_players.end(); ++i)
1626 RemoteClient *client = getClient(peer_id);
1629 client->SetBlocksNotSent(modified_blocks2);
1635 /*// Don't send too many at a time
1637 if(count >= 1 && m_unsent_map_edit_queue.size() < 100)
1641 if(event_count >= 5){
1642 infostream<<"Server: MapEditEvents:"<<std::endl;
1643 prof.print(infostream);
1644 } else if(event_count != 0){
1645 verbosestream<<"Server: MapEditEvents:"<<std::endl;
1646 prof.print(verbosestream);
1652 Trigger emergethread (it somehow gets to a non-triggered but
1653 bysy state sometimes)
1656 float &counter = m_emergethread_trigger_timer;
1662 for (unsigned int i = 0; i != m_emerge->emergethread.size(); i++)
1663 m_emerge->emergethread[i]->trigger();
1665 // Update m_enable_rollback_recording here too
1666 m_enable_rollback_recording =
1667 g_settings->getBool("enable_rollback_recording");
1671 // Save map, players and auth stuff
1673 float &counter = m_savemap_timer;
1675 if(counter >= g_settings->getFloat("server_map_save_interval"))
1678 JMutexAutoLock lock(m_env_mutex);
1680 ScopeProfiler sp(g_profiler, "Server: saving stuff");
1683 if(m_banmanager.isModified())
1684 m_banmanager.save();
1686 // Save changed parts of map
1687 m_env->getMap().save(MOD_STATE_WRITE_NEEDED);
1690 m_env->serializePlayers(m_path_world);
1692 // Save environment metadata
1693 m_env->saveMeta(m_path_world);
1698 void Server::Receive()
1700 DSTACK(__FUNCTION_NAME);
1701 SharedBuffer<u8> data;
1706 JMutexAutoLock conlock(m_con_mutex);
1707 datasize = m_con.Receive(peer_id, data);
1710 // This has to be called so that the client list gets synced
1711 // with the peer list of the connection
1712 handlePeerChanges();
1714 ProcessData(*data, datasize, peer_id);
1716 catch(con::InvalidIncomingDataException &e)
1718 infostream<<"Server::Receive(): "
1719 "InvalidIncomingDataException: what()="
1720 <<e.what()<<std::endl;
1722 catch(con::PeerNotFoundException &e)
1724 //NOTE: This is not needed anymore
1726 // The peer has been disconnected.
1727 // Find the associated player and remove it.
1729 /*JMutexAutoLock envlock(m_env_mutex);
1731 infostream<<"ServerThread: peer_id="<<peer_id
1732 <<" has apparently closed connection. "
1733 <<"Removing player."<<std::endl;
1735 m_env->removePlayer(peer_id);*/
1739 void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
1741 DSTACK(__FUNCTION_NAME);
1742 // Environment is locked first.
1743 JMutexAutoLock envlock(m_env_mutex);
1744 JMutexAutoLock conlock(m_con_mutex);
1746 ScopeProfiler sp(g_profiler, "Server::ProcessData");
1749 Address address = m_con.GetPeerAddress(peer_id);
1750 std::string addr_s = address.serializeString();
1752 // drop player if is ip is banned
1753 if(m_banmanager.isIpBanned(addr_s)){
1754 infostream<<"Server: A banned client tried to connect from "
1755 <<addr_s<<"; banned name was "
1756 <<m_banmanager.getBanName(addr_s)<<std::endl;
1757 // This actually doesn't seem to transfer to the client
1758 SendAccessDenied(m_con, peer_id,
1759 L"Your ip is banned. Banned name was "
1760 +narrow_to_wide(m_banmanager.getBanName(addr_s)));
1761 m_con.DeletePeer(peer_id);
1765 catch(con::PeerNotFoundException &e)
1767 infostream<<"Server::ProcessData(): Cancelling: peer "
1768 <<peer_id<<" not found"<<std::endl;
1772 std::string addr_s = m_con.GetPeerAddress(peer_id).serializeString();
1774 u8 peer_ser_ver = getClient(peer_id)->serialization_version;
1782 ToServerCommand command = (ToServerCommand)readU16(&data[0]);
1784 if(command == TOSERVER_INIT)
1786 // [0] u16 TOSERVER_INIT
1787 // [2] u8 SER_FMT_VER_HIGHEST
1788 // [3] u8[20] player_name
1789 // [23] u8[28] password <--- can be sent without this, from old versions
1791 if(datasize < 2+1+PLAYERNAME_SIZE)
1794 verbosestream<<"Server: Got TOSERVER_INIT from "
1795 <<peer_id<<std::endl;
1797 // First byte after command is maximum supported
1798 // serialization version
1799 u8 client_max = data[2];
1800 u8 our_max = SER_FMT_VER_HIGHEST;
1801 // Use the highest version supported by both
1802 u8 deployed = std::min(client_max, our_max);
1803 // If it's lower than the lowest supported, give up.
1804 if(deployed < SER_FMT_VER_LOWEST)
1805 deployed = SER_FMT_VER_INVALID;
1807 //peer->serialization_version = deployed;
1808 getClient(peer_id)->pending_serialization_version = deployed;
1810 if(deployed == SER_FMT_VER_INVALID)
1812 actionstream<<"Server: A mismatched client tried to connect from "
1813 <<addr_s<<std::endl;
1814 infostream<<"Server: Cannot negotiate "
1815 "serialization version with peer "
1816 <<peer_id<<std::endl;
1817 SendAccessDenied(m_con, peer_id, std::wstring(
1818 L"Your client's version is not supported.\n"
1819 L"Server version is ")
1820 + narrow_to_wide(VERSION_STRING) + L"."
1826 Read and check network protocol version
1829 u16 min_net_proto_version = 0;
1830 if(datasize >= 2+1+PLAYERNAME_SIZE+PASSWORD_SIZE+2)
1831 min_net_proto_version = readU16(&data[2+1+PLAYERNAME_SIZE+PASSWORD_SIZE]);
1833 // Use same version as minimum and maximum if maximum version field
1834 // doesn't exist (backwards compatibility)
1835 u16 max_net_proto_version = min_net_proto_version;
1836 if(datasize >= 2+1+PLAYERNAME_SIZE+PASSWORD_SIZE+2+2)
1837 max_net_proto_version = readU16(&data[2+1+PLAYERNAME_SIZE+PASSWORD_SIZE+2]);
1839 // Start with client's maximum version
1840 u16 net_proto_version = max_net_proto_version;
1842 // Figure out a working version if it is possible at all
1843 if(max_net_proto_version >= SERVER_PROTOCOL_VERSION_MIN ||
1844 min_net_proto_version <= SERVER_PROTOCOL_VERSION_MAX)
1846 // If maximum is larger than our maximum, go with our maximum
1847 if(max_net_proto_version > SERVER_PROTOCOL_VERSION_MAX)
1848 net_proto_version = SERVER_PROTOCOL_VERSION_MAX;
1849 // Else go with client's maximum
1851 net_proto_version = max_net_proto_version;
1854 verbosestream<<"Server: "<<peer_id<<" Protocol version: min: "
1855 <<min_net_proto_version<<", max: "<<max_net_proto_version
1856 <<", chosen: "<<net_proto_version<<std::endl;
1858 getClient(peer_id)->net_proto_version = net_proto_version;
1860 if(net_proto_version < SERVER_PROTOCOL_VERSION_MIN ||
1861 net_proto_version > SERVER_PROTOCOL_VERSION_MAX)
1863 actionstream<<"Server: A mismatched client tried to connect from "<<addr_s
1865 SendAccessDenied(m_con, peer_id, std::wstring(
1866 L"Your client's version is not supported.\n"
1867 L"Server version is ")
1868 + narrow_to_wide(VERSION_STRING) + L",\n"
1869 + L"server's PROTOCOL_VERSION is "
1870 + narrow_to_wide(itos(SERVER_PROTOCOL_VERSION_MIN))
1872 + narrow_to_wide(itos(SERVER_PROTOCOL_VERSION_MAX))
1873 + L", client's PROTOCOL_VERSION is "
1874 + narrow_to_wide(itos(min_net_proto_version))
1876 + narrow_to_wide(itos(max_net_proto_version))
1881 if(g_settings->getBool("strict_protocol_version_checking"))
1883 if(net_proto_version != LATEST_PROTOCOL_VERSION)
1885 actionstream<<"Server: A mismatched (strict) client tried to "
1886 <<"connect from "<<addr_s<<std::endl;
1887 SendAccessDenied(m_con, peer_id, std::wstring(
1888 L"Your client's version is not supported.\n"
1889 L"Server version is ")
1890 + narrow_to_wide(VERSION_STRING) + L",\n"
1891 + L"server's PROTOCOL_VERSION (strict) is "
1892 + narrow_to_wide(itos(LATEST_PROTOCOL_VERSION))
1893 + L", client's PROTOCOL_VERSION is "
1894 + narrow_to_wide(itos(min_net_proto_version))
1896 + narrow_to_wide(itos(max_net_proto_version))
1907 char playername[PLAYERNAME_SIZE];
1908 for(u32 i=0; i<PLAYERNAME_SIZE-1; i++)
1910 playername[i] = data[3+i];
1912 playername[PLAYERNAME_SIZE-1] = 0;
1914 if(playername[0]=='\0')
1916 actionstream<<"Server: Player with an empty name "
1917 <<"tried to connect from "<<addr_s<<std::endl;
1918 SendAccessDenied(m_con, peer_id,
1923 if(string_allowed(playername, PLAYERNAME_ALLOWED_CHARS)==false)
1925 actionstream<<"Server: Player with an invalid name "
1926 <<"tried to connect from "<<addr_s<<std::endl;
1927 SendAccessDenied(m_con, peer_id,
1928 L"Name contains unallowed characters");
1932 infostream<<"Server: New connection: \""<<playername<<"\" from "
1933 <<m_con.GetPeerAddress(peer_id).serializeString()<<std::endl;
1936 char given_password[PASSWORD_SIZE];
1937 if(datasize < 2+1+PLAYERNAME_SIZE+PASSWORD_SIZE)
1939 // old version - assume blank password
1940 given_password[0] = 0;
1944 for(u32 i=0; i<PASSWORD_SIZE-1; i++)
1946 given_password[i] = data[23+i];
1948 given_password[PASSWORD_SIZE-1] = 0;
1951 if(!base64_is_valid(given_password)){
1952 infostream<<"Server: "<<playername
1953 <<" supplied invalid password hash"<<std::endl;
1954 SendAccessDenied(m_con, peer_id, L"Invalid password hash");
1958 std::string checkpwd; // Password hash to check against
1959 bool has_auth = scriptapi_get_auth(m_lua, playername, &checkpwd, NULL);
1961 // If no authentication info exists for user, create it
1963 if(!isSingleplayer() &&
1964 g_settings->getBool("disallow_empty_password") &&
1965 std::string(given_password) == ""){
1966 SendAccessDenied(m_con, peer_id, L"Empty passwords are "
1967 L"disallowed. Set a password and try again.");
1970 std::wstring raw_default_password =
1971 narrow_to_wide(g_settings->get("default_password"));
1972 std::string initial_password =
1973 translatePassword(playername, raw_default_password);
1975 // If default_password is empty, allow any initial password
1976 if (raw_default_password.length() == 0)
1977 initial_password = given_password;
1979 scriptapi_create_auth(m_lua, playername, initial_password);
1982 has_auth = scriptapi_get_auth(m_lua, playername, &checkpwd, NULL);
1985 SendAccessDenied(m_con, peer_id, L"Not allowed to login");
1989 if(given_password != checkpwd){
1990 infostream<<"Server: peer_id="<<peer_id
1991 <<": supplied invalid password for "
1992 <<playername<<std::endl;
1993 SendAccessDenied(m_con, peer_id, L"Invalid password");
1997 // Do not allow multiple players in simple singleplayer mode.
1998 // This isn't a perfect way to do it, but will suffice for now.
1999 if(m_simple_singleplayer_mode && m_clients.size() > 1){
2000 infostream<<"Server: Not allowing another client to connect in"
2001 <<" simple singleplayer mode"<<std::endl;
2002 SendAccessDenied(m_con, peer_id,
2003 L"Running in simple singleplayer mode.");
2007 // Enforce user limit.
2008 // Don't enforce for users that have some admin right
2009 if(m_clients.size() >= g_settings->getU16("max_users") &&
2010 !checkPriv(playername, "server") &&
2011 !checkPriv(playername, "ban") &&
2012 !checkPriv(playername, "privs") &&
2013 !checkPriv(playername, "password") &&
2014 playername != g_settings->get("name"))
2016 actionstream<<"Server: "<<playername<<" tried to join, but there"
2017 <<" are already max_users="
2018 <<g_settings->getU16("max_users")<<" players."<<std::endl;
2019 SendAccessDenied(m_con, peer_id, L"Too many users.");
2024 PlayerSAO *playersao = emergePlayer(playername, peer_id);
2026 // If failed, cancel
2027 if(playersao == NULL)
2029 errorstream<<"Server: peer_id="<<peer_id
2030 <<": failed to emerge player"<<std::endl;
2035 Answer with a TOCLIENT_INIT
2038 SharedBuffer<u8> reply(2+1+6+8+4);
2039 writeU16(&reply[0], TOCLIENT_INIT);
2040 writeU8(&reply[2], deployed);
2041 writeV3S16(&reply[2+1], floatToInt(playersao->getPlayer()->getPosition()+v3f(0,BS/2,0), BS));
2042 writeU64(&reply[2+1+6], m_env->getServerMap().getSeed());
2043 writeF1000(&reply[2+1+6+8], g_settings->getFloat("dedicated_server_step"));
2046 m_con.Send(peer_id, 0, reply, true);
2050 Send complete position information
2052 SendMovePlayer(peer_id);
2057 if(command == TOSERVER_INIT2)
2059 verbosestream<<"Server: Got TOSERVER_INIT2 from "
2060 <<peer_id<<std::endl;
2062 Player *player = m_env->getPlayer(peer_id);
2064 verbosestream<<"Server: TOSERVER_INIT2: "
2065 <<"Player not found; ignoring."<<std::endl;
2069 RemoteClient *client = getClient(peer_id);
2070 client->serialization_version =
2071 getClient(peer_id)->pending_serialization_version;
2074 Send some initialization data
2077 infostream<<"Server: Sending content to "
2078 <<getPlayerName(peer_id)<<std::endl;
2080 // Send player movement settings
2081 SendMovement(m_con, peer_id);
2083 // Send item definitions
2084 SendItemDef(m_con, peer_id, m_itemdef);
2086 // Send node definitions
2087 SendNodeDef(m_con, peer_id, m_nodedef, client->net_proto_version);
2089 // Send media announcement
2090 sendMediaAnnouncement(peer_id);
2093 SendPlayerPrivileges(peer_id);
2095 // Send inventory formspec
2096 SendPlayerInventoryFormspec(peer_id);
2099 UpdateCrafting(peer_id);
2100 SendInventory(peer_id);
2103 if(g_settings->getBool("enable_damage"))
2104 SendPlayerHP(peer_id);
2106 // Send detached inventories
2107 sendDetachedInventories(peer_id);
2109 // Show death screen if necessary
2111 SendDeathscreen(m_con, peer_id, false, v3f(0,0,0));
2115 SharedBuffer<u8> data = makePacket_TOCLIENT_TIME_OF_DAY(
2116 m_env->getTimeOfDay(), g_settings->getFloat("time_speed"));
2117 m_con.Send(peer_id, 0, data, true);
2120 // Note things in chat if not in simple singleplayer mode
2121 if(!m_simple_singleplayer_mode)
2123 // Send information about server to player in chat
2124 SendChatMessage(peer_id, getStatusString());
2126 // Send information about joining in chat
2128 std::wstring name = L"unknown";
2129 Player *player = m_env->getPlayer(peer_id);
2131 name = narrow_to_wide(player->getName());
2133 std::wstring message;
2136 message += L" joined the game.";
2137 BroadcastChatMessage(message);
2141 // Warnings about protocol version can be issued here
2142 if(getClient(peer_id)->net_proto_version < LATEST_PROTOCOL_VERSION)
2144 SendChatMessage(peer_id, L"# Server: WARNING: YOUR CLIENT'S "
2145 L"VERSION MAY NOT BE FULLY COMPATIBLE WITH THIS SERVER!");
2152 std::ostringstream os(std::ios_base::binary);
2153 for(std::map<u16, RemoteClient*>::iterator
2154 i = m_clients.begin();
2155 i != m_clients.end(); ++i)
2157 RemoteClient *client = i->second;
2158 assert(client->peer_id == i->first);
2159 if(client->serialization_version == SER_FMT_VER_INVALID)
2162 Player *player = m_env->getPlayer(client->peer_id);
2165 // Get name of player
2166 os<<player->getName()<<" ";
2169 actionstream<<player->getName()<<" joins game. List of players: "
2170 <<os.str()<<std::endl;
2176 if(peer_ser_ver == SER_FMT_VER_INVALID)
2178 infostream<<"Server::ProcessData(): Cancelling: Peer"
2179 " serialization format invalid or not initialized."
2180 " Skipping incoming command="<<command<<std::endl;
2184 Player *player = m_env->getPlayer(peer_id);
2186 infostream<<"Server::ProcessData(): Cancelling: "
2187 "No player for peer_id="<<peer_id
2192 PlayerSAO *playersao = player->getPlayerSAO();
2193 if(playersao == NULL){
2194 infostream<<"Server::ProcessData(): Cancelling: "
2195 "No player object for peer_id="<<peer_id
2200 if(command == TOSERVER_PLAYERPOS)
2202 if(datasize < 2+12+12+4+4)
2206 v3s32 ps = readV3S32(&data[start+2]);
2207 v3s32 ss = readV3S32(&data[start+2+12]);
2208 f32 pitch = (f32)readS32(&data[2+12+12]) / 100.0;
2209 f32 yaw = (f32)readS32(&data[2+12+12+4]) / 100.0;
2211 if(datasize >= 2+12+12+4+4+4)
2212 keyPressed = (u32)readU32(&data[2+12+12+4+4]);
2213 v3f position((f32)ps.X/100., (f32)ps.Y/100., (f32)ps.Z/100.);
2214 v3f speed((f32)ss.X/100., (f32)ss.Y/100., (f32)ss.Z/100.);
2215 pitch = wrapDegrees(pitch);
2216 yaw = wrapDegrees(yaw);
2218 player->setPosition(position);
2219 player->setSpeed(speed);
2220 player->setPitch(pitch);
2221 player->setYaw(yaw);
2222 player->keyPressed=keyPressed;
2223 player->control.up = (bool)(keyPressed&1);
2224 player->control.down = (bool)(keyPressed&2);
2225 player->control.left = (bool)(keyPressed&4);
2226 player->control.right = (bool)(keyPressed&8);
2227 player->control.jump = (bool)(keyPressed&16);
2228 player->control.aux1 = (bool)(keyPressed&32);
2229 player->control.sneak = (bool)(keyPressed&64);
2230 player->control.LMB = (bool)(keyPressed&128);
2231 player->control.RMB = (bool)(keyPressed&256);
2233 /*infostream<<"Server::ProcessData(): Moved player "<<peer_id<<" to "
2234 <<"("<<position.X<<","<<position.Y<<","<<position.Z<<")"
2235 <<" pitch="<<pitch<<" yaw="<<yaw<<std::endl;*/
2237 else if(command == TOSERVER_GOTBLOCKS)
2250 u16 count = data[2];
2251 for(u16 i=0; i<count; i++)
2253 if((s16)datasize < 2+1+(i+1)*6)
2254 throw con::InvalidIncomingDataException
2255 ("GOTBLOCKS length is too short");
2256 v3s16 p = readV3S16(&data[2+1+i*6]);
2257 /*infostream<<"Server: GOTBLOCKS ("
2258 <<p.X<<","<<p.Y<<","<<p.Z<<")"<<std::endl;*/
2259 RemoteClient *client = getClient(peer_id);
2260 client->GotBlock(p);
2263 else if(command == TOSERVER_DELETEDBLOCKS)
2276 u16 count = data[2];
2277 for(u16 i=0; i<count; i++)
2279 if((s16)datasize < 2+1+(i+1)*6)
2280 throw con::InvalidIncomingDataException
2281 ("DELETEDBLOCKS length is too short");
2282 v3s16 p = readV3S16(&data[2+1+i*6]);
2283 /*infostream<<"Server: DELETEDBLOCKS ("
2284 <<p.X<<","<<p.Y<<","<<p.Z<<")"<<std::endl;*/
2285 RemoteClient *client = getClient(peer_id);
2286 client->SetBlockNotSent(p);
2289 else if(command == TOSERVER_CLICK_OBJECT)
2291 infostream<<"Server: CLICK_OBJECT not supported anymore"<<std::endl;
2294 else if(command == TOSERVER_CLICK_ACTIVEOBJECT)
2296 infostream<<"Server: CLICK_ACTIVEOBJECT not supported anymore"<<std::endl;
2299 else if(command == TOSERVER_GROUND_ACTION)
2301 infostream<<"Server: GROUND_ACTION not supported anymore"<<std::endl;
2305 else if(command == TOSERVER_RELEASE)
2307 infostream<<"Server: RELEASE not supported anymore"<<std::endl;
2310 else if(command == TOSERVER_SIGNTEXT)
2312 infostream<<"Server: SIGNTEXT not supported anymore"
2316 else if(command == TOSERVER_SIGNNODETEXT)
2318 infostream<<"Server: SIGNNODETEXT not supported anymore"
2322 else if(command == TOSERVER_INVENTORY_ACTION)
2324 // Strip command and create a stream
2325 std::string datastring((char*)&data[2], datasize-2);
2326 verbosestream<<"TOSERVER_INVENTORY_ACTION: data="<<datastring<<std::endl;
2327 std::istringstream is(datastring, std::ios_base::binary);
2329 InventoryAction *a = InventoryAction::deSerialize(is);
2332 infostream<<"TOSERVER_INVENTORY_ACTION: "
2333 <<"InventoryAction::deSerialize() returned NULL"
2338 // If something goes wrong, this player is to blame
2339 RollbackScopeActor rollback_scope(m_rollback,
2340 std::string("player:")+player->getName());
2343 Note: Always set inventory not sent, to repair cases
2344 where the client made a bad prediction.
2348 Handle restrictions and special cases of the move action
2350 if(a->getType() == IACTION_MOVE)
2352 IMoveAction *ma = (IMoveAction*)a;
2354 ma->from_inv.applyCurrentPlayer(player->getName());
2355 ma->to_inv.applyCurrentPlayer(player->getName());
2357 setInventoryModified(ma->from_inv);
2358 setInventoryModified(ma->to_inv);
2360 bool from_inv_is_current_player =
2361 (ma->from_inv.type == InventoryLocation::PLAYER) &&
2362 (ma->from_inv.name == player->getName());
2364 bool to_inv_is_current_player =
2365 (ma->to_inv.type == InventoryLocation::PLAYER) &&
2366 (ma->to_inv.name == player->getName());
2369 Disable moving items out of craftpreview
2371 if(ma->from_list == "craftpreview")
2373 infostream<<"Ignoring IMoveAction from "
2374 <<(ma->from_inv.dump())<<":"<<ma->from_list
2375 <<" to "<<(ma->to_inv.dump())<<":"<<ma->to_list
2376 <<" because src is "<<ma->from_list<<std::endl;
2382 Disable moving items into craftresult and craftpreview
2384 if(ma->to_list == "craftpreview" || ma->to_list == "craftresult")
2386 infostream<<"Ignoring IMoveAction from "
2387 <<(ma->from_inv.dump())<<":"<<ma->from_list
2388 <<" to "<<(ma->to_inv.dump())<<":"<<ma->to_list
2389 <<" because dst is "<<ma->to_list<<std::endl;
2394 // Disallow moving items in elsewhere than player's inventory
2395 // if not allowed to interact
2396 if(!checkPriv(player->getName(), "interact") &&
2397 (!from_inv_is_current_player ||
2398 !to_inv_is_current_player))
2400 infostream<<"Cannot move outside of player's inventory: "
2401 <<"No interact privilege"<<std::endl;
2407 Handle restrictions and special cases of the drop action
2409 else if(a->getType() == IACTION_DROP)
2411 IDropAction *da = (IDropAction*)a;
2413 da->from_inv.applyCurrentPlayer(player->getName());
2415 setInventoryModified(da->from_inv);
2417 // Disallow dropping items if not allowed to interact
2418 if(!checkPriv(player->getName(), "interact"))
2425 Handle restrictions and special cases of the craft action
2427 else if(a->getType() == IACTION_CRAFT)
2429 ICraftAction *ca = (ICraftAction*)a;
2431 ca->craft_inv.applyCurrentPlayer(player->getName());
2433 setInventoryModified(ca->craft_inv);
2435 //bool craft_inv_is_current_player =
2436 // (ca->craft_inv.type == InventoryLocation::PLAYER) &&
2437 // (ca->craft_inv.name == player->getName());
2439 // Disallow crafting if not allowed to interact
2440 if(!checkPriv(player->getName(), "interact"))
2442 infostream<<"Cannot craft: "
2443 <<"No interact privilege"<<std::endl;
2450 a->apply(this, playersao, this);
2454 else if(command == TOSERVER_CHAT_MESSAGE)
2462 std::string datastring((char*)&data[2], datasize-2);
2463 std::istringstream is(datastring, std::ios_base::binary);
2466 is.read((char*)buf, 2);
2467 u16 len = readU16(buf);
2469 std::wstring message;
2470 for(u16 i=0; i<len; i++)
2472 is.read((char*)buf, 2);
2473 message += (wchar_t)readU16(buf);
2476 // If something goes wrong, this player is to blame
2477 RollbackScopeActor rollback_scope(m_rollback,
2478 std::string("player:")+player->getName());
2480 // Get player name of this client
2481 std::wstring name = narrow_to_wide(player->getName());
2484 bool ate = scriptapi_on_chat_message(m_lua, player->getName(),
2485 wide_to_narrow(message));
2486 // If script ate the message, don't proceed
2490 // Line to send to players
2492 // Whether to send to the player that sent the line
2493 bool send_to_sender = false;
2494 // Whether to send to other players
2495 bool send_to_others = false;
2497 // Commands are implemented in Lua, so only catch invalid
2498 // commands that were not "eaten" and send an error back
2499 if(message[0] == L'/')
2501 message = message.substr(1);
2502 send_to_sender = true;
2503 if(message.length() == 0)
2504 line += L"-!- Empty command";
2506 line += L"-!- Invalid command: " + str_split(message, L' ')[0];
2510 if(checkPriv(player->getName(), "shout")){
2515 send_to_others = true;
2517 line += L"-!- You don't have permission to shout.";
2518 send_to_sender = true;
2525 actionstream<<"CHAT: "<<wide_to_narrow(line)<<std::endl;
2528 Send the message to clients
2530 for(std::map<u16, RemoteClient*>::iterator
2531 i = m_clients.begin();
2532 i != m_clients.end(); ++i)
2534 // Get client and check that it is valid
2535 RemoteClient *client = i->second;
2536 assert(client->peer_id == i->first);
2537 if(client->serialization_version == SER_FMT_VER_INVALID)
2541 bool sender_selected = (peer_id == client->peer_id);
2542 if(sender_selected == true && send_to_sender == false)
2544 if(sender_selected == false && send_to_others == false)
2547 SendChatMessage(client->peer_id, line);
2551 else if(command == TOSERVER_DAMAGE)
2553 std::string datastring((char*)&data[2], datasize-2);
2554 std::istringstream is(datastring, std::ios_base::binary);
2555 u8 damage = readU8(is);
2557 if(g_settings->getBool("enable_damage"))
2559 actionstream<<player->getName()<<" damaged by "
2560 <<(int)damage<<" hp at "<<PP(player->getPosition()/BS)
2563 playersao->setHP(playersao->getHP() - damage);
2565 if(playersao->getHP() == 0 && playersao->m_hp_not_sent)
2568 if(playersao->m_hp_not_sent)
2569 SendPlayerHP(peer_id);
2572 else if(command == TOSERVER_PASSWORD)
2575 [0] u16 TOSERVER_PASSWORD
2576 [2] u8[28] old password
2577 [30] u8[28] new password
2580 if(datasize != 2+PASSWORD_SIZE*2)
2582 /*char password[PASSWORD_SIZE];
2583 for(u32 i=0; i<PASSWORD_SIZE-1; i++)
2584 password[i] = data[2+i];
2585 password[PASSWORD_SIZE-1] = 0;*/
2587 for(u32 i=0; i<PASSWORD_SIZE-1; i++)
2595 for(u32 i=0; i<PASSWORD_SIZE-1; i++)
2597 char c = data[2+PASSWORD_SIZE+i];
2603 if(!base64_is_valid(newpwd)){
2604 infostream<<"Server: "<<player->getName()<<" supplied invalid password hash"<<std::endl;
2605 // Wrong old password supplied!!
2606 SendChatMessage(peer_id, L"Invalid new password hash supplied. Password NOT changed.");
2610 infostream<<"Server: Client requests a password change from "
2611 <<"'"<<oldpwd<<"' to '"<<newpwd<<"'"<<std::endl;
2613 std::string playername = player->getName();
2615 std::string checkpwd;
2616 scriptapi_get_auth(m_lua, playername, &checkpwd, NULL);
2618 if(oldpwd != checkpwd)
2620 infostream<<"Server: invalid old password"<<std::endl;
2621 // Wrong old password supplied!!
2622 SendChatMessage(peer_id, L"Invalid old password supplied. Password NOT changed.");
2626 bool success = scriptapi_set_password(m_lua, playername, newpwd);
2628 actionstream<<player->getName()<<" changes password"<<std::endl;
2629 SendChatMessage(peer_id, L"Password change successful.");
2631 actionstream<<player->getName()<<" tries to change password but "
2632 <<"it fails"<<std::endl;
2633 SendChatMessage(peer_id, L"Password change failed or inavailable.");
2636 else if(command == TOSERVER_PLAYERITEM)
2641 u16 item = readU16(&data[2]);
2642 playersao->setWieldIndex(item);
2644 else if(command == TOSERVER_RESPAWN)
2646 if(player->hp != 0 || !g_settings->getBool("enable_damage"))
2649 RespawnPlayer(peer_id);
2651 actionstream<<player->getName()<<" respawns at "
2652 <<PP(player->getPosition()/BS)<<std::endl;
2654 // ActiveObject is added to environment in AsyncRunStep after
2655 // the previous addition has been succesfully removed
2657 else if(command == TOSERVER_REQUEST_MEDIA) {
2658 std::string datastring((char*)&data[2], datasize-2);
2659 std::istringstream is(datastring, std::ios_base::binary);
2661 std::list<MediaRequest> tosend;
2662 u16 numfiles = readU16(is);
2664 infostream<<"Sending "<<numfiles<<" files to "
2665 <<getPlayerName(peer_id)<<std::endl;
2666 verbosestream<<"TOSERVER_REQUEST_MEDIA: "<<std::endl;
2668 for(int i = 0; i < numfiles; i++) {
2669 std::string name = deSerializeString(is);
2670 tosend.push_back(MediaRequest(name));
2671 verbosestream<<"TOSERVER_REQUEST_MEDIA: requested file "
2675 sendRequestedMedia(peer_id, tosend);
2677 // Now the client should know about everything
2678 // (definitions and files)
2679 getClient(peer_id)->definitions_sent = true;
2681 else if(command == TOSERVER_RECEIVED_MEDIA) {
2682 getClient(peer_id)->definitions_sent = true;
2684 else if(command == TOSERVER_INTERACT)
2686 std::string datastring((char*)&data[2], datasize-2);
2687 std::istringstream is(datastring, std::ios_base::binary);
2693 [5] u32 length of the next item
2694 [9] serialized PointedThing
2696 0: start digging (from undersurface) or use
2697 1: stop digging (all parameters ignored)
2698 2: digging completed
2699 3: place block or item (to abovesurface)
2702 u8 action = readU8(is);
2703 u16 item_i = readU16(is);
2704 std::istringstream tmp_is(deSerializeLongString(is), std::ios::binary);
2705 PointedThing pointed;
2706 pointed.deSerialize(tmp_is);
2708 verbosestream<<"TOSERVER_INTERACT: action="<<(int)action<<", item="
2709 <<item_i<<", pointed="<<pointed.dump()<<std::endl;
2713 verbosestream<<"TOSERVER_INTERACT: "<<player->getName()
2714 <<" tried to interact, but is dead!"<<std::endl;
2718 v3f player_pos = playersao->getLastGoodPosition();
2720 // Update wielded item
2721 playersao->setWieldIndex(item_i);
2723 // Get pointed to node (undefined if not POINTEDTYPE_NODE)
2724 v3s16 p_under = pointed.node_undersurface;
2725 v3s16 p_above = pointed.node_abovesurface;
2727 // Get pointed to object (NULL if not POINTEDTYPE_OBJECT)
2728 ServerActiveObject *pointed_object = NULL;
2729 if(pointed.type == POINTEDTHING_OBJECT)
2731 pointed_object = m_env->getActiveObject(pointed.object_id);
2732 if(pointed_object == NULL)
2734 verbosestream<<"TOSERVER_INTERACT: "
2735 "pointed object is NULL"<<std::endl;
2741 v3f pointed_pos_under = player_pos;
2742 v3f pointed_pos_above = player_pos;
2743 if(pointed.type == POINTEDTHING_NODE)
2745 pointed_pos_under = intToFloat(p_under, BS);
2746 pointed_pos_above = intToFloat(p_above, BS);
2748 else if(pointed.type == POINTEDTHING_OBJECT)
2750 pointed_pos_under = pointed_object->getBasePosition();
2751 pointed_pos_above = pointed_pos_under;
2755 Check that target is reasonably close
2756 (only when digging or placing things)
2758 if(action == 0 || action == 2 || action == 3)
2760 float d = player_pos.getDistanceFrom(pointed_pos_under);
2761 float max_d = BS * 14; // Just some large enough value
2763 actionstream<<"Player "<<player->getName()
2764 <<" tried to access "<<pointed.dump()
2766 <<"d="<<d<<", max_d="<<max_d
2767 <<". ignoring."<<std::endl;
2768 // Re-send block to revert change on client-side
2769 RemoteClient *client = getClient(peer_id);
2770 v3s16 blockpos = getNodeBlockPos(floatToInt(pointed_pos_under, BS));
2771 client->SetBlockNotSent(blockpos);
2778 Make sure the player is allowed to do it
2780 if(!checkPriv(player->getName(), "interact"))
2782 actionstream<<player->getName()<<" attempted to interact with "
2783 <<pointed.dump()<<" without 'interact' privilege"
2785 // Re-send block to revert change on client-side
2786 RemoteClient *client = getClient(peer_id);
2787 // Digging completed -> under
2789 v3s16 blockpos = getNodeBlockPos(floatToInt(pointed_pos_under, BS));
2790 client->SetBlockNotSent(blockpos);
2792 // Placement -> above
2794 v3s16 blockpos = getNodeBlockPos(floatToInt(pointed_pos_above, BS));
2795 client->SetBlockNotSent(blockpos);
2801 If something goes wrong, this player is to blame
2803 RollbackScopeActor rollback_scope(m_rollback,
2804 std::string("player:")+player->getName());
2807 0: start digging or punch object
2811 if(pointed.type == POINTEDTHING_NODE)
2814 NOTE: This can be used in the future to check if
2815 somebody is cheating, by checking the timing.
2817 MapNode n(CONTENT_IGNORE);
2820 n = m_env->getMap().getNode(p_under);
2822 catch(InvalidPositionException &e)
2824 infostream<<"Server: Not punching: Node not found."
2825 <<" Adding block to emerge queue."
2827 m_emerge->enqueueBlockEmerge(peer_id, getNodeBlockPos(p_above), false);
2829 if(n.getContent() != CONTENT_IGNORE)
2830 scriptapi_node_on_punch(m_lua, p_under, n, playersao);
2832 playersao->noCheatDigStart(p_under);
2834 else if(pointed.type == POINTEDTHING_OBJECT)
2836 // Skip if object has been removed
2837 if(pointed_object->m_removed)
2840 actionstream<<player->getName()<<" punches object "
2841 <<pointed.object_id<<": "
2842 <<pointed_object->getDescription()<<std::endl;
2844 ItemStack punchitem = playersao->getWieldedItem();
2845 ToolCapabilities toolcap =
2846 punchitem.getToolCapabilities(m_itemdef);
2847 v3f dir = (pointed_object->getBasePosition() -
2848 (player->getPosition() + player->getEyeOffset())
2850 float time_from_last_punch =
2851 playersao->resetTimeFromLastPunch();
2852 pointed_object->punch(dir, &toolcap, playersao,
2853 time_from_last_punch);
2861 else if(action == 1)
2866 2: Digging completed
2868 else if(action == 2)
2870 // Only digging of nodes
2871 if(pointed.type == POINTEDTHING_NODE)
2873 MapNode n(CONTENT_IGNORE);
2876 n = m_env->getMap().getNode(p_under);
2878 catch(InvalidPositionException &e)
2880 infostream<<"Server: Not finishing digging: Node not found."
2881 <<" Adding block to emerge queue."
2883 m_emerge->enqueueBlockEmerge(peer_id, getNodeBlockPos(p_above), false);
2886 /* Cheat prevention */
2887 bool is_valid_dig = true;
2888 if(!isSingleplayer() && !g_settings->getBool("disable_anticheat"))
2890 v3s16 nocheat_p = playersao->getNoCheatDigPos();
2891 float nocheat_t = playersao->getNoCheatDigTime();
2892 playersao->noCheatDigEnd();
2893 // If player didn't start digging this, ignore dig
2894 if(nocheat_p != p_under){
2895 infostream<<"Server: NoCheat: "<<player->getName()
2896 <<" started digging "
2897 <<PP(nocheat_p)<<" and completed digging "
2898 <<PP(p_under)<<"; not digging."<<std::endl;
2899 is_valid_dig = false;
2901 // Get player's wielded item
2902 ItemStack playeritem;
2903 InventoryList *mlist = playersao->getInventory()->getList("main");
2905 playeritem = mlist->getItem(playersao->getWieldIndex());
2906 ToolCapabilities playeritem_toolcap =
2907 playeritem.getToolCapabilities(m_itemdef);
2908 // Get diggability and expected digging time
2909 DigParams params = getDigParams(m_nodedef->get(n).groups,
2910 &playeritem_toolcap);
2911 // If can't dig, try hand
2912 if(!params.diggable){
2913 const ItemDefinition &hand = m_itemdef->get("");
2914 const ToolCapabilities *tp = hand.tool_capabilities;
2916 params = getDigParams(m_nodedef->get(n).groups, tp);
2918 // If can't dig, ignore dig
2919 if(!params.diggable){
2920 infostream<<"Server: NoCheat: "<<player->getName()
2921 <<" completed digging "<<PP(p_under)
2922 <<", which is not diggable with tool. not digging."
2924 is_valid_dig = false;
2926 // If time is considerably too short, ignore dig
2927 // Check time only for medium and slow timed digs
2928 if(params.diggable && params.time > 0.3 && nocheat_t < 0.5 * params.time){
2929 infostream<<"Server: NoCheat: "<<player->getName()
2930 <<" completed digging "
2931 <<PP(p_under)<<" in "<<nocheat_t<<"s; expected "
2932 <<params.time<<"s; not digging."<<std::endl;
2933 is_valid_dig = false;
2937 /* Actually dig node */
2939 if(is_valid_dig && n.getContent() != CONTENT_IGNORE)
2940 scriptapi_node_on_dig(m_lua, p_under, n, playersao);
2942 // Send unusual result (that is, node not being removed)
2943 if(m_env->getMap().getNodeNoEx(p_under).getContent() != CONTENT_AIR)
2945 // Re-send block to revert change on client-side
2946 RemoteClient *client = getClient(peer_id);
2947 v3s16 blockpos = getNodeBlockPos(floatToInt(pointed_pos_under, BS));
2948 client->SetBlockNotSent(blockpos);
2954 3: place block or right-click object
2956 else if(action == 3)
2958 ItemStack item = playersao->getWieldedItem();
2960 // Reset build time counter
2961 if(pointed.type == POINTEDTHING_NODE &&
2962 item.getDefinition(m_itemdef).type == ITEM_NODE)
2963 getClient(peer_id)->m_time_from_building = 0.0;
2965 if(pointed.type == POINTEDTHING_OBJECT)
2967 // Right click object
2969 // Skip if object has been removed
2970 if(pointed_object->m_removed)
2973 actionstream<<player->getName()<<" right-clicks object "
2974 <<pointed.object_id<<": "
2975 <<pointed_object->getDescription()<<std::endl;
2978 pointed_object->rightClick(playersao);
2980 else if(scriptapi_item_on_place(m_lua,
2981 item, playersao, pointed))
2983 // Placement was handled in lua
2985 // Apply returned ItemStack
2986 playersao->setWieldedItem(item);
2989 // If item has node placement prediction, always send the above
2990 // node to make sure the client knows what exactly happened
2991 if(item.getDefinition(m_itemdef).node_placement_prediction != ""){
2992 RemoteClient *client = getClient(peer_id);
2993 v3s16 blockpos = getNodeBlockPos(floatToInt(pointed_pos_above, BS));
2994 client->SetBlockNotSent(blockpos);
3001 else if(action == 4)
3003 ItemStack item = playersao->getWieldedItem();
3005 actionstream<<player->getName()<<" uses "<<item.name
3006 <<", pointing at "<<pointed.dump()<<std::endl;
3008 if(scriptapi_item_on_use(m_lua,
3009 item, playersao, pointed))
3011 // Apply returned ItemStack
3012 playersao->setWieldedItem(item);
3019 Catch invalid actions
3023 infostream<<"WARNING: Server: Invalid action "
3024 <<action<<std::endl;
3027 else if(command == TOSERVER_REMOVED_SOUNDS)
3029 std::string datastring((char*)&data[2], datasize-2);
3030 std::istringstream is(datastring, std::ios_base::binary);
3032 int num = readU16(is);
3033 for(int k=0; k<num; k++){
3034 s32 id = readS32(is);
3035 std::map<s32, ServerPlayingSound>::iterator i =
3036 m_playing_sounds.find(id);
3037 if(i == m_playing_sounds.end())
3039 ServerPlayingSound &psound = i->second;
3040 psound.clients.erase(peer_id);
3041 if(psound.clients.size() == 0)
3042 m_playing_sounds.erase(i++);
3045 else if(command == TOSERVER_NODEMETA_FIELDS)
3047 std::string datastring((char*)&data[2], datasize-2);
3048 std::istringstream is(datastring, std::ios_base::binary);
3050 v3s16 p = readV3S16(is);
3051 std::string formname = deSerializeString(is);
3052 int num = readU16(is);
3053 std::map<std::string, std::string> fields;
3054 for(int k=0; k<num; k++){
3055 std::string fieldname = deSerializeString(is);
3056 std::string fieldvalue = deSerializeLongString(is);
3057 fields[fieldname] = fieldvalue;
3060 // If something goes wrong, this player is to blame
3061 RollbackScopeActor rollback_scope(m_rollback,
3062 std::string("player:")+player->getName());
3064 // Check the target node for rollback data; leave others unnoticed
3065 RollbackNode rn_old(&m_env->getMap(), p, this);
3067 scriptapi_node_on_receive_fields(m_lua, p, formname, fields,
3070 // Report rollback data
3071 RollbackNode rn_new(&m_env->getMap(), p, this);
3072 if(rollback() && rn_new != rn_old){
3073 RollbackAction action;
3074 action.setSetNode(p, rn_old, rn_new);
3075 rollback()->reportAction(action);
3078 else if(command == TOSERVER_INVENTORY_FIELDS)
3080 std::string datastring((char*)&data[2], datasize-2);
3081 std::istringstream is(datastring, std::ios_base::binary);
3083 std::string formname = deSerializeString(is);
3084 int num = readU16(is);
3085 std::map<std::string, std::string> fields;
3086 for(int k=0; k<num; k++){
3087 std::string fieldname = deSerializeString(is);
3088 std::string fieldvalue = deSerializeLongString(is);
3089 fields[fieldname] = fieldvalue;
3092 scriptapi_on_player_receive_fields(m_lua, playersao, formname, fields);
3096 infostream<<"Server::ProcessData(): Ignoring "
3097 "unknown command "<<command<<std::endl;
3101 catch(SendFailedException &e)
3103 errorstream<<"Server::ProcessData(): SendFailedException: "
3109 void Server::onMapEditEvent(MapEditEvent *event)
3111 //infostream<<"Server::onMapEditEvent()"<<std::endl;
3112 if(m_ignore_map_edit_events)
3114 if(m_ignore_map_edit_events_area.contains(event->getArea()))
3116 MapEditEvent *e = event->clone();
3117 m_unsent_map_edit_queue.push_back(e);
3120 Inventory* Server::getInventory(const InventoryLocation &loc)
3123 case InventoryLocation::UNDEFINED:
3126 case InventoryLocation::CURRENT_PLAYER:
3129 case InventoryLocation::PLAYER:
3131 Player *player = m_env->getPlayer(loc.name.c_str());
3134 PlayerSAO *playersao = player->getPlayerSAO();
3137 return playersao->getInventory();
3140 case InventoryLocation::NODEMETA:
3142 NodeMetadata *meta = m_env->getMap().getNodeMetadata(loc.p);
3145 return meta->getInventory();
3148 case InventoryLocation::DETACHED:
3150 if(m_detached_inventories.count(loc.name) == 0)
3152 return m_detached_inventories[loc.name];
3160 void Server::setInventoryModified(const InventoryLocation &loc)
3163 case InventoryLocation::UNDEFINED:
3166 case InventoryLocation::PLAYER:
3168 Player *player = m_env->getPlayer(loc.name.c_str());
3171 PlayerSAO *playersao = player->getPlayerSAO();
3174 playersao->m_inventory_not_sent = true;
3175 playersao->m_wielded_item_not_sent = true;
3178 case InventoryLocation::NODEMETA:
3180 v3s16 blockpos = getNodeBlockPos(loc.p);
3182 MapBlock *block = m_env->getMap().getBlockNoCreateNoEx(blockpos);
3184 block->raiseModified(MOD_STATE_WRITE_NEEDED);
3186 setBlockNotSent(blockpos);
3189 case InventoryLocation::DETACHED:
3191 sendDetachedInventoryToAll(loc.name);
3199 std::list<PlayerInfo> Server::getPlayerInfo()
3201 DSTACK(__FUNCTION_NAME);
3202 JMutexAutoLock envlock(m_env_mutex);
3203 JMutexAutoLock conlock(m_con_mutex);
3205 std::list<PlayerInfo> list;
3207 std::list<Player*> players = m_env->getPlayers();
3209 std::list<Player*>::iterator i;
3210 for(i = players.begin();
3211 i != players.end(); ++i)
3215 Player *player = *i;
3218 // Copy info from connection to info struct
3219 info.id = player->peer_id;
3220 info.address = m_con.GetPeerAddress(player->peer_id);
3221 info.avg_rtt = m_con.GetPeerAvgRTT(player->peer_id);
3223 catch(con::PeerNotFoundException &e)
3225 // Set dummy peer info
3227 info.address = Address(0,0,0,0,0);
3231 snprintf(info.name, PLAYERNAME_SIZE, "%s", player->getName());
3232 info.position = player->getPosition();
3234 list.push_back(info);
3241 void Server::peerAdded(con::Peer *peer)
3243 DSTACK(__FUNCTION_NAME);
3244 verbosestream<<"Server::peerAdded(): peer->id="
3245 <<peer->id<<std::endl;
3248 c.type = PEER_ADDED;
3249 c.peer_id = peer->id;
3251 m_peer_change_queue.push_back(c);
3254 void Server::deletingPeer(con::Peer *peer, bool timeout)
3256 DSTACK(__FUNCTION_NAME);
3257 verbosestream<<"Server::deletingPeer(): peer->id="
3258 <<peer->id<<", timeout="<<timeout<<std::endl;
3261 c.type = PEER_REMOVED;
3262 c.peer_id = peer->id;
3263 c.timeout = timeout;
3264 m_peer_change_queue.push_back(c);
3271 void Server::SendMovement(con::Connection &con, u16 peer_id)
3273 DSTACK(__FUNCTION_NAME);
3274 std::ostringstream os(std::ios_base::binary);
3276 writeU16(os, TOCLIENT_MOVEMENT);
3277 writeF1000(os, g_settings->getFloat("movement_acceleration_default"));
3278 writeF1000(os, g_settings->getFloat("movement_acceleration_air"));
3279 writeF1000(os, g_settings->getFloat("movement_acceleration_fast"));
3280 writeF1000(os, g_settings->getFloat("movement_speed_walk"));
3281 writeF1000(os, g_settings->getFloat("movement_speed_crouch"));
3282 writeF1000(os, g_settings->getFloat("movement_speed_fast"));
3283 writeF1000(os, g_settings->getFloat("movement_speed_climb"));
3284 writeF1000(os, g_settings->getFloat("movement_speed_jump"));
3285 writeF1000(os, g_settings->getFloat("movement_liquid_fluidity"));
3286 writeF1000(os, g_settings->getFloat("movement_liquid_fluidity_smooth"));
3287 writeF1000(os, g_settings->getFloat("movement_liquid_sink"));
3288 writeF1000(os, g_settings->getFloat("movement_gravity"));
3291 std::string s = os.str();
3292 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3294 con.Send(peer_id, 0, data, true);
3297 void Server::SendHP(con::Connection &con, u16 peer_id, u8 hp)
3299 DSTACK(__FUNCTION_NAME);
3300 std::ostringstream os(std::ios_base::binary);
3302 writeU16(os, TOCLIENT_HP);
3306 std::string s = os.str();
3307 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3309 con.Send(peer_id, 0, data, true);
3312 void Server::SendAccessDenied(con::Connection &con, u16 peer_id,
3313 const std::wstring &reason)
3315 DSTACK(__FUNCTION_NAME);
3316 std::ostringstream os(std::ios_base::binary);
3318 writeU16(os, TOCLIENT_ACCESS_DENIED);
3319 os<<serializeWideString(reason);
3322 std::string s = os.str();
3323 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3325 con.Send(peer_id, 0, data, true);
3328 void Server::SendDeathscreen(con::Connection &con, u16 peer_id,
3329 bool set_camera_point_target, v3f camera_point_target)
3331 DSTACK(__FUNCTION_NAME);
3332 std::ostringstream os(std::ios_base::binary);
3334 writeU16(os, TOCLIENT_DEATHSCREEN);
3335 writeU8(os, set_camera_point_target);
3336 writeV3F1000(os, camera_point_target);
3339 std::string s = os.str();
3340 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3342 con.Send(peer_id, 0, data, true);
3345 void Server::SendItemDef(con::Connection &con, u16 peer_id,
3346 IItemDefManager *itemdef)
3348 DSTACK(__FUNCTION_NAME);
3349 std::ostringstream os(std::ios_base::binary);
3353 u32 length of the next item
3354 zlib-compressed serialized ItemDefManager
3356 writeU16(os, TOCLIENT_ITEMDEF);
3357 std::ostringstream tmp_os(std::ios::binary);
3358 itemdef->serialize(tmp_os);
3359 std::ostringstream tmp_os2(std::ios::binary);
3360 compressZlib(tmp_os.str(), tmp_os2);
3361 os<<serializeLongString(tmp_os2.str());
3364 std::string s = os.str();
3365 verbosestream<<"Server: Sending item definitions to id("<<peer_id
3366 <<"): size="<<s.size()<<std::endl;
3367 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3369 con.Send(peer_id, 0, data, true);
3372 void Server::SendNodeDef(con::Connection &con, u16 peer_id,
3373 INodeDefManager *nodedef, u16 protocol_version)
3375 DSTACK(__FUNCTION_NAME);
3376 std::ostringstream os(std::ios_base::binary);
3380 u32 length of the next item
3381 zlib-compressed serialized NodeDefManager
3383 writeU16(os, TOCLIENT_NODEDEF);
3384 std::ostringstream tmp_os(std::ios::binary);
3385 nodedef->serialize(tmp_os, protocol_version);
3386 std::ostringstream tmp_os2(std::ios::binary);
3387 compressZlib(tmp_os.str(), tmp_os2);
3388 os<<serializeLongString(tmp_os2.str());
3391 std::string s = os.str();
3392 verbosestream<<"Server: Sending node definitions to id("<<peer_id
3393 <<"): size="<<s.size()<<std::endl;
3394 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3396 con.Send(peer_id, 0, data, true);
3400 Non-static send methods
3403 void Server::SendInventory(u16 peer_id)
3405 DSTACK(__FUNCTION_NAME);
3407 PlayerSAO *playersao = getPlayerSAO(peer_id);
3410 playersao->m_inventory_not_sent = false;
3416 std::ostringstream os;
3417 playersao->getInventory()->serialize(os);
3419 std::string s = os.str();
3421 SharedBuffer<u8> data(s.size()+2);
3422 writeU16(&data[0], TOCLIENT_INVENTORY);
3423 memcpy(&data[2], s.c_str(), s.size());
3426 m_con.Send(peer_id, 0, data, true);
3429 void Server::SendChatMessage(u16 peer_id, const std::wstring &message)
3431 DSTACK(__FUNCTION_NAME);
3433 std::ostringstream os(std::ios_base::binary);
3437 writeU16(buf, TOCLIENT_CHAT_MESSAGE);
3438 os.write((char*)buf, 2);
3441 writeU16(buf, message.size());
3442 os.write((char*)buf, 2);
3445 for(u32 i=0; i<message.size(); i++)
3449 os.write((char*)buf, 2);
3453 std::string s = os.str();
3454 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3456 m_con.Send(peer_id, 0, data, true);
3458 void Server::SendShowFormspecMessage(u16 peer_id, const std::string formspec, const std::string formname)
3460 DSTACK(__FUNCTION_NAME);
3462 std::ostringstream os(std::ios_base::binary);
3466 writeU16(buf, TOCLIENT_SHOW_FORMSPEC);
3467 os.write((char*)buf, 2);
3468 os<<serializeLongString(formspec);
3469 os<<serializeString(formname);
3472 std::string s = os.str();
3473 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3475 m_con.Send(peer_id, 0, data, true);
3478 // Spawns a particle on peer with peer_id
3479 void Server::SendSpawnParticle(u16 peer_id, v3f pos, v3f velocity, v3f acceleration, float expirationtime, float size, bool collisiondetection, std::string texture)
3481 DSTACK(__FUNCTION_NAME);
3483 std::ostringstream os(std::ios_base::binary);
3484 writeU16(os, TOCLIENT_SPAWN_PARTICLE);
3485 writeV3F1000(os, pos);
3486 writeV3F1000(os, velocity);
3487 writeV3F1000(os, acceleration);
3488 writeF1000(os, expirationtime);
3489 writeF1000(os, size);
3490 writeU8(os, collisiondetection);
3491 os<<serializeLongString(texture);
3494 std::string s = os.str();
3495 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3497 m_con.Send(peer_id, 0, data, true);
3500 // Spawns a particle on all peers
3501 void Server::SendSpawnParticleAll(v3f pos, v3f velocity, v3f acceleration, float expirationtime, float size, bool collisiondetection, 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::BroadcastChatMessage(const std::wstring &message)
3606 for(std::map<u16, RemoteClient*>::iterator
3607 i = m_clients.begin();
3608 i != m_clients.end(); ++i)
3610 // Get client and check that it is valid
3611 RemoteClient *client = i->second;
3612 assert(client->peer_id == i->first);
3613 if(client->serialization_version == SER_FMT_VER_INVALID)
3616 SendChatMessage(client->peer_id, message);
3620 void Server::SendPlayerHP(u16 peer_id)
3622 DSTACK(__FUNCTION_NAME);
3623 PlayerSAO *playersao = getPlayerSAO(peer_id);
3625 playersao->m_hp_not_sent = false;
3626 SendHP(m_con, peer_id, playersao->getHP());
3629 void Server::SendMovePlayer(u16 peer_id)
3631 DSTACK(__FUNCTION_NAME);
3632 Player *player = m_env->getPlayer(peer_id);
3635 std::ostringstream os(std::ios_base::binary);
3636 writeU16(os, TOCLIENT_MOVE_PLAYER);
3637 writeV3F1000(os, player->getPosition());
3638 writeF1000(os, player->getPitch());
3639 writeF1000(os, player->getYaw());
3642 v3f pos = player->getPosition();
3643 f32 pitch = player->getPitch();
3644 f32 yaw = player->getYaw();
3645 verbosestream<<"Server: Sending TOCLIENT_MOVE_PLAYER"
3646 <<" pos=("<<pos.X<<","<<pos.Y<<","<<pos.Z<<")"
3653 std::string s = os.str();
3654 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3656 m_con.Send(peer_id, 0, data, true);
3659 void Server::SendPlayerPrivileges(u16 peer_id)
3661 Player *player = m_env->getPlayer(peer_id);
3663 if(player->peer_id == PEER_ID_INEXISTENT)
3666 std::set<std::string> privs;
3667 scriptapi_get_auth(m_lua, player->getName(), NULL, &privs);
3669 std::ostringstream os(std::ios_base::binary);
3670 writeU16(os, TOCLIENT_PRIVILEGES);
3671 writeU16(os, privs.size());
3672 for(std::set<std::string>::const_iterator i = privs.begin();
3673 i != privs.end(); i++){
3674 os<<serializeString(*i);
3678 std::string s = os.str();
3679 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3681 m_con.Send(peer_id, 0, data, true);
3684 void Server::SendPlayerInventoryFormspec(u16 peer_id)
3686 Player *player = m_env->getPlayer(peer_id);
3688 if(player->peer_id == PEER_ID_INEXISTENT)
3691 std::ostringstream os(std::ios_base::binary);
3692 writeU16(os, TOCLIENT_INVENTORY_FORMSPEC);
3693 os<<serializeLongString(player->inventory_formspec);
3696 std::string s = os.str();
3697 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3699 m_con.Send(peer_id, 0, data, true);
3702 s32 Server::playSound(const SimpleSoundSpec &spec,
3703 const ServerSoundParams ¶ms)
3705 // Find out initial position of sound
3706 bool pos_exists = false;
3707 v3f pos = params.getPos(m_env, &pos_exists);
3708 // If position is not found while it should be, cancel sound
3709 if(pos_exists != (params.type != ServerSoundParams::SSP_LOCAL))
3711 // Filter destination clients
3712 std::set<RemoteClient*> dst_clients;
3713 if(params.to_player != "")
3715 Player *player = m_env->getPlayer(params.to_player.c_str());
3717 infostream<<"Server::playSound: Player \""<<params.to_player
3718 <<"\" not found"<<std::endl;
3721 if(player->peer_id == PEER_ID_INEXISTENT){
3722 infostream<<"Server::playSound: Player \""<<params.to_player
3723 <<"\" not connected"<<std::endl;
3726 RemoteClient *client = getClient(player->peer_id);
3727 dst_clients.insert(client);
3731 for(std::map<u16, RemoteClient*>::iterator
3732 i = m_clients.begin(); i != m_clients.end(); ++i)
3734 RemoteClient *client = i->second;
3735 Player *player = m_env->getPlayer(client->peer_id);
3739 if(player->getPosition().getDistanceFrom(pos) >
3740 params.max_hear_distance)
3743 dst_clients.insert(client);
3746 if(dst_clients.size() == 0)
3749 s32 id = m_next_sound_id++;
3750 // The sound will exist as a reference in m_playing_sounds
3751 m_playing_sounds[id] = ServerPlayingSound();
3752 ServerPlayingSound &psound = m_playing_sounds[id];
3753 psound.params = params;
3754 for(std::set<RemoteClient*>::iterator i = dst_clients.begin();
3755 i != dst_clients.end(); i++)
3756 psound.clients.insert((*i)->peer_id);
3758 std::ostringstream os(std::ios_base::binary);
3759 writeU16(os, TOCLIENT_PLAY_SOUND);
3761 os<<serializeString(spec.name);
3762 writeF1000(os, spec.gain * params.gain);
3763 writeU8(os, params.type);
3764 writeV3F1000(os, pos);
3765 writeU16(os, params.object);
3766 writeU8(os, params.loop);
3768 std::string s = os.str();
3769 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3771 for(std::set<RemoteClient*>::iterator i = dst_clients.begin();
3772 i != dst_clients.end(); i++){
3774 m_con.Send((*i)->peer_id, 0, data, true);
3778 void Server::stopSound(s32 handle)
3780 // Get sound reference
3781 std::map<s32, ServerPlayingSound>::iterator i =
3782 m_playing_sounds.find(handle);
3783 if(i == m_playing_sounds.end())
3785 ServerPlayingSound &psound = i->second;
3787 std::ostringstream os(std::ios_base::binary);
3788 writeU16(os, TOCLIENT_STOP_SOUND);
3789 writeS32(os, handle);
3791 std::string s = os.str();
3792 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3794 for(std::set<u16>::iterator i = psound.clients.begin();
3795 i != psound.clients.end(); i++){
3797 m_con.Send(*i, 0, data, true);
3799 // Remove sound reference
3800 m_playing_sounds.erase(i);
3803 void Server::sendRemoveNode(v3s16 p, u16 ignore_id,
3804 std::list<u16> *far_players, float far_d_nodes)
3806 float maxd = far_d_nodes*BS;
3807 v3f p_f = intToFloat(p, BS);
3811 SharedBuffer<u8> reply(replysize);
3812 writeU16(&reply[0], TOCLIENT_REMOVENODE);
3813 writeS16(&reply[2], p.X);
3814 writeS16(&reply[4], p.Y);
3815 writeS16(&reply[6], p.Z);
3817 for(std::map<u16, RemoteClient*>::iterator
3818 i = m_clients.begin();
3819 i != m_clients.end(); ++i)
3821 // Get client and check that it is valid
3822 RemoteClient *client = i->second;
3823 assert(client->peer_id == i->first);
3824 if(client->serialization_version == SER_FMT_VER_INVALID)
3827 // Don't send if it's the same one
3828 if(client->peer_id == ignore_id)
3834 Player *player = m_env->getPlayer(client->peer_id);
3837 // If player is far away, only set modified blocks not sent
3838 v3f player_pos = player->getPosition();
3839 if(player_pos.getDistanceFrom(p_f) > maxd)
3841 far_players->push_back(client->peer_id);
3848 m_con.Send(client->peer_id, 0, reply, true);
3852 void Server::sendAddNode(v3s16 p, MapNode n, u16 ignore_id,
3853 std::list<u16> *far_players, float far_d_nodes)
3855 float maxd = far_d_nodes*BS;
3856 v3f p_f = intToFloat(p, BS);
3858 for(std::map<u16, RemoteClient*>::iterator
3859 i = m_clients.begin();
3860 i != m_clients.end(); ++i)
3862 // Get client and check that it is valid
3863 RemoteClient *client = i->second;
3864 assert(client->peer_id == i->first);
3865 if(client->serialization_version == SER_FMT_VER_INVALID)
3868 // Don't send if it's the same one
3869 if(client->peer_id == ignore_id)
3875 Player *player = m_env->getPlayer(client->peer_id);
3878 // If player is far away, only set modified blocks not sent
3879 v3f player_pos = player->getPosition();
3880 if(player_pos.getDistanceFrom(p_f) > maxd)
3882 far_players->push_back(client->peer_id);
3889 u32 replysize = 8 + MapNode::serializedLength(client->serialization_version);
3890 SharedBuffer<u8> reply(replysize);
3891 writeU16(&reply[0], TOCLIENT_ADDNODE);
3892 writeS16(&reply[2], p.X);
3893 writeS16(&reply[4], p.Y);
3894 writeS16(&reply[6], p.Z);
3895 n.serialize(&reply[8], client->serialization_version);
3898 m_con.Send(client->peer_id, 0, reply, true);
3902 void Server::setBlockNotSent(v3s16 p)
3904 for(std::map<u16, RemoteClient*>::iterator
3905 i = m_clients.begin();
3906 i != m_clients.end(); ++i)
3908 RemoteClient *client = i->second;
3909 client->SetBlockNotSent(p);
3913 void Server::SendBlockNoLock(u16 peer_id, MapBlock *block, u8 ver)
3915 DSTACK(__FUNCTION_NAME);
3917 v3s16 p = block->getPos();
3921 bool completely_air = true;
3922 for(s16 z0=0; z0<MAP_BLOCKSIZE; z0++)
3923 for(s16 x0=0; x0<MAP_BLOCKSIZE; x0++)
3924 for(s16 y0=0; y0<MAP_BLOCKSIZE; y0++)
3926 if(block->getNodeNoEx(v3s16(x0,y0,z0)).d != CONTENT_AIR)
3928 completely_air = false;
3929 x0 = y0 = z0 = MAP_BLOCKSIZE; // Break out
3934 infostream<<"Server: Sending block ("<<p.X<<","<<p.Y<<","<<p.Z<<"): ";
3936 infostream<<"[completely air] ";
3937 infostream<<std::endl;
3941 Create a packet with the block in the right format
3944 std::ostringstream os(std::ios_base::binary);
3945 block->serialize(os, ver, false);
3946 std::string s = os.str();
3947 SharedBuffer<u8> blockdata((u8*)s.c_str(), s.size());
3949 u32 replysize = 8 + blockdata.getSize();
3950 SharedBuffer<u8> reply(replysize);
3951 writeU16(&reply[0], TOCLIENT_BLOCKDATA);
3952 writeS16(&reply[2], p.X);
3953 writeS16(&reply[4], p.Y);
3954 writeS16(&reply[6], p.Z);
3955 memcpy(&reply[8], *blockdata, blockdata.getSize());
3957 /*infostream<<"Server: Sending block ("<<p.X<<","<<p.Y<<","<<p.Z<<")"
3958 <<": \tpacket size: "<<replysize<<std::endl;*/
3963 m_con.Send(peer_id, 1, reply, true);
3966 void Server::SendBlocks(float dtime)
3968 DSTACK(__FUNCTION_NAME);
3970 JMutexAutoLock envlock(m_env_mutex);
3971 JMutexAutoLock conlock(m_con_mutex);
3973 ScopeProfiler sp(g_profiler, "Server: sel and send blocks to clients");
3975 std::vector<PrioritySortedBlockTransfer> queue;
3977 s32 total_sending = 0;
3980 ScopeProfiler sp(g_profiler, "Server: selecting blocks for sending");
3982 for(std::map<u16, RemoteClient*>::iterator
3983 i = m_clients.begin();
3984 i != m_clients.end(); ++i)
3986 RemoteClient *client = i->second;
3987 assert(client->peer_id == i->first);
3989 // If definitions and textures have not been sent, don't
3990 // send MapBlocks either
3991 if(!client->definitions_sent)
3994 total_sending += client->SendingCount();
3996 if(client->serialization_version == SER_FMT_VER_INVALID)
3999 client->GetNextBlocks(this, dtime, queue);
4004 // Lowest priority number comes first.
4005 // Lowest is most important.
4006 std::sort(queue.begin(), queue.end());
4008 for(u32 i=0; i<queue.size(); i++)
4010 //TODO: Calculate limit dynamically
4011 if(total_sending >= g_settings->getS32
4012 ("max_simultaneous_block_sends_server_total"))
4015 PrioritySortedBlockTransfer q = queue[i];
4017 MapBlock *block = NULL;
4020 block = m_env->getMap().getBlockNoCreate(q.pos);
4022 catch(InvalidPositionException &e)
4027 RemoteClient *client = getClient(q.peer_id);
4029 SendBlockNoLock(q.peer_id, block, client->serialization_version);
4031 client->SentBlock(q.pos);
4037 void Server::fillMediaCache()
4039 DSTACK(__FUNCTION_NAME);
4041 infostream<<"Server: Calculating media file checksums"<<std::endl;
4043 // Collect all media file paths
4044 std::list<std::string> paths;
4045 for(std::vector<ModSpec>::iterator i = m_mods.begin();
4046 i != m_mods.end(); i++){
4047 const ModSpec &mod = *i;
4048 paths.push_back(mod.path + DIR_DELIM + "textures");
4049 paths.push_back(mod.path + DIR_DELIM + "sounds");
4050 paths.push_back(mod.path + DIR_DELIM + "media");
4051 paths.push_back(mod.path + DIR_DELIM + "models");
4053 std::string path_all = "textures";
4054 paths.push_back(path_all + DIR_DELIM + "all");
4056 // Collect media file information from paths into cache
4057 for(std::list<std::string>::iterator i = paths.begin();
4058 i != paths.end(); i++)
4060 std::string mediapath = *i;
4061 std::vector<fs::DirListNode> dirlist = fs::GetDirListing(mediapath);
4062 for(u32 j=0; j<dirlist.size(); j++){
4063 if(dirlist[j].dir) // Ignode dirs
4065 std::string filename = dirlist[j].name;
4066 // If name contains illegal characters, ignore the file
4067 if(!string_allowed(filename, TEXTURENAME_ALLOWED_CHARS)){
4068 infostream<<"Server: ignoring illegal file name: \""
4069 <<filename<<"\""<<std::endl;
4072 // If name is not in a supported format, ignore it
4073 const char *supported_ext[] = {
4074 ".png", ".jpg", ".bmp", ".tga",
4075 ".pcx", ".ppm", ".psd", ".wal", ".rgb",
4077 ".x", ".b3d", ".md2", ".obj",
4080 if(removeStringEnd(filename, supported_ext) == ""){
4081 infostream<<"Server: ignoring unsupported file extension: \""
4082 <<filename<<"\""<<std::endl;
4085 // Ok, attempt to load the file and add to cache
4086 std::string filepath = mediapath + DIR_DELIM + filename;
4088 std::ifstream fis(filepath.c_str(), std::ios_base::binary);
4089 if(fis.good() == false){
4090 errorstream<<"Server::fillMediaCache(): Could not open \""
4091 <<filename<<"\" for reading"<<std::endl;
4094 std::ostringstream tmp_os(std::ios_base::binary);
4098 fis.read(buf, 1024);
4099 std::streamsize len = fis.gcount();
4100 tmp_os.write(buf, len);
4109 errorstream<<"Server::fillMediaCache(): Failed to read \""
4110 <<filename<<"\""<<std::endl;
4113 if(tmp_os.str().length() == 0){
4114 errorstream<<"Server::fillMediaCache(): Empty file \""
4115 <<filepath<<"\""<<std::endl;
4120 sha1.addBytes(tmp_os.str().c_str(), tmp_os.str().length());
4122 unsigned char *digest = sha1.getDigest();
4123 std::string sha1_base64 = base64_encode(digest, 20);
4124 std::string sha1_hex = hex_encode((char*)digest, 20);
4128 this->m_media[filename] = MediaInfo(filepath, sha1_base64);
4129 verbosestream<<"Server: "<<sha1_hex<<" is "<<filename<<std::endl;
4134 struct SendableMediaAnnouncement
4137 std::string sha1_digest;
4139 SendableMediaAnnouncement(const std::string name_="",
4140 const std::string sha1_digest_=""):
4142 sha1_digest(sha1_digest_)
4146 void Server::sendMediaAnnouncement(u16 peer_id)
4148 DSTACK(__FUNCTION_NAME);
4150 verbosestream<<"Server: Announcing files to id("<<peer_id<<")"
4153 std::list<SendableMediaAnnouncement> file_announcements;
4155 for(std::map<std::string, MediaInfo>::iterator i = m_media.begin();
4156 i != m_media.end(); i++){
4158 file_announcements.push_back(
4159 SendableMediaAnnouncement(i->first, i->second.sha1_digest));
4163 std::ostringstream os(std::ios_base::binary);
4171 u16 length of sha1_digest
4176 writeU16(os, TOCLIENT_ANNOUNCE_MEDIA);
4177 writeU16(os, file_announcements.size());
4179 for(std::list<SendableMediaAnnouncement>::iterator
4180 j = file_announcements.begin();
4181 j != file_announcements.end(); ++j){
4182 os<<serializeString(j->name);
4183 os<<serializeString(j->sha1_digest);
4185 os<<serializeString(g_settings->get("remote_media"));
4188 std::string s = os.str();
4189 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
4192 m_con.Send(peer_id, 0, data, true);
4195 struct SendableMedia
4201 SendableMedia(const std::string &name_="", const std::string path_="",
4202 const std::string &data_=""):
4209 void Server::sendRequestedMedia(u16 peer_id,
4210 const std::list<MediaRequest> &tosend)
4212 DSTACK(__FUNCTION_NAME);
4214 verbosestream<<"Server::sendRequestedMedia(): "
4215 <<"Sending files to client"<<std::endl;
4219 // Put 5kB in one bunch (this is not accurate)
4220 u32 bytes_per_bunch = 5000;
4222 std::vector< std::list<SendableMedia> > file_bunches;
4223 file_bunches.push_back(std::list<SendableMedia>());
4225 u32 file_size_bunch_total = 0;
4227 for(std::list<MediaRequest>::const_iterator i = tosend.begin();
4228 i != tosend.end(); ++i)
4230 if(m_media.find(i->name) == m_media.end()){
4231 errorstream<<"Server::sendRequestedMedia(): Client asked for "
4232 <<"unknown file \""<<(i->name)<<"\""<<std::endl;
4236 //TODO get path + name
4237 std::string tpath = m_media[(*i).name].path;
4240 std::ifstream fis(tpath.c_str(), std::ios_base::binary);
4241 if(fis.good() == false){
4242 errorstream<<"Server::sendRequestedMedia(): Could not open \""
4243 <<tpath<<"\" for reading"<<std::endl;
4246 std::ostringstream tmp_os(std::ios_base::binary);
4250 fis.read(buf, 1024);
4251 std::streamsize len = fis.gcount();
4252 tmp_os.write(buf, len);
4253 file_size_bunch_total += len;
4262 errorstream<<"Server::sendRequestedMedia(): Failed to read \""
4263 <<(*i).name<<"\""<<std::endl;
4266 /*infostream<<"Server::sendRequestedMedia(): Loaded \""
4267 <<tname<<"\""<<std::endl;*/
4269 file_bunches[file_bunches.size()-1].push_back(
4270 SendableMedia((*i).name, tpath, tmp_os.str()));
4272 // Start next bunch if got enough data
4273 if(file_size_bunch_total >= bytes_per_bunch){
4274 file_bunches.push_back(std::list<SendableMedia>());
4275 file_size_bunch_total = 0;
4280 /* Create and send packets */
4282 u32 num_bunches = file_bunches.size();
4283 for(u32 i=0; i<num_bunches; i++)
4285 std::ostringstream os(std::ios_base::binary);
4289 u16 total number of texture bunches
4290 u16 index of this bunch
4291 u32 number of files in this bunch
4300 writeU16(os, TOCLIENT_MEDIA);
4301 writeU16(os, num_bunches);
4303 writeU32(os, file_bunches[i].size());
4305 for(std::list<SendableMedia>::iterator
4306 j = file_bunches[i].begin();
4307 j != file_bunches[i].end(); ++j){
4308 os<<serializeString(j->name);
4309 os<<serializeLongString(j->data);
4313 std::string s = os.str();
4314 verbosestream<<"Server::sendRequestedMedia(): bunch "
4315 <<i<<"/"<<num_bunches
4316 <<" files="<<file_bunches[i].size()
4317 <<" size=" <<s.size()<<std::endl;
4318 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
4320 m_con.Send(peer_id, 0, data, true);
4324 void Server::sendDetachedInventory(const std::string &name, u16 peer_id)
4326 if(m_detached_inventories.count(name) == 0){
4327 errorstream<<__FUNCTION_NAME<<": \""<<name<<"\" not found"<<std::endl;
4330 Inventory *inv = m_detached_inventories[name];
4332 std::ostringstream os(std::ios_base::binary);
4333 writeU16(os, TOCLIENT_DETACHED_INVENTORY);
4334 os<<serializeString(name);
4338 std::string s = os.str();
4339 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
4341 m_con.Send(peer_id, 0, data, true);
4344 void Server::sendDetachedInventoryToAll(const std::string &name)
4346 DSTACK(__FUNCTION_NAME);
4348 for(std::map<u16, RemoteClient*>::iterator
4349 i = m_clients.begin();
4350 i != m_clients.end(); ++i){
4351 RemoteClient *client = i->second;
4352 sendDetachedInventory(name, client->peer_id);
4356 void Server::sendDetachedInventories(u16 peer_id)
4358 DSTACK(__FUNCTION_NAME);
4360 for(std::map<std::string, Inventory*>::iterator
4361 i = m_detached_inventories.begin();
4362 i != m_detached_inventories.end(); i++){
4363 const std::string &name = i->first;
4364 //Inventory *inv = i->second;
4365 sendDetachedInventory(name, peer_id);
4373 void Server::DiePlayer(u16 peer_id)
4375 DSTACK(__FUNCTION_NAME);
4377 PlayerSAO *playersao = getPlayerSAO(peer_id);
4380 infostream<<"Server::DiePlayer(): Player "
4381 <<playersao->getPlayer()->getName()
4382 <<" dies"<<std::endl;
4384 playersao->setHP(0);
4386 // Trigger scripted stuff
4387 scriptapi_on_dieplayer(m_lua, playersao);
4389 SendPlayerHP(peer_id);
4390 SendDeathscreen(m_con, peer_id, false, v3f(0,0,0));
4393 void Server::RespawnPlayer(u16 peer_id)
4395 DSTACK(__FUNCTION_NAME);
4397 PlayerSAO *playersao = getPlayerSAO(peer_id);
4400 infostream<<"Server::RespawnPlayer(): Player "
4401 <<playersao->getPlayer()->getName()
4402 <<" respawns"<<std::endl;
4404 playersao->setHP(PLAYER_MAX_HP);
4406 bool repositioned = scriptapi_on_respawnplayer(m_lua, playersao);
4408 v3f pos = findSpawnPos(m_env->getServerMap());
4409 playersao->setPos(pos);
4413 void Server::UpdateCrafting(u16 peer_id)
4415 DSTACK(__FUNCTION_NAME);
4417 Player* player = m_env->getPlayer(peer_id);
4420 // Get a preview for crafting
4422 getCraftingResult(&player->inventory, preview, false, this);
4424 // Put the new preview in
4425 InventoryList *plist = player->inventory.getList("craftpreview");
4427 assert(plist->getSize() >= 1);
4428 plist->changeItem(0, preview);
4431 RemoteClient* Server::getClient(u16 peer_id)
4433 DSTACK(__FUNCTION_NAME);
4434 //JMutexAutoLock lock(m_con_mutex);
4435 std::map<u16, RemoteClient*>::iterator n;
4436 n = m_clients.find(peer_id);
4437 // A client should exist for all peers
4438 assert(n != m_clients.end());
4442 std::wstring Server::getStatusString()
4444 std::wostringstream os(std::ios_base::binary);
4447 os<<L"version="<<narrow_to_wide(VERSION_STRING);
4449 os<<L", uptime="<<m_uptime.get();
4450 // Information about clients
4451 std::map<u16, RemoteClient*>::iterator i;
4454 for(i = m_clients.begin(), first = true;
4455 i != m_clients.end(); ++i)
4457 // Get client and check that it is valid
4458 RemoteClient *client = i->second;
4459 assert(client->peer_id == i->first);
4460 if(client->serialization_version == SER_FMT_VER_INVALID)
4463 Player *player = m_env->getPlayer(client->peer_id);
4464 // Get name of player
4465 std::wstring name = L"unknown";
4467 name = narrow_to_wide(player->getName());
4468 // Add name to information string
4476 if(((ServerMap*)(&m_env->getMap()))->isSavingEnabled() == false)
4477 os<<std::endl<<L"# Server: "<<" WARNING: Map saving is disabled.";
4478 if(g_settings->get("motd") != "")
4479 os<<std::endl<<L"# Server: "<<narrow_to_wide(g_settings->get("motd"));
4483 std::set<std::string> Server::getPlayerEffectivePrivs(const std::string &name)
4485 std::set<std::string> privs;
4486 scriptapi_get_auth(m_lua, name, NULL, &privs);
4490 bool Server::checkPriv(const std::string &name, const std::string &priv)
4492 std::set<std::string> privs = getPlayerEffectivePrivs(name);
4493 return (privs.count(priv) != 0);
4496 void Server::reportPrivsModified(const std::string &name)
4499 for(std::map<u16, RemoteClient*>::iterator
4500 i = m_clients.begin();
4501 i != m_clients.end(); ++i){
4502 RemoteClient *client = i->second;
4503 Player *player = m_env->getPlayer(client->peer_id);
4504 reportPrivsModified(player->getName());
4507 Player *player = m_env->getPlayer(name.c_str());
4510 SendPlayerPrivileges(player->peer_id);
4511 PlayerSAO *sao = player->getPlayerSAO();
4514 sao->updatePrivileges(
4515 getPlayerEffectivePrivs(name),
4520 void Server::reportInventoryFormspecModified(const std::string &name)
4522 Player *player = m_env->getPlayer(name.c_str());
4525 SendPlayerInventoryFormspec(player->peer_id);
4528 // Saves g_settings to configpath given at initialization
4529 void Server::saveConfig()
4531 if(m_path_config != "")
4532 g_settings->updateConfigFile(m_path_config.c_str());
4535 void Server::notifyPlayer(const char *name, const std::wstring msg)
4537 Player *player = m_env->getPlayer(name);
4540 SendChatMessage(player->peer_id, std::wstring(L"Server: -!- ")+msg);
4543 bool Server::showFormspec(const char *playername, const std::string &formspec, const std::string &formname)
4545 Player *player = m_env->getPlayer(playername);
4549 infostream<<"showFormspec: couldn't find player:"<<playername<<std::endl;
4553 SendShowFormspecMessage(player->peer_id, formspec, formname);
4557 void Server::notifyPlayers(const std::wstring msg)
4559 BroadcastChatMessage(msg);
4562 void Server::spawnParticle(const char *playername, v3f pos,
4563 v3f velocity, v3f acceleration,
4564 float expirationtime, float size, bool
4565 collisiondetection, std::string texture)
4567 Player *player = m_env->getPlayer(playername);
4570 SendSpawnParticle(player->peer_id, pos, velocity, acceleration,
4571 expirationtime, size, collisiondetection, texture);
4574 void Server::spawnParticleAll(v3f pos, v3f velocity, v3f acceleration,
4575 float expirationtime, float size,
4576 bool collisiondetection, std::string texture)
4578 SendSpawnParticleAll(pos, velocity, acceleration,
4579 expirationtime, size, collisiondetection, texture);
4582 u32 Server::addParticleSpawner(const char *playername,
4583 u16 amount, float spawntime,
4584 v3f minpos, v3f maxpos,
4585 v3f minvel, v3f maxvel,
4586 v3f minacc, v3f maxacc,
4587 float minexptime, float maxexptime,
4588 float minsize, float maxsize,
4589 bool collisiondetection, std::string texture)
4591 Player *player = m_env->getPlayer(playername);
4596 for(;;) // look for unused particlespawner id
4599 if (std::find(m_particlespawner_ids.begin(),
4600 m_particlespawner_ids.end(), id)
4601 == m_particlespawner_ids.end())
4603 m_particlespawner_ids.push_back(id);
4608 SendAddParticleSpawner(player->peer_id, amount, spawntime,
4609 minpos, maxpos, minvel, maxvel, minacc, maxacc,
4610 minexptime, maxexptime, minsize, maxsize,
4611 collisiondetection, texture, id);
4616 u32 Server::addParticleSpawnerAll(u16 amount, float spawntime,
4617 v3f minpos, v3f maxpos,
4618 v3f minvel, v3f maxvel,
4619 v3f minacc, v3f maxacc,
4620 float minexptime, float maxexptime,
4621 float minsize, float maxsize,
4622 bool collisiondetection, std::string texture)
4625 for(;;) // look for unused particlespawner id
4628 if (std::find(m_particlespawner_ids.begin(),
4629 m_particlespawner_ids.end(), id)
4630 == m_particlespawner_ids.end())
4632 m_particlespawner_ids.push_back(id);
4637 SendAddParticleSpawnerAll(amount, spawntime,
4638 minpos, maxpos, minvel, maxvel, minacc, maxacc,
4639 minexptime, maxexptime, minsize, maxsize,
4640 collisiondetection, texture, id);
4645 void Server::deleteParticleSpawner(const char *playername, u32 id)
4647 Player *player = m_env->getPlayer(playername);
4651 m_particlespawner_ids.erase(
4652 std::remove(m_particlespawner_ids.begin(),
4653 m_particlespawner_ids.end(), id),
4654 m_particlespawner_ids.end());
4655 SendDeleteParticleSpawner(player->peer_id, id);
4658 void Server::deleteParticleSpawnerAll(u32 id)
4660 m_particlespawner_ids.erase(
4661 std::remove(m_particlespawner_ids.begin(),
4662 m_particlespawner_ids.end(), id),
4663 m_particlespawner_ids.end());
4664 SendDeleteParticleSpawnerAll(id);
4667 void Server::queueBlockEmerge(v3s16 blockpos, bool allow_generate)
4669 m_emerge->enqueueBlockEmerge(PEER_ID_INEXISTENT, blockpos, allow_generate);
4672 Inventory* Server::createDetachedInventory(const std::string &name)
4674 if(m_detached_inventories.count(name) > 0){
4675 infostream<<"Server clearing detached inventory \""<<name<<"\""<<std::endl;
4676 delete m_detached_inventories[name];
4678 infostream<<"Server creating detached inventory \""<<name<<"\""<<std::endl;
4680 Inventory *inv = new Inventory(m_itemdef);
4682 m_detached_inventories[name] = inv;
4683 sendDetachedInventoryToAll(name);
4690 BoolScopeSet(bool *dst, bool val):
4693 m_orig_state = *m_dst;
4698 *m_dst = m_orig_state;
4705 // actions: time-reversed list
4706 // Return value: success/failure
4707 bool Server::rollbackRevertActions(const std::list<RollbackAction> &actions,
4708 std::list<std::string> *log)
4710 infostream<<"Server::rollbackRevertActions(len="<<actions.size()<<")"<<std::endl;
4711 ServerMap *map = (ServerMap*)(&m_env->getMap());
4712 // Disable rollback report sink while reverting
4713 BoolScopeSet rollback_scope_disable(&m_rollback_sink_enabled, false);
4715 // Fail if no actions to handle
4716 if(actions.empty()){
4717 log->push_back("Nothing to do.");
4724 for(std::list<RollbackAction>::const_iterator
4725 i = actions.begin();
4726 i != actions.end(); i++)
4728 const RollbackAction &action = *i;
4730 bool success = action.applyRevert(map, this, this);
4733 std::ostringstream os;
4734 os<<"Revert of step ("<<num_tried<<") "<<action.toString()<<" failed";
4735 infostream<<"Map::rollbackRevertActions(): "<<os.str()<<std::endl;
4737 log->push_back(os.str());
4739 std::ostringstream os;
4740 os<<"Successfully reverted step ("<<num_tried<<") "<<action.toString();
4741 infostream<<"Map::rollbackRevertActions(): "<<os.str()<<std::endl;
4743 log->push_back(os.str());
4747 infostream<<"Map::rollbackRevertActions(): "<<num_failed<<"/"<<num_tried
4748 <<" failed"<<std::endl;
4750 // Call it done if less than half failed
4751 return num_failed <= num_tried/2;
4754 // IGameDef interface
4756 IItemDefManager* Server::getItemDefManager()
4760 INodeDefManager* Server::getNodeDefManager()
4764 ICraftDefManager* Server::getCraftDefManager()
4768 ITextureSource* Server::getTextureSource()
4772 IShaderSource* Server::getShaderSource()
4776 u16 Server::allocateUnknownNodeId(const std::string &name)
4778 return m_nodedef->allocateDummy(name);
4780 ISoundManager* Server::getSoundManager()
4782 return &dummySoundManager;
4784 MtEventManager* Server::getEventManager()
4788 IRollbackReportSink* Server::getRollbackReportSink()
4790 if(!m_enable_rollback_recording)
4792 if(!m_rollback_sink_enabled)
4797 IWritableItemDefManager* Server::getWritableItemDefManager()
4801 IWritableNodeDefManager* Server::getWritableNodeDefManager()
4805 IWritableCraftDefManager* Server::getWritableCraftDefManager()
4810 const ModSpec* Server::getModSpec(const std::string &modname)
4812 for(std::vector<ModSpec>::iterator i = m_mods.begin();
4813 i != m_mods.end(); i++){
4814 const ModSpec &mod = *i;
4815 if(mod.name == modname)
4820 void Server::getModNames(std::list<std::string> &modlist)
4822 for(std::vector<ModSpec>::iterator i = m_mods.begin(); i != m_mods.end(); i++)
4824 modlist.push_back(i->name);
4827 std::string Server::getBuiltinLuaPath()
4829 return porting::path_share + DIR_DELIM + "builtin";
4832 v3f findSpawnPos(ServerMap &map)
4834 //return v3f(50,50,50)*BS;
4839 nodepos = v2s16(0,0);
4844 s16 water_level = map.m_mgparams->water_level;
4846 // Try to find a good place a few times
4847 for(s32 i=0; i<1000; i++)
4850 // We're going to try to throw the player to this position
4851 v2s16 nodepos2d = v2s16(-range + (myrand()%(range*2)),
4852 -range + (myrand()%(range*2)));
4853 //v2s16 sectorpos = getNodeSectorPos(nodepos2d);
4854 // Get ground height at point (fallbacks to heightmap function)
4855 s16 groundheight = map.findGroundLevel(nodepos2d);
4856 // Don't go underwater
4857 if(groundheight <= water_level)
4859 //infostream<<"-> Underwater"<<std::endl;
4862 // Don't go to high places
4863 if(groundheight > water_level + 6)
4865 //infostream<<"-> Underwater"<<std::endl;
4869 nodepos = v3s16(nodepos2d.X, groundheight-2, nodepos2d.Y);
4870 bool is_good = false;
4872 for(s32 i=0; i<10; i++){
4873 v3s16 blockpos = getNodeBlockPos(nodepos);
4874 map.emergeBlock(blockpos, true);
4875 MapNode n = map.getNodeNoEx(nodepos);
4876 if(n.getContent() == CONTENT_AIR){
4887 // Found a good place
4888 //infostream<<"Searched through "<<i<<" places."<<std::endl;
4894 return intToFloat(nodepos, BS);
4897 PlayerSAO* Server::emergePlayer(const char *name, u16 peer_id)
4899 RemotePlayer *player = NULL;
4900 bool newplayer = false;
4903 Try to get an existing player
4905 player = static_cast<RemotePlayer*>(m_env->getPlayer(name));
4907 // If player is already connected, cancel
4908 if(player != NULL && player->peer_id != 0)
4910 infostream<<"emergePlayer(): Player already connected"<<std::endl;
4915 If player with the wanted peer_id already exists, cancel.
4917 if(m_env->getPlayer(peer_id) != NULL)
4919 infostream<<"emergePlayer(): Player with wrong name but same"
4920 " peer_id already exists"<<std::endl;
4925 Create a new player if it doesn't exist yet
4930 player = new RemotePlayer(this);
4931 player->updateName(name);
4933 /* Set player position */
4934 infostream<<"Server: Finding spawn place for player \""
4935 <<name<<"\""<<std::endl;
4936 v3f pos = findSpawnPos(m_env->getServerMap());
4937 player->setPosition(pos);
4939 /* Add player to environment */
4940 m_env->addPlayer(player);
4944 Create a new player active object
4946 PlayerSAO *playersao = new PlayerSAO(m_env, player, peer_id,
4947 getPlayerEffectivePrivs(player->getName()),
4950 /* Add object to environment */
4951 m_env->addActiveObject(playersao);
4955 scriptapi_on_newplayer(m_lua, playersao);
4957 scriptapi_on_joinplayer(m_lua, playersao);
4962 void Server::handlePeerChange(PeerChange &c)
4964 JMutexAutoLock envlock(m_env_mutex);
4965 JMutexAutoLock conlock(m_con_mutex);
4967 if(c.type == PEER_ADDED)
4974 std::map<u16, RemoteClient*>::iterator n;
4975 n = m_clients.find(c.peer_id);
4976 // The client shouldn't already exist
4977 assert(n == m_clients.end());
4980 RemoteClient *client = new RemoteClient();
4981 client->peer_id = c.peer_id;
4982 m_clients[client->peer_id] = client;
4985 else if(c.type == PEER_REMOVED)
4992 std::map<u16, RemoteClient*>::iterator n;
4993 n = m_clients.find(c.peer_id);
4994 // The client should exist
4995 assert(n != m_clients.end());
4998 Mark objects to be not known by the client
5000 RemoteClient *client = n->second;
5002 for(std::set<u16>::iterator
5003 i = client->m_known_objects.begin();
5004 i != client->m_known_objects.end(); ++i)
5008 ServerActiveObject* obj = m_env->getActiveObject(id);
5010 if(obj && obj->m_known_by_count > 0)
5011 obj->m_known_by_count--;
5015 Clear references to playing sounds
5017 for(std::map<s32, ServerPlayingSound>::iterator
5018 i = m_playing_sounds.begin();
5019 i != m_playing_sounds.end();)
5021 ServerPlayingSound &psound = i->second;
5022 psound.clients.erase(c.peer_id);
5023 if(psound.clients.size() == 0)
5024 m_playing_sounds.erase(i++);
5029 Player *player = m_env->getPlayer(c.peer_id);
5031 // Collect information about leaving in chat
5032 std::wstring message;
5036 std::wstring name = narrow_to_wide(player->getName());
5039 message += L" left the game.";
5041 message += L" (timed out)";
5045 /* Run scripts and remove from environment */
5049 PlayerSAO *playersao = player->getPlayerSAO();
5052 scriptapi_on_leaveplayer(m_lua, playersao);
5054 playersao->disconnected();
5064 std::ostringstream os(std::ios_base::binary);
5065 for(std::map<u16, RemoteClient*>::iterator
5066 i = m_clients.begin();
5067 i != m_clients.end(); ++i)
5069 RemoteClient *client = i->second;
5070 assert(client->peer_id == i->first);
5071 if(client->serialization_version == SER_FMT_VER_INVALID)
5074 Player *player = m_env->getPlayer(client->peer_id);
5077 // Get name of player
5078 os<<player->getName()<<" ";
5081 actionstream<<player->getName()<<" "
5082 <<(c.timeout?"times out.":"leaves game.")
5083 <<" List of players: "
5084 <<os.str()<<std::endl;
5089 delete m_clients[c.peer_id];
5090 m_clients.erase(c.peer_id);
5092 // Send player info to all remaining clients
5093 //SendPlayerInfos();
5095 // Send leave chat message to all remaining clients
5096 if(message.length() != 0)
5097 BroadcastChatMessage(message);
5106 void Server::handlePeerChanges()
5108 while(m_peer_change_queue.size() > 0)
5110 PeerChange c = m_peer_change_queue.pop_front();
5112 verbosestream<<"Server: Handling peer change: "
5113 <<"id="<<c.peer_id<<", timeout="<<c.timeout
5116 handlePeerChange(c);
5120 void dedicated_server_loop(Server &server, bool &kill)
5122 DSTACK(__FUNCTION_NAME);
5124 verbosestream<<"dedicated_server_loop()"<<std::endl;
5126 IntervalLimiter m_profiler_interval;
5130 float steplen = g_settings->getFloat("dedicated_server_step");
5131 // This is kind of a hack but can be done like this
5132 // because server.step() is very light
5134 ScopeProfiler sp(g_profiler, "dedicated server sleep");
5135 sleep_ms((int)(steplen*1000.0));
5137 server.step(steplen);
5139 if(server.getShutdownRequested() || kill)
5141 infostream<<"Dedicated server quitting"<<std::endl;
5143 if(g_settings->getBool("server_announce") == true)
5144 ServerList::sendAnnounce("delete");
5152 float profiler_print_interval =
5153 g_settings->getFloat("profiler_print_interval");
5154 if(profiler_print_interval != 0)
5156 if(m_profiler_interval.step(steplen, profiler_print_interval))
5158 infostream<<"Profiler:"<<std::endl;
5159 g_profiler->print(infostream);
5160 g_profiler->clear();