3 Copyright (C) 2010-2013 celeron55, Perttu Ahola <celeron55@gmail.com>
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU Lesser General Public License as published by
7 the Free Software Foundation; either version 2.1 of the License, or
8 (at your option) any later version.
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU Lesser General Public License for more details.
15 You should have received a copy of the GNU Lesser General Public License along
16 with this program; if not, write to the Free Software Foundation, Inc.,
17 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
24 #include "clientserver.h"
26 #include "jmutexautolock.h"
28 #include "constants.h"
33 #include "serverobject.h"
38 #include "scriptapi.h"
45 #include "content_mapnode.h"
46 #include "content_nodemeta.h"
47 #include "content_abm.h"
48 #include "content_sao.h"
53 #include "sound.h" // dummySoundManager
54 #include "event_manager.h"
56 #include "serverlist.h"
57 #include "util/string.h"
58 #include "util/pointedthing.h"
59 #include "util/mathconstants.h"
61 #include "util/serialize.h"
62 #include "defaultsettings.h"
64 void * ServerThread::Thread()
68 log_register_thread("ServerThread");
70 DSTACK(__FUNCTION_NAME);
72 BEGIN_DEBUG_EXCEPTION_HANDLER
77 //TimeTaker timer("AsyncRunStep() + Receive()");
80 //TimeTaker timer("AsyncRunStep()");
81 m_server->AsyncRunStep();
84 //infostream<<"Running m_server->Receive()"<<std::endl;
87 catch(con::NoIncomingDataException &e)
90 catch(con::PeerNotFoundException &e)
92 infostream<<"Server: PeerNotFoundException"<<std::endl;
94 catch(con::ConnectionBindFailed &e)
96 m_server->setAsyncFatalError(e.what());
100 m_server->setAsyncFatalError(e.what());
104 END_DEBUG_EXCEPTION_HANDLER(errorstream)
109 v3f ServerSoundParams::getPos(ServerEnvironment *env, bool *pos_exists) const
111 if(pos_exists) *pos_exists = false;
116 if(pos_exists) *pos_exists = true;
121 ServerActiveObject *sao = env->getActiveObject(object);
124 if(pos_exists) *pos_exists = true;
125 return sao->getBasePosition(); }
130 void RemoteClient::GetNextBlocks(Server *server, float dtime,
131 std::vector<PrioritySortedBlockTransfer> &dest)
133 DSTACK(__FUNCTION_NAME);
136 TimeTaker timer("RemoteClient::GetNextBlocks", &timer_result);*/
139 m_nothing_to_send_pause_timer -= dtime;
140 m_nearest_unsent_reset_timer += dtime;
142 if(m_nothing_to_send_pause_timer >= 0)
145 Player *player = server->m_env->getPlayer(peer_id);
146 // This can happen sometimes; clients and players are not in perfect sync.
150 // Won't send anything if already sending
151 if(m_blocks_sending.size() >= g_settings->getU16
152 ("max_simultaneous_block_sends_per_client"))
154 //infostream<<"Not sending any blocks, Queue full."<<std::endl;
158 //TimeTaker timer("RemoteClient::GetNextBlocks");
160 v3f playerpos = player->getPosition();
161 v3f playerspeed = player->getSpeed();
162 v3f playerspeeddir(0,0,0);
163 if(playerspeed.getLength() > 1.0*BS)
164 playerspeeddir = playerspeed / playerspeed.getLength();
165 // Predict to next block
166 v3f playerpos_predicted = playerpos + playerspeeddir*MAP_BLOCKSIZE*BS;
168 v3s16 center_nodepos = floatToInt(playerpos_predicted, BS);
170 v3s16 center = getNodeBlockPos(center_nodepos);
172 // Camera position and direction
173 v3f camera_pos = player->getEyePosition();
174 v3f camera_dir = v3f(0,0,1);
175 camera_dir.rotateYZBy(player->getPitch());
176 camera_dir.rotateXZBy(player->getYaw());
178 /*infostream<<"camera_dir=("<<camera_dir.X<<","<<camera_dir.Y<<","
179 <<camera_dir.Z<<")"<<std::endl;*/
182 Get the starting value of the block finder radius.
185 if(m_last_center != center)
187 m_nearest_unsent_d = 0;
188 m_last_center = center;
191 /*infostream<<"m_nearest_unsent_reset_timer="
192 <<m_nearest_unsent_reset_timer<<std::endl;*/
194 // Reset periodically to workaround for some bugs or stuff
195 if(m_nearest_unsent_reset_timer > 20.0)
197 m_nearest_unsent_reset_timer = 0;
198 m_nearest_unsent_d = 0;
199 //infostream<<"Resetting m_nearest_unsent_d for "
200 // <<server->getPlayerName(peer_id)<<std::endl;
203 //s16 last_nearest_unsent_d = m_nearest_unsent_d;
204 s16 d_start = m_nearest_unsent_d;
206 //infostream<<"d_start="<<d_start<<std::endl;
208 u16 max_simul_sends_setting = g_settings->getU16
209 ("max_simultaneous_block_sends_per_client");
210 u16 max_simul_sends_usually = max_simul_sends_setting;
213 Check the time from last addNode/removeNode.
215 Decrease send rate if player is building stuff.
217 m_time_from_building += dtime;
218 if(m_time_from_building < g_settings->getFloat(
219 "full_block_send_enable_min_time_from_building"))
221 max_simul_sends_usually
222 = LIMITED_MAX_SIMULTANEOUS_BLOCK_SENDS;
226 Number of blocks sending + number of blocks selected for sending
228 u32 num_blocks_selected = m_blocks_sending.size();
231 next time d will be continued from the d from which the nearest
232 unsent block was found this time.
234 This is because not necessarily any of the blocks found this
235 time are actually sent.
237 s32 new_nearest_unsent_d = -1;
239 s16 d_max = g_settings->getS16("max_block_send_distance");
240 s16 d_max_gen = g_settings->getS16("max_block_generate_distance");
242 // Don't loop very much at a time
243 s16 max_d_increment_at_time = 2;
244 if(d_max > d_start + max_d_increment_at_time)
245 d_max = d_start + max_d_increment_at_time;
246 /*if(d_max_gen > d_start+2)
247 d_max_gen = d_start+2;*/
249 //infostream<<"Starting from "<<d_start<<std::endl;
251 s32 nearest_emerged_d = -1;
252 s32 nearest_emergefull_d = -1;
253 s32 nearest_sent_d = -1;
254 bool queue_is_full = false;
257 for(d = d_start; d <= d_max; d++)
259 /*errorstream<<"checking d="<<d<<" for "
260 <<server->getPlayerName(peer_id)<<std::endl;*/
261 //infostream<<"RemoteClient::SendBlocks(): d="<<d<<std::endl;
264 If m_nearest_unsent_d was changed by the EmergeThread
265 (it can change it to 0 through SetBlockNotSent),
267 Else update m_nearest_unsent_d
269 /*if(m_nearest_unsent_d != last_nearest_unsent_d)
271 d = m_nearest_unsent_d;
272 last_nearest_unsent_d = m_nearest_unsent_d;
276 Get the border/face dot coordinates of a "d-radiused"
279 std::list<v3s16> list;
280 getFacePositions(list, d);
282 std::list<v3s16>::iterator li;
283 for(li=list.begin(); li!=list.end(); ++li)
285 v3s16 p = *li + center;
289 - Don't allow too many simultaneous transfers
290 - EXCEPT when the blocks are very close
292 Also, don't send blocks that are already flying.
295 // Start with the usual maximum
296 u16 max_simul_dynamic = max_simul_sends_usually;
298 // If block is very close, allow full maximum
299 if(d <= BLOCK_SEND_DISABLE_LIMITS_MAX_D)
300 max_simul_dynamic = max_simul_sends_setting;
302 // Don't select too many blocks for sending
303 if(num_blocks_selected >= max_simul_dynamic)
305 queue_is_full = true;
306 goto queue_full_break;
309 // Don't send blocks that are currently being transferred
310 if(m_blocks_sending.find(p) != m_blocks_sending.end())
316 if(p.X < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
317 || p.X > MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
318 || p.Y < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
319 || p.Y > MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
320 || p.Z < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
321 || p.Z > MAP_GENERATION_LIMIT / MAP_BLOCKSIZE)
324 // If this is true, inexistent block will be made from scratch
325 bool generate = d <= d_max_gen;
328 /*// Limit the generating area vertically to 2/3
329 if(abs(p.Y - center.Y) > d_max_gen - d_max_gen / 3)
332 // Limit the send area vertically to 1/2
333 if(abs(p.Y - center.Y) > d_max / 2)
339 If block is far away, don't generate it unless it is
345 // Block center y in nodes
346 f32 y = (f32)(p.Y * MAP_BLOCKSIZE + MAP_BLOCKSIZE/2);
347 // Don't generate if it's very high or very low
348 if(y < -64 || y > 64)
352 v2s16 p2d_nodes_center(
356 // Get ground height in nodes
357 s16 gh = server->m_env->getServerMap().findGroundLevel(
360 // If differs a lot, don't generate
361 if(fabs(gh - y) > MAP_BLOCKSIZE*2)
363 // Actually, don't even send it
369 //infostream<<"d="<<d<<std::endl;
372 Don't generate or send if not in sight
373 FIXME This only works if the client uses a small enough
374 FOV setting. The default of 72 degrees is fine.
377 float camera_fov = (72.0*M_PI/180) * 4./3.;
378 if(isBlockInSight(p, camera_pos, camera_dir, camera_fov, 10000*BS) == false)
384 Don't send already sent blocks
387 if(m_blocks_sent.find(p) != m_blocks_sent.end())
394 Check if map has this block
396 MapBlock *block = server->m_env->getMap().getBlockNoCreateNoEx(p);
398 bool surely_not_found_on_disk = false;
399 bool block_is_invalid = false;
402 // Reset usage timer, this block will be of use in the future.
403 block->resetUsageTimer();
405 // Block is dummy if data doesn't exist.
406 // It means it has been not found from disk and not generated
409 surely_not_found_on_disk = true;
412 // Block is valid if lighting is up-to-date and data exists
413 if(block->isValid() == false)
415 block_is_invalid = true;
418 /*if(block->isFullyGenerated() == false)
420 block_is_invalid = true;
425 ServerMap *map = (ServerMap*)(&server->m_env->getMap());
426 v2s16 chunkpos = map->sector_to_chunk(p2d);
427 if(map->chunkNonVolatile(chunkpos) == false)
428 block_is_invalid = true;
430 if(block->isGenerated() == false)
431 block_is_invalid = true;
434 If block is not close, don't send it unless it is near
437 Block is near ground level if night-time mesh
438 differs from day-time mesh.
442 if(block->getDayNightDiff() == false)
449 If block has been marked to not exist on disk (dummy)
450 and generating new ones is not wanted, skip block.
452 if(generate == false && surely_not_found_on_disk == true)
459 Add inexistent block to emerge queue.
461 if(block == NULL || surely_not_found_on_disk || block_is_invalid)
463 /* //TODO: Get value from somewhere
464 // Allow only one block in emerge queue
465 //if(server->m_emerge_queue.peerItemCount(peer_id) < 1)
466 // Allow two blocks in queue per client
467 //if(server->m_emerge_queue.peerItemCount(peer_id) < 2)
469 // Make it more responsive when needing to generate stuff
470 if(surely_not_found_on_disk)
472 if(server->m_emerge_queue.peerItemCount(peer_id) < max_emerge)
474 //infostream<<"Adding block to emerge queue"<<std::endl;
476 // Add it to the emerge queue and trigger the thread
479 if(generate == false)
480 flags |= BLOCK_EMERGE_FLAG_FROMDISK;
482 server->m_emerge_queue.addBlock(peer_id, p, flags);
483 server->m_emergethread.trigger();
485 if(nearest_emerged_d == -1)
486 nearest_emerged_d = d;
488 if(nearest_emergefull_d == -1)
489 nearest_emergefull_d = d;
490 goto queue_full_break;
494 if (server->m_emerge->enqueueBlockEmerge(peer_id, p, generate)) {
495 if (nearest_emerged_d == -1)
496 nearest_emerged_d = d;
498 if (nearest_emergefull_d == -1)
499 nearest_emergefull_d = d;
500 goto queue_full_break;
507 if(nearest_sent_d == -1)
511 Add block to send queue
514 /*errorstream<<"sending from d="<<d<<" to "
515 <<server->getPlayerName(peer_id)<<std::endl;*/
517 PrioritySortedBlockTransfer q((float)d, p, peer_id);
521 num_blocks_selected += 1;
526 //infostream<<"Stopped at "<<d<<std::endl;
528 // If nothing was found for sending and nothing was queued for
529 // emerging, continue next time browsing from here
530 if(nearest_emerged_d != -1){
531 new_nearest_unsent_d = nearest_emerged_d;
532 } else if(nearest_emergefull_d != -1){
533 new_nearest_unsent_d = nearest_emergefull_d;
535 if(d > g_settings->getS16("max_block_send_distance")){
536 new_nearest_unsent_d = 0;
537 m_nothing_to_send_pause_timer = 2.0;
538 /*infostream<<"GetNextBlocks(): d wrapped around for "
539 <<server->getPlayerName(peer_id)
540 <<"; setting to 0 and pausing"<<std::endl;*/
542 if(nearest_sent_d != -1)
543 new_nearest_unsent_d = nearest_sent_d;
545 new_nearest_unsent_d = d;
549 if(new_nearest_unsent_d != -1)
550 m_nearest_unsent_d = new_nearest_unsent_d;
552 /*timer_result = timer.stop(true);
553 if(timer_result != 0)
554 infostream<<"GetNextBlocks timeout: "<<timer_result<<" (!=0)"<<std::endl;*/
557 void RemoteClient::GotBlock(v3s16 p)
559 if(m_blocks_sending.find(p) != m_blocks_sending.end())
560 m_blocks_sending.erase(p);
563 /*infostream<<"RemoteClient::GotBlock(): Didn't find in"
564 " m_blocks_sending"<<std::endl;*/
565 m_excess_gotblocks++;
567 m_blocks_sent.insert(p);
570 void RemoteClient::SentBlock(v3s16 p)
572 if(m_blocks_sending.find(p) == m_blocks_sending.end())
573 m_blocks_sending[p] = 0.0;
575 infostream<<"RemoteClient::SentBlock(): Sent block"
576 " already in m_blocks_sending"<<std::endl;
579 void RemoteClient::SetBlockNotSent(v3s16 p)
581 m_nearest_unsent_d = 0;
583 if(m_blocks_sending.find(p) != m_blocks_sending.end())
584 m_blocks_sending.erase(p);
585 if(m_blocks_sent.find(p) != m_blocks_sent.end())
586 m_blocks_sent.erase(p);
589 void RemoteClient::SetBlocksNotSent(std::map<v3s16, MapBlock*> &blocks)
591 m_nearest_unsent_d = 0;
593 for(std::map<v3s16, MapBlock*>::iterator
595 i != blocks.end(); ++i)
599 if(m_blocks_sending.find(p) != m_blocks_sending.end())
600 m_blocks_sending.erase(p);
601 if(m_blocks_sent.find(p) != m_blocks_sent.end())
602 m_blocks_sent.erase(p);
610 PlayerInfo::PlayerInfo()
616 void PlayerInfo::PrintLine(std::ostream *s)
619 (*s)<<"\""<<name<<"\" ("
620 <<(position.X/10)<<","<<(position.Y/10)
621 <<","<<(position.Z/10)<<") ";
623 (*s)<<" avg_rtt="<<avg_rtt;
632 const std::string &path_world,
633 const std::string &path_config,
634 const SubgameSpec &gamespec,
635 bool simple_singleplayer_mode
637 m_path_world(path_world),
638 m_path_config(path_config),
639 m_gamespec(gamespec),
640 m_simple_singleplayer_mode(simple_singleplayer_mode),
641 m_async_fatal_error(""),
643 m_con(PROTOCOL_ID, 512, CONNECTION_TIMEOUT, this),
644 m_banmanager(path_world+DIR_DELIM+"ipban.txt"),
646 m_rollback_sink_enabled(true),
647 m_enable_rollback_recording(false),
650 m_itemdef(createItemDefManager()),
651 m_nodedef(createNodeDefManager()),
652 m_craftdef(createCraftDefManager()),
653 m_event(new EventManager()),
655 m_time_of_day_send_timer(0),
657 m_shutdown_requested(false),
658 m_ignore_map_edit_events(false),
659 m_ignore_map_edit_events_peer_id(0)
661 m_liquid_transform_timer = 0.0;
662 m_liquid_transform_every = 1.0;
663 m_print_info_timer = 0.0;
664 m_masterserver_timer = 0.0;
665 m_objectdata_timer = 0.0;
666 m_emergethread_trigger_timer = 0.0;
667 m_savemap_timer = 0.0;
668 m_clients_number = 0;
672 m_step_dtime_mutex.Init();
676 throw ServerError("Supplied empty world path");
678 if(!gamespec.isValid())
679 throw ServerError("Supplied invalid gamespec");
681 infostream<<"Server created for gameid \""<<m_gamespec.id<<"\"";
682 if(m_simple_singleplayer_mode)
683 infostream<<" in simple singleplayer mode"<<std::endl;
685 infostream<<std::endl;
686 infostream<<"- world: "<<m_path_world<<std::endl;
687 infostream<<"- config: "<<m_path_config<<std::endl;
688 infostream<<"- game: "<<m_gamespec.path<<std::endl;
690 // Initialize default settings and override defaults with those provided
692 set_default_settings(g_settings);
693 Settings gamedefaults;
694 getGameMinetestConfig(gamespec.path, gamedefaults);
695 override_default_settings(g_settings, &gamedefaults);
697 // Create emerge manager
698 m_emerge = new EmergeManager(this);
700 // Create rollback manager
701 std::string rollback_path = m_path_world+DIR_DELIM+"rollback.txt";
702 m_rollback = createRollbackManager(rollback_path, this);
704 // Create world if it doesn't exist
705 if(!initializeWorld(m_path_world, m_gamespec.id))
706 throw ServerError("Failed to initialize world");
708 ModConfiguration modconf(m_path_world);
709 m_mods = modconf.getMods();
710 std::vector<ModSpec> unsatisfied_mods = modconf.getUnsatisfiedMods();
711 // complain about mods with unsatisfied dependencies
712 if(!modconf.isConsistent())
714 for(std::vector<ModSpec>::iterator it = unsatisfied_mods.begin();
715 it != unsatisfied_mods.end(); ++it)
718 errorstream << "mod \"" << mod.name << "\" has unsatisfied dependencies: ";
719 for(std::set<std::string>::iterator dep_it = mod.unsatisfied_depends.begin();
720 dep_it != mod.unsatisfied_depends.end(); ++dep_it)
721 errorstream << " \"" << *dep_it << "\"";
722 errorstream << std::endl;
726 Settings worldmt_settings;
727 std::string worldmt = m_path_world + DIR_DELIM + "world.mt";
728 worldmt_settings.readConfigFile(worldmt.c_str());
729 std::vector<std::string> names = worldmt_settings.getNames();
730 std::set<std::string> load_mod_names;
731 for(std::vector<std::string>::iterator it = names.begin();
732 it != names.end(); ++it)
734 std::string name = *it;
735 if(name.compare(0,9,"load_mod_")==0 && worldmt_settings.getBool(name))
736 load_mod_names.insert(name.substr(9));
738 // complain about mods declared to be loaded, but not found
739 for(std::vector<ModSpec>::iterator it = m_mods.begin();
740 it != m_mods.end(); ++it)
741 load_mod_names.erase((*it).name);
742 for(std::vector<ModSpec>::iterator it = unsatisfied_mods.begin();
743 it != unsatisfied_mods.end(); ++it)
744 load_mod_names.erase((*it).name);
745 if(!load_mod_names.empty())
747 errorstream << "The following mods could not be found:";
748 for(std::set<std::string>::iterator it = load_mod_names.begin();
749 it != load_mod_names.end(); ++it)
750 errorstream << " \"" << (*it) << "\"";
751 errorstream << std::endl;
754 // Path to builtin.lua
755 std::string builtinpath = getBuiltinLuaPath() + DIR_DELIM + "builtin.lua";
758 JMutexAutoLock envlock(m_env_mutex);
759 JMutexAutoLock conlock(m_con_mutex);
761 // Initialize scripting
763 infostream<<"Server: Initializing Lua"<<std::endl;
764 m_lua = script_init();
767 scriptapi_export(m_lua, this);
768 // Load and run builtin.lua
769 infostream<<"Server: Loading builtin.lua [\""
770 <<builtinpath<<"\"]"<<std::endl;
771 bool success = scriptapi_loadmod(m_lua, builtinpath, "__builtin");
773 errorstream<<"Server: Failed to load and run "
774 <<builtinpath<<std::endl;
775 throw ModError("Failed to load and run "+builtinpath);
778 infostream<<"Server: Loading mods: ";
779 for(std::vector<ModSpec>::iterator i = m_mods.begin();
780 i != m_mods.end(); i++){
781 const ModSpec &mod = *i;
782 infostream<<mod.name<<" ";
784 infostream<<std::endl;
785 // Load and run "mod" scripts
786 for(std::vector<ModSpec>::iterator i = m_mods.begin();
787 i != m_mods.end(); i++){
788 const ModSpec &mod = *i;
789 std::string scriptpath = mod.path + DIR_DELIM + "init.lua";
790 infostream<<" ["<<padStringRight(mod.name, 12)<<"] [\""
791 <<scriptpath<<"\"]"<<std::endl;
792 bool success = scriptapi_loadmod(m_lua, scriptpath, mod.name);
794 errorstream<<"Server: Failed to load and run "
795 <<scriptpath<<std::endl;
796 throw ModError("Failed to load and run "+scriptpath);
800 // Read Textures and calculate sha1 sums
803 // Apply item aliases in the node definition manager
804 m_nodedef->updateAliases(m_itemdef);
806 // Initialize Environment
807 ServerMap *servermap = new ServerMap(path_world, this, m_emerge);
808 m_env = new ServerEnvironment(servermap, m_lua, this, this);
810 m_emerge->initMapgens(servermap->getMapgenParams());
812 // Give environment reference to scripting api
813 scriptapi_add_environment(m_lua, m_env);
815 // Register us to receive map edit events
816 servermap->addEventReceiver(this);
818 // If file exists, load environment metadata
819 if(fs::PathExists(m_path_world+DIR_DELIM+"env_meta.txt"))
821 infostream<<"Server: Loading environment metadata"<<std::endl;
822 m_env->loadMeta(m_path_world);
826 infostream<<"Server: Loading players"<<std::endl;
827 m_env->deSerializePlayers(m_path_world);
830 Add some test ActiveBlockModifiers to environment
832 add_legacy_abms(m_env, m_nodedef);
834 m_liquid_transform_every = g_settings->getFloat("liquid_update");
839 infostream<<"Server destructing"<<std::endl;
842 Send shutdown message
845 JMutexAutoLock conlock(m_con_mutex);
847 std::wstring line = L"*** Server shutting down";
850 Send the message to clients
852 for(std::map<u16, RemoteClient*>::iterator
853 i = m_clients.begin();
854 i != m_clients.end(); ++i)
856 // Get client and check that it is valid
857 RemoteClient *client = i->second;
858 assert(client->peer_id == i->first);
859 if(client->serialization_version == SER_FMT_VER_INVALID)
863 SendChatMessage(client->peer_id, line);
865 catch(con::PeerNotFoundException &e)
871 JMutexAutoLock envlock(m_env_mutex);
872 JMutexAutoLock conlock(m_con_mutex);
875 Execute script shutdown hooks
877 scriptapi_on_shutdown(m_lua);
881 JMutexAutoLock envlock(m_env_mutex);
886 infostream<<"Server: Saving players"<<std::endl;
887 m_env->serializePlayers(m_path_world);
890 Save environment metadata
892 infostream<<"Server: Saving environment metadata"<<std::endl;
893 m_env->saveMeta(m_path_world);
901 //shutdown all emerge threads first!
908 JMutexAutoLock clientslock(m_con_mutex);
910 for(std::map<u16, RemoteClient*>::iterator
911 i = m_clients.begin();
912 i != m_clients.end(); ++i)
920 // Delete things in the reverse order of creation
928 // Deinitialize scripting
929 infostream<<"Server: Deinitializing scripting"<<std::endl;
930 script_deinit(m_lua);
932 // Delete detached inventories
934 for(std::map<std::string, Inventory*>::iterator
935 i = m_detached_inventories.begin();
936 i != m_detached_inventories.end(); i++){
942 void Server::start(unsigned short port)
944 DSTACK(__FUNCTION_NAME);
945 infostream<<"Starting server on port "<<port<<"..."<<std::endl;
947 // Stop thread if already running
950 // Initialize connection
951 m_con.SetTimeoutMs(30);
955 m_thread.setRun(true);
958 // ASCII art for the win!
960 <<" .__ __ __ "<<std::endl
961 <<" _____ |__| ____ _____/ |_ ____ _______/ |_ "<<std::endl
962 <<" / \\| |/ \\_/ __ \\ __\\/ __ \\ / ___/\\ __\\"<<std::endl
963 <<"| Y Y \\ | | \\ ___/| | \\ ___/ \\___ \\ | | "<<std::endl
964 <<"|__|_| /__|___| /\\___ >__| \\___ >____ > |__| "<<std::endl
965 <<" \\/ \\/ \\/ \\/ \\/ "<<std::endl;
966 actionstream<<"World at ["<<m_path_world<<"]"<<std::endl;
967 actionstream<<"Server for gameid=\""<<m_gamespec.id
968 <<"\" listening on port "<<port<<"."<<std::endl;
973 DSTACK(__FUNCTION_NAME);
975 infostream<<"Server: Stopping and waiting threads"<<std::endl;
977 // Stop threads (set run=false first so both start stopping)
978 m_thread.setRun(false);
979 //m_emergethread.setRun(false);
981 //m_emergethread.stop();
983 infostream<<"Server: Threads stopped"<<std::endl;
986 void Server::step(float dtime)
988 DSTACK(__FUNCTION_NAME);
993 JMutexAutoLock lock(m_step_dtime_mutex);
994 m_step_dtime += dtime;
996 // Throw if fatal error occurred in thread
997 std::string async_err = m_async_fatal_error.get();
999 throw ServerError(async_err);
1003 void Server::AsyncRunStep()
1005 DSTACK(__FUNCTION_NAME);
1007 g_profiler->add("Server::AsyncRunStep (num)", 1);
1011 JMutexAutoLock lock1(m_step_dtime_mutex);
1012 dtime = m_step_dtime;
1016 // Send blocks to clients
1023 g_profiler->add("Server::AsyncRunStep with dtime (num)", 1);
1025 //infostream<<"Server steps "<<dtime<<std::endl;
1026 //infostream<<"Server::AsyncRunStep(): dtime="<<dtime<<std::endl;
1029 JMutexAutoLock lock1(m_step_dtime_mutex);
1030 m_step_dtime -= dtime;
1037 m_uptime.set(m_uptime.get() + dtime);
1041 // Process connection's timeouts
1042 JMutexAutoLock lock2(m_con_mutex);
1043 ScopeProfiler sp(g_profiler, "Server: connection timeout processing");
1044 m_con.RunTimeouts(dtime);
1048 // This has to be called so that the client list gets synced
1049 // with the peer list of the connection
1050 handlePeerChanges();
1054 Update time of day and overall game time
1057 JMutexAutoLock envlock(m_env_mutex);
1059 m_env->setTimeOfDaySpeed(g_settings->getFloat("time_speed"));
1062 Send to clients at constant intervals
1065 m_time_of_day_send_timer -= dtime;
1066 if(m_time_of_day_send_timer < 0.0)
1068 m_time_of_day_send_timer = g_settings->getFloat("time_send_interval");
1070 //JMutexAutoLock envlock(m_env_mutex);
1071 JMutexAutoLock conlock(m_con_mutex);
1073 for(std::map<u16, RemoteClient*>::iterator
1074 i = m_clients.begin();
1075 i != m_clients.end(); ++i)
1077 RemoteClient *client = i->second;
1078 SharedBuffer<u8> data = makePacket_TOCLIENT_TIME_OF_DAY(
1079 m_env->getTimeOfDay(), g_settings->getFloat("time_speed"));
1081 m_con.Send(client->peer_id, 0, data, true);
1087 JMutexAutoLock lock(m_env_mutex);
1089 ScopeProfiler sp(g_profiler, "SEnv step");
1090 ScopeProfiler sp2(g_profiler, "SEnv step avg", SPT_AVG);
1094 const float map_timer_and_unload_dtime = 2.92;
1095 if(m_map_timer_and_unload_interval.step(dtime, map_timer_and_unload_dtime))
1097 JMutexAutoLock lock(m_env_mutex);
1098 // Run Map's timers and unload unused data
1099 ScopeProfiler sp(g_profiler, "Server: map timer and unload");
1100 m_env->getMap().timerUpdate(map_timer_and_unload_dtime,
1101 g_settings->getFloat("server_unload_unused_data_timeout"));
1112 JMutexAutoLock lock(m_env_mutex);
1113 JMutexAutoLock lock2(m_con_mutex);
1115 ScopeProfiler sp(g_profiler, "Server: handle players");
1117 for(std::map<u16, RemoteClient*>::iterator
1118 i = m_clients.begin();
1119 i != m_clients.end(); ++i)
1121 RemoteClient *client = i->second;
1122 PlayerSAO *playersao = getPlayerSAO(client->peer_id);
1123 if(playersao == NULL)
1127 Handle player HPs (die if hp=0)
1129 if(playersao->m_hp_not_sent && g_settings->getBool("enable_damage"))
1131 if(playersao->getHP() == 0)
1132 DiePlayer(client->peer_id);
1134 SendPlayerHP(client->peer_id);
1138 Send player inventories if necessary
1140 if(playersao->m_moved){
1141 SendMovePlayer(client->peer_id);
1142 playersao->m_moved = false;
1144 if(playersao->m_inventory_not_sent){
1145 UpdateCrafting(client->peer_id);
1146 SendInventory(client->peer_id);
1151 /* Transform liquids */
1152 m_liquid_transform_timer += dtime;
1153 if(m_liquid_transform_timer >= m_liquid_transform_every)
1155 m_liquid_transform_timer -= m_liquid_transform_every;
1157 JMutexAutoLock lock(m_env_mutex);
1159 ScopeProfiler sp(g_profiler, "Server: liquid transform");
1161 std::map<v3s16, MapBlock*> modified_blocks;
1162 m_env->getMap().transformLiquids(modified_blocks);
1167 core::map<v3s16, MapBlock*> lighting_modified_blocks;
1168 ServerMap &map = ((ServerMap&)m_env->getMap());
1169 map.updateLighting(modified_blocks, lighting_modified_blocks);
1171 // Add blocks modified by lighting to modified_blocks
1172 for(core::map<v3s16, MapBlock*>::Iterator
1173 i = lighting_modified_blocks.getIterator();
1174 i.atEnd() == false; i++)
1176 MapBlock *block = i.getNode()->getValue();
1177 modified_blocks.insert(block->getPos(), block);
1181 Set the modified blocks unsent for all the clients
1184 JMutexAutoLock lock2(m_con_mutex);
1186 for(std::map<u16, RemoteClient*>::iterator
1187 i = m_clients.begin();
1188 i != m_clients.end(); ++i)
1190 RemoteClient *client = i->second;
1192 if(modified_blocks.size() > 0)
1194 // Remove block from sent history
1195 client->SetBlocksNotSent(modified_blocks);
1200 // Periodically print some info
1202 float &counter = m_print_info_timer;
1208 JMutexAutoLock lock2(m_con_mutex);
1209 m_clients_number = 0;
1210 if(m_clients.size() != 0)
1211 infostream<<"Players:"<<std::endl;
1212 for(std::map<u16, RemoteClient*>::iterator
1213 i = m_clients.begin();
1214 i != m_clients.end(); ++i)
1216 //u16 peer_id = i.getNode()->getKey();
1217 RemoteClient *client = i->second;
1218 Player *player = m_env->getPlayer(client->peer_id);
1221 infostream<<"* "<<player->getName()<<"\t";
1222 client->PrintInfo(infostream);
1230 // send masterserver announce
1232 float &counter = m_masterserver_timer;
1233 if((!counter || counter >= 300.0) && g_settings->getBool("server_announce") == true)
1235 ServerList::sendAnnounce(!counter ? "start" : "update", m_clients_number, m_uptime.get(), m_gamespec.id);
1242 //if(g_settings->getBool("enable_experimental"))
1246 Check added and deleted active objects
1249 //infostream<<"Server: Checking added and deleted active objects"<<std::endl;
1250 JMutexAutoLock envlock(m_env_mutex);
1251 JMutexAutoLock conlock(m_con_mutex);
1253 ScopeProfiler sp(g_profiler, "Server: checking added and deleted objs");
1255 // Radius inside which objects are active
1256 s16 radius = g_settings->getS16("active_object_send_range_blocks");
1257 radius *= MAP_BLOCKSIZE;
1259 for(std::map<u16, RemoteClient*>::iterator
1260 i = m_clients.begin();
1261 i != m_clients.end(); ++i)
1263 RemoteClient *client = i->second;
1265 // If definitions and textures have not been sent, don't
1266 // send objects either
1267 if(!client->definitions_sent)
1270 Player *player = m_env->getPlayer(client->peer_id);
1273 // This can happen if the client timeouts somehow
1274 /*infostream<<"WARNING: "<<__FUNCTION_NAME<<": Client "
1276 <<" has no associated player"<<std::endl;*/
1279 v3s16 pos = floatToInt(player->getPosition(), BS);
1281 std::set<u16> removed_objects;
1282 std::set<u16> added_objects;
1283 m_env->getRemovedActiveObjects(pos, radius,
1284 client->m_known_objects, removed_objects);
1285 m_env->getAddedActiveObjects(pos, radius,
1286 client->m_known_objects, added_objects);
1288 // Ignore if nothing happened
1289 if(removed_objects.size() == 0 && added_objects.size() == 0)
1291 //infostream<<"active objects: none changed"<<std::endl;
1295 std::string data_buffer;
1299 // Handle removed objects
1300 writeU16((u8*)buf, removed_objects.size());
1301 data_buffer.append(buf, 2);
1302 for(std::set<u16>::iterator
1303 i = removed_objects.begin();
1304 i != removed_objects.end(); ++i)
1308 ServerActiveObject* obj = m_env->getActiveObject(id);
1310 // Add to data buffer for sending
1311 writeU16((u8*)buf, id);
1312 data_buffer.append(buf, 2);
1314 // Remove from known objects
1315 client->m_known_objects.erase(id);
1317 if(obj && obj->m_known_by_count > 0)
1318 obj->m_known_by_count--;
1321 // Handle added objects
1322 writeU16((u8*)buf, added_objects.size());
1323 data_buffer.append(buf, 2);
1324 for(std::set<u16>::iterator
1325 i = added_objects.begin();
1326 i != added_objects.end(); ++i)
1330 ServerActiveObject* obj = m_env->getActiveObject(id);
1333 u8 type = ACTIVEOBJECT_TYPE_INVALID;
1335 infostream<<"WARNING: "<<__FUNCTION_NAME
1336 <<": NULL object"<<std::endl;
1338 type = obj->getSendType();
1340 // Add to data buffer for sending
1341 writeU16((u8*)buf, id);
1342 data_buffer.append(buf, 2);
1343 writeU8((u8*)buf, type);
1344 data_buffer.append(buf, 1);
1347 data_buffer.append(serializeLongString(
1348 obj->getClientInitializationData(client->net_proto_version)));
1350 data_buffer.append(serializeLongString(""));
1352 // Add to known objects
1353 client->m_known_objects.insert(id);
1356 obj->m_known_by_count++;
1360 SharedBuffer<u8> reply(2 + data_buffer.size());
1361 writeU16(&reply[0], TOCLIENT_ACTIVE_OBJECT_REMOVE_ADD);
1362 memcpy((char*)&reply[2], data_buffer.c_str(),
1363 data_buffer.size());
1365 m_con.Send(client->peer_id, 0, reply, true);
1367 verbosestream<<"Server: Sent object remove/add: "
1368 <<removed_objects.size()<<" removed, "
1369 <<added_objects.size()<<" added, "
1370 <<"packet size is "<<reply.getSize()<<std::endl;
1375 Collect a list of all the objects known by the clients
1376 and report it back to the environment.
1379 core::map<u16, bool> all_known_objects;
1381 for(core::map<u16, RemoteClient*>::Iterator
1382 i = m_clients.getIterator();
1383 i.atEnd() == false; i++)
1385 RemoteClient *client = i.getNode()->getValue();
1386 // Go through all known objects of client
1387 for(core::map<u16, bool>::Iterator
1388 i = client->m_known_objects.getIterator();
1389 i.atEnd()==false; i++)
1391 u16 id = i.getNode()->getKey();
1392 all_known_objects[id] = true;
1396 m_env->setKnownActiveObjects(whatever);
1402 Send object messages
1405 JMutexAutoLock envlock(m_env_mutex);
1406 JMutexAutoLock conlock(m_con_mutex);
1408 ScopeProfiler sp(g_profiler, "Server: sending object messages");
1411 // Value = data sent by object
1412 std::map<u16, std::list<ActiveObjectMessage>* > buffered_messages;
1414 // Get active object messages from environment
1417 ActiveObjectMessage aom = m_env->getActiveObjectMessage();
1421 std::list<ActiveObjectMessage>* message_list = NULL;
1422 std::map<u16, std::list<ActiveObjectMessage>* >::iterator n;
1423 n = buffered_messages.find(aom.id);
1424 if(n == buffered_messages.end())
1426 message_list = new std::list<ActiveObjectMessage>;
1427 buffered_messages[aom.id] = message_list;
1431 message_list = n->second;
1433 message_list->push_back(aom);
1436 // Route data to every client
1437 for(std::map<u16, RemoteClient*>::iterator
1438 i = m_clients.begin();
1439 i != m_clients.end(); ++i)
1441 RemoteClient *client = i->second;
1442 std::string reliable_data;
1443 std::string unreliable_data;
1444 // Go through all objects in message buffer
1445 for(std::map<u16, std::list<ActiveObjectMessage>* >::iterator
1446 j = buffered_messages.begin();
1447 j != buffered_messages.end(); ++j)
1449 // If object is not known by client, skip it
1451 if(client->m_known_objects.find(id) == client->m_known_objects.end())
1453 // Get message list of object
1454 std::list<ActiveObjectMessage>* list = j->second;
1455 // Go through every message
1456 for(std::list<ActiveObjectMessage>::iterator
1457 k = list->begin(); k != list->end(); ++k)
1459 // Compose the full new data with header
1460 ActiveObjectMessage aom = *k;
1461 std::string new_data;
1464 writeU16((u8*)&buf[0], aom.id);
1465 new_data.append(buf, 2);
1467 new_data += serializeString(aom.datastring);
1468 // Add data to buffer
1470 reliable_data += new_data;
1472 unreliable_data += new_data;
1476 reliable_data and unreliable_data are now ready.
1479 if(reliable_data.size() > 0)
1481 SharedBuffer<u8> reply(2 + reliable_data.size());
1482 writeU16(&reply[0], TOCLIENT_ACTIVE_OBJECT_MESSAGES);
1483 memcpy((char*)&reply[2], reliable_data.c_str(),
1484 reliable_data.size());
1486 m_con.Send(client->peer_id, 0, reply, true);
1488 if(unreliable_data.size() > 0)
1490 SharedBuffer<u8> reply(2 + unreliable_data.size());
1491 writeU16(&reply[0], TOCLIENT_ACTIVE_OBJECT_MESSAGES);
1492 memcpy((char*)&reply[2], unreliable_data.c_str(),
1493 unreliable_data.size());
1494 // Send as unreliable
1495 m_con.Send(client->peer_id, 0, reply, false);
1498 /*if(reliable_data.size() > 0 || unreliable_data.size() > 0)
1500 infostream<<"Server: Size of object message data: "
1501 <<"reliable: "<<reliable_data.size()
1502 <<", unreliable: "<<unreliable_data.size()
1507 // Clear buffered_messages
1508 for(std::map<u16, std::list<ActiveObjectMessage>* >::iterator
1509 i = buffered_messages.begin();
1510 i != buffered_messages.end(); ++i)
1516 } // enable_experimental
1519 Send queued-for-sending map edit events.
1522 // We will be accessing the environment and the connection
1523 JMutexAutoLock lock(m_env_mutex);
1524 JMutexAutoLock conlock(m_con_mutex);
1526 // Don't send too many at a time
1529 // Single change sending is disabled if queue size is not small
1530 bool disable_single_change_sending = false;
1531 if(m_unsent_map_edit_queue.size() >= 4)
1532 disable_single_change_sending = true;
1534 int event_count = m_unsent_map_edit_queue.size();
1536 // We'll log the amount of each
1539 while(m_unsent_map_edit_queue.size() != 0)
1541 MapEditEvent* event = m_unsent_map_edit_queue.pop_front();
1543 // Players far away from the change are stored here.
1544 // Instead of sending the changes, MapBlocks are set not sent
1546 std::list<u16> far_players;
1548 if(event->type == MEET_ADDNODE)
1550 //infostream<<"Server: MEET_ADDNODE"<<std::endl;
1551 prof.add("MEET_ADDNODE", 1);
1552 if(disable_single_change_sending)
1553 sendAddNode(event->p, event->n, event->already_known_by_peer,
1556 sendAddNode(event->p, event->n, event->already_known_by_peer,
1559 else if(event->type == MEET_REMOVENODE)
1561 //infostream<<"Server: MEET_REMOVENODE"<<std::endl;
1562 prof.add("MEET_REMOVENODE", 1);
1563 if(disable_single_change_sending)
1564 sendRemoveNode(event->p, event->already_known_by_peer,
1567 sendRemoveNode(event->p, event->already_known_by_peer,
1570 else if(event->type == MEET_BLOCK_NODE_METADATA_CHANGED)
1572 infostream<<"Server: MEET_BLOCK_NODE_METADATA_CHANGED"<<std::endl;
1573 prof.add("MEET_BLOCK_NODE_METADATA_CHANGED", 1);
1574 setBlockNotSent(event->p);
1576 else if(event->type == MEET_OTHER)
1578 infostream<<"Server: MEET_OTHER"<<std::endl;
1579 prof.add("MEET_OTHER", 1);
1580 for(std::set<v3s16>::iterator
1581 i = event->modified_blocks.begin();
1582 i != event->modified_blocks.end(); ++i)
1584 setBlockNotSent(*i);
1589 prof.add("unknown", 1);
1590 infostream<<"WARNING: Server: Unknown MapEditEvent "
1591 <<((u32)event->type)<<std::endl;
1595 Set blocks not sent to far players
1597 if(far_players.size() > 0)
1599 // Convert list format to that wanted by SetBlocksNotSent
1600 std::map<v3s16, MapBlock*> modified_blocks2;
1601 for(std::set<v3s16>::iterator
1602 i = event->modified_blocks.begin();
1603 i != event->modified_blocks.end(); ++i)
1605 modified_blocks2[*i] =
1606 m_env->getMap().getBlockNoCreateNoEx(*i);
1608 // Set blocks not sent
1609 for(std::list<u16>::iterator
1610 i = far_players.begin();
1611 i != far_players.end(); ++i)
1614 RemoteClient *client = getClient(peer_id);
1617 client->SetBlocksNotSent(modified_blocks2);
1623 /*// Don't send too many at a time
1625 if(count >= 1 && m_unsent_map_edit_queue.size() < 100)
1629 if(event_count >= 5){
1630 infostream<<"Server: MapEditEvents:"<<std::endl;
1631 prof.print(infostream);
1632 } else if(event_count != 0){
1633 verbosestream<<"Server: MapEditEvents:"<<std::endl;
1634 prof.print(verbosestream);
1640 Trigger emergethread (it somehow gets to a non-triggered but
1641 bysy state sometimes)
1644 float &counter = m_emergethread_trigger_timer;
1650 for (unsigned int i = 0; i != m_emerge->emergethread.size(); i++)
1651 m_emerge->emergethread[i]->trigger();
1653 // Update m_enable_rollback_recording here too
1654 m_enable_rollback_recording =
1655 g_settings->getBool("enable_rollback_recording");
1659 // Save map, players and auth stuff
1661 float &counter = m_savemap_timer;
1663 if(counter >= g_settings->getFloat("server_map_save_interval"))
1666 JMutexAutoLock lock(m_env_mutex);
1668 ScopeProfiler sp(g_profiler, "Server: saving stuff");
1671 if(m_banmanager.isModified())
1672 m_banmanager.save();
1674 // Save changed parts of map
1675 m_env->getMap().save(MOD_STATE_WRITE_NEEDED);
1678 m_env->serializePlayers(m_path_world);
1680 // Save environment metadata
1681 m_env->saveMeta(m_path_world);
1686 void Server::Receive()
1688 DSTACK(__FUNCTION_NAME);
1689 SharedBuffer<u8> data;
1694 JMutexAutoLock conlock(m_con_mutex);
1695 datasize = m_con.Receive(peer_id, data);
1698 // This has to be called so that the client list gets synced
1699 // with the peer list of the connection
1700 handlePeerChanges();
1702 ProcessData(*data, datasize, peer_id);
1704 catch(con::InvalidIncomingDataException &e)
1706 infostream<<"Server::Receive(): "
1707 "InvalidIncomingDataException: what()="
1708 <<e.what()<<std::endl;
1710 catch(con::PeerNotFoundException &e)
1712 //NOTE: This is not needed anymore
1714 // The peer has been disconnected.
1715 // Find the associated player and remove it.
1717 /*JMutexAutoLock envlock(m_env_mutex);
1719 infostream<<"ServerThread: peer_id="<<peer_id
1720 <<" has apparently closed connection. "
1721 <<"Removing player."<<std::endl;
1723 m_env->removePlayer(peer_id);*/
1727 void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
1729 DSTACK(__FUNCTION_NAME);
1730 // Environment is locked first.
1731 JMutexAutoLock envlock(m_env_mutex);
1732 JMutexAutoLock conlock(m_con_mutex);
1734 ScopeProfiler sp(g_profiler, "Server::ProcessData");
1737 Address address = m_con.GetPeerAddress(peer_id);
1738 std::string addr_s = address.serializeString();
1740 // drop player if is ip is banned
1741 if(m_banmanager.isIpBanned(addr_s)){
1742 infostream<<"Server: A banned client tried to connect from "
1743 <<addr_s<<"; banned name was "
1744 <<m_banmanager.getBanName(addr_s)<<std::endl;
1745 // This actually doesn't seem to transfer to the client
1746 SendAccessDenied(m_con, peer_id,
1747 L"Your ip is banned. Banned name was "
1748 +narrow_to_wide(m_banmanager.getBanName(addr_s)));
1749 m_con.DeletePeer(peer_id);
1753 catch(con::PeerNotFoundException &e)
1755 infostream<<"Server::ProcessData(): Cancelling: peer "
1756 <<peer_id<<" not found"<<std::endl;
1760 std::string addr_s = m_con.GetPeerAddress(peer_id).serializeString();
1762 u8 peer_ser_ver = getClient(peer_id)->serialization_version;
1770 ToServerCommand command = (ToServerCommand)readU16(&data[0]);
1772 if(command == TOSERVER_INIT)
1774 // [0] u16 TOSERVER_INIT
1775 // [2] u8 SER_FMT_VER_HIGHEST
1776 // [3] u8[20] player_name
1777 // [23] u8[28] password <--- can be sent without this, from old versions
1779 if(datasize < 2+1+PLAYERNAME_SIZE)
1782 verbosestream<<"Server: Got TOSERVER_INIT from "
1783 <<peer_id<<std::endl;
1785 // First byte after command is maximum supported
1786 // serialization version
1787 u8 client_max = data[2];
1788 u8 our_max = SER_FMT_VER_HIGHEST;
1789 // Use the highest version supported by both
1790 u8 deployed = std::min(client_max, our_max);
1791 // If it's lower than the lowest supported, give up.
1792 if(deployed < SER_FMT_VER_LOWEST)
1793 deployed = SER_FMT_VER_INVALID;
1795 //peer->serialization_version = deployed;
1796 getClient(peer_id)->pending_serialization_version = deployed;
1798 if(deployed == SER_FMT_VER_INVALID)
1800 actionstream<<"Server: A mismatched client tried to connect from "
1801 <<addr_s<<std::endl;
1802 infostream<<"Server: Cannot negotiate "
1803 "serialization version with peer "
1804 <<peer_id<<std::endl;
1805 SendAccessDenied(m_con, peer_id, std::wstring(
1806 L"Your client's version is not supported.\n"
1807 L"Server version is ")
1808 + narrow_to_wide(VERSION_STRING) + L"."
1814 Read and check network protocol version
1817 u16 min_net_proto_version = 0;
1818 if(datasize >= 2+1+PLAYERNAME_SIZE+PASSWORD_SIZE+2)
1819 min_net_proto_version = readU16(&data[2+1+PLAYERNAME_SIZE+PASSWORD_SIZE]);
1821 // Use same version as minimum and maximum if maximum version field
1822 // doesn't exist (backwards compatibility)
1823 u16 max_net_proto_version = min_net_proto_version;
1824 if(datasize >= 2+1+PLAYERNAME_SIZE+PASSWORD_SIZE+2+2)
1825 max_net_proto_version = readU16(&data[2+1+PLAYERNAME_SIZE+PASSWORD_SIZE+2]);
1827 // Start with client's maximum version
1828 u16 net_proto_version = max_net_proto_version;
1830 // Figure out a working version if it is possible at all
1831 if(max_net_proto_version >= SERVER_PROTOCOL_VERSION_MIN ||
1832 min_net_proto_version <= SERVER_PROTOCOL_VERSION_MAX)
1834 // If maximum is larger than our maximum, go with our maximum
1835 if(max_net_proto_version > SERVER_PROTOCOL_VERSION_MAX)
1836 net_proto_version = SERVER_PROTOCOL_VERSION_MAX;
1837 // Else go with client's maximum
1839 net_proto_version = max_net_proto_version;
1842 verbosestream<<"Server: "<<peer_id<<" Protocol version: min: "
1843 <<min_net_proto_version<<", max: "<<max_net_proto_version
1844 <<", chosen: "<<net_proto_version<<std::endl;
1846 getClient(peer_id)->net_proto_version = net_proto_version;
1848 if(net_proto_version < SERVER_PROTOCOL_VERSION_MIN ||
1849 net_proto_version > SERVER_PROTOCOL_VERSION_MAX)
1851 actionstream<<"Server: A mismatched client tried to connect from "<<addr_s
1853 SendAccessDenied(m_con, peer_id, std::wstring(
1854 L"Your client's version is not supported.\n"
1855 L"Server version is ")
1856 + narrow_to_wide(VERSION_STRING) + L",\n"
1857 + L"server's PROTOCOL_VERSION is "
1858 + narrow_to_wide(itos(SERVER_PROTOCOL_VERSION_MIN))
1860 + narrow_to_wide(itos(SERVER_PROTOCOL_VERSION_MAX))
1861 + L", client's PROTOCOL_VERSION is "
1862 + narrow_to_wide(itos(min_net_proto_version))
1864 + narrow_to_wide(itos(max_net_proto_version))
1869 if(g_settings->getBool("strict_protocol_version_checking"))
1871 if(net_proto_version != LATEST_PROTOCOL_VERSION)
1873 actionstream<<"Server: A mismatched (strict) client tried to "
1874 <<"connect from "<<addr_s<<std::endl;
1875 SendAccessDenied(m_con, peer_id, std::wstring(
1876 L"Your client's version is not supported.\n"
1877 L"Server version is ")
1878 + narrow_to_wide(VERSION_STRING) + L",\n"
1879 + L"server's PROTOCOL_VERSION (strict) is "
1880 + narrow_to_wide(itos(LATEST_PROTOCOL_VERSION))
1881 + L", client's PROTOCOL_VERSION is "
1882 + narrow_to_wide(itos(min_net_proto_version))
1884 + narrow_to_wide(itos(max_net_proto_version))
1895 char playername[PLAYERNAME_SIZE];
1896 for(u32 i=0; i<PLAYERNAME_SIZE-1; i++)
1898 playername[i] = data[3+i];
1900 playername[PLAYERNAME_SIZE-1] = 0;
1902 if(playername[0]=='\0')
1904 actionstream<<"Server: Player with an empty name "
1905 <<"tried to connect from "<<addr_s<<std::endl;
1906 SendAccessDenied(m_con, peer_id,
1911 if(string_allowed(playername, PLAYERNAME_ALLOWED_CHARS)==false)
1913 actionstream<<"Server: Player with an invalid name "
1914 <<"tried to connect from "<<addr_s<<std::endl;
1915 SendAccessDenied(m_con, peer_id,
1916 L"Name contains unallowed characters");
1920 infostream<<"Server: New connection: \""<<playername<<"\" from "
1921 <<m_con.GetPeerAddress(peer_id).serializeString()<<std::endl;
1924 char given_password[PASSWORD_SIZE];
1925 if(datasize < 2+1+PLAYERNAME_SIZE+PASSWORD_SIZE)
1927 // old version - assume blank password
1928 given_password[0] = 0;
1932 for(u32 i=0; i<PASSWORD_SIZE-1; i++)
1934 given_password[i] = data[23+i];
1936 given_password[PASSWORD_SIZE-1] = 0;
1939 if(!base64_is_valid(given_password)){
1940 infostream<<"Server: "<<playername
1941 <<" supplied invalid password hash"<<std::endl;
1942 SendAccessDenied(m_con, peer_id, L"Invalid password hash");
1946 std::string checkpwd; // Password hash to check against
1947 bool has_auth = scriptapi_get_auth(m_lua, playername, &checkpwd, NULL);
1949 // If no authentication info exists for user, create it
1951 if(!isSingleplayer() &&
1952 g_settings->getBool("disallow_empty_password") &&
1953 std::string(given_password) == ""){
1954 SendAccessDenied(m_con, peer_id, L"Empty passwords are "
1955 L"disallowed. Set a password and try again.");
1958 std::wstring raw_default_password =
1959 narrow_to_wide(g_settings->get("default_password"));
1960 std::string initial_password =
1961 translatePassword(playername, raw_default_password);
1963 // If default_password is empty, allow any initial password
1964 if (raw_default_password.length() == 0)
1965 initial_password = given_password;
1967 scriptapi_create_auth(m_lua, playername, initial_password);
1970 has_auth = scriptapi_get_auth(m_lua, playername, &checkpwd, NULL);
1973 SendAccessDenied(m_con, peer_id, L"Not allowed to login");
1977 if(given_password != checkpwd){
1978 infostream<<"Server: peer_id="<<peer_id
1979 <<": supplied invalid password for "
1980 <<playername<<std::endl;
1981 SendAccessDenied(m_con, peer_id, L"Invalid password");
1985 // Do not allow multiple players in simple singleplayer mode.
1986 // This isn't a perfect way to do it, but will suffice for now.
1987 if(m_simple_singleplayer_mode && m_clients.size() > 1){
1988 infostream<<"Server: Not allowing another client to connect in"
1989 <<" simple singleplayer mode"<<std::endl;
1990 SendAccessDenied(m_con, peer_id,
1991 L"Running in simple singleplayer mode.");
1995 // Enforce user limit.
1996 // Don't enforce for users that have some admin right
1997 if(m_clients.size() >= g_settings->getU16("max_users") &&
1998 !checkPriv(playername, "server") &&
1999 !checkPriv(playername, "ban") &&
2000 !checkPriv(playername, "privs") &&
2001 !checkPriv(playername, "password") &&
2002 playername != g_settings->get("name"))
2004 actionstream<<"Server: "<<playername<<" tried to join, but there"
2005 <<" are already max_users="
2006 <<g_settings->getU16("max_users")<<" players."<<std::endl;
2007 SendAccessDenied(m_con, peer_id, L"Too many users.");
2012 PlayerSAO *playersao = emergePlayer(playername, peer_id);
2014 // If failed, cancel
2015 if(playersao == NULL)
2017 errorstream<<"Server: peer_id="<<peer_id
2018 <<": failed to emerge player"<<std::endl;
2023 Answer with a TOCLIENT_INIT
2026 SharedBuffer<u8> reply(2+1+6+8+4);
2027 writeU16(&reply[0], TOCLIENT_INIT);
2028 writeU8(&reply[2], deployed);
2029 writeV3S16(&reply[2+1], floatToInt(playersao->getPlayer()->getPosition()+v3f(0,BS/2,0), BS));
2030 writeU64(&reply[2+1+6], m_env->getServerMap().getSeed());
2031 writeF1000(&reply[2+1+6+8], g_settings->getFloat("dedicated_server_step"));
2034 m_con.Send(peer_id, 0, reply, true);
2038 Send complete position information
2040 SendMovePlayer(peer_id);
2045 if(command == TOSERVER_INIT2)
2047 verbosestream<<"Server: Got TOSERVER_INIT2 from "
2048 <<peer_id<<std::endl;
2050 Player *player = m_env->getPlayer(peer_id);
2052 verbosestream<<"Server: TOSERVER_INIT2: "
2053 <<"Player not found; ignoring."<<std::endl;
2057 RemoteClient *client = getClient(peer_id);
2058 client->serialization_version =
2059 getClient(peer_id)->pending_serialization_version;
2062 Send some initialization data
2065 infostream<<"Server: Sending content to "
2066 <<getPlayerName(peer_id)<<std::endl;
2068 // Send player movement settings
2069 SendMovement(m_con, peer_id);
2071 // Send item definitions
2072 SendItemDef(m_con, peer_id, m_itemdef, client->net_proto_version);
2074 // Send node definitions
2075 SendNodeDef(m_con, peer_id, m_nodedef, client->net_proto_version);
2077 // Send media announcement
2078 sendMediaAnnouncement(peer_id);
2081 SendPlayerPrivileges(peer_id);
2083 // Send inventory formspec
2084 SendPlayerInventoryFormspec(peer_id);
2087 UpdateCrafting(peer_id);
2088 SendInventory(peer_id);
2091 if(g_settings->getBool("enable_damage"))
2092 SendPlayerHP(peer_id);
2094 // Send detached inventories
2095 sendDetachedInventories(peer_id);
2097 // Show death screen if necessary
2099 SendDeathscreen(m_con, peer_id, false, v3f(0,0,0));
2103 SharedBuffer<u8> data = makePacket_TOCLIENT_TIME_OF_DAY(
2104 m_env->getTimeOfDay(), g_settings->getFloat("time_speed"));
2105 m_con.Send(peer_id, 0, data, true);
2108 // Note things in chat if not in simple singleplayer mode
2109 if(!m_simple_singleplayer_mode)
2111 // Send information about server to player in chat
2112 SendChatMessage(peer_id, getStatusString());
2114 // Send information about joining in chat
2116 std::wstring name = L"unknown";
2117 Player *player = m_env->getPlayer(peer_id);
2119 name = narrow_to_wide(player->getName());
2121 std::wstring message;
2124 message += L" joined the game.";
2125 BroadcastChatMessage(message);
2129 // Warnings about protocol version can be issued here
2130 if(getClient(peer_id)->net_proto_version < LATEST_PROTOCOL_VERSION)
2132 SendChatMessage(peer_id, L"# Server: WARNING: YOUR CLIENT'S "
2133 L"VERSION MAY NOT BE FULLY COMPATIBLE WITH THIS SERVER!");
2140 std::ostringstream os(std::ios_base::binary);
2141 for(std::map<u16, RemoteClient*>::iterator
2142 i = m_clients.begin();
2143 i != m_clients.end(); ++i)
2145 RemoteClient *client = i->second;
2146 assert(client->peer_id == i->first);
2147 if(client->serialization_version == SER_FMT_VER_INVALID)
2150 Player *player = m_env->getPlayer(client->peer_id);
2153 // Get name of player
2154 os<<player->getName()<<" ";
2157 actionstream<<player->getName()<<" joins game. List of players: "
2158 <<os.str()<<std::endl;
2164 if(peer_ser_ver == SER_FMT_VER_INVALID)
2166 infostream<<"Server::ProcessData(): Cancelling: Peer"
2167 " serialization format invalid or not initialized."
2168 " Skipping incoming command="<<command<<std::endl;
2172 Player *player = m_env->getPlayer(peer_id);
2174 infostream<<"Server::ProcessData(): Cancelling: "
2175 "No player for peer_id="<<peer_id
2180 PlayerSAO *playersao = player->getPlayerSAO();
2181 if(playersao == NULL){
2182 infostream<<"Server::ProcessData(): Cancelling: "
2183 "No player object for peer_id="<<peer_id
2188 if(command == TOSERVER_PLAYERPOS)
2190 if(datasize < 2+12+12+4+4)
2194 v3s32 ps = readV3S32(&data[start+2]);
2195 v3s32 ss = readV3S32(&data[start+2+12]);
2196 f32 pitch = (f32)readS32(&data[2+12+12]) / 100.0;
2197 f32 yaw = (f32)readS32(&data[2+12+12+4]) / 100.0;
2199 if(datasize >= 2+12+12+4+4+4)
2200 keyPressed = (u32)readU32(&data[2+12+12+4+4]);
2201 v3f position((f32)ps.X/100., (f32)ps.Y/100., (f32)ps.Z/100.);
2202 v3f speed((f32)ss.X/100., (f32)ss.Y/100., (f32)ss.Z/100.);
2203 pitch = wrapDegrees(pitch);
2204 yaw = wrapDegrees(yaw);
2206 player->setPosition(position);
2207 player->setSpeed(speed);
2208 player->setPitch(pitch);
2209 player->setYaw(yaw);
2210 player->keyPressed=keyPressed;
2211 player->control.up = (bool)(keyPressed&1);
2212 player->control.down = (bool)(keyPressed&2);
2213 player->control.left = (bool)(keyPressed&4);
2214 player->control.right = (bool)(keyPressed&8);
2215 player->control.jump = (bool)(keyPressed&16);
2216 player->control.aux1 = (bool)(keyPressed&32);
2217 player->control.sneak = (bool)(keyPressed&64);
2218 player->control.LMB = (bool)(keyPressed&128);
2219 player->control.RMB = (bool)(keyPressed&256);
2221 /*infostream<<"Server::ProcessData(): Moved player "<<peer_id<<" to "
2222 <<"("<<position.X<<","<<position.Y<<","<<position.Z<<")"
2223 <<" pitch="<<pitch<<" yaw="<<yaw<<std::endl;*/
2225 else if(command == TOSERVER_GOTBLOCKS)
2238 u16 count = data[2];
2239 for(u16 i=0; i<count; i++)
2241 if((s16)datasize < 2+1+(i+1)*6)
2242 throw con::InvalidIncomingDataException
2243 ("GOTBLOCKS length is too short");
2244 v3s16 p = readV3S16(&data[2+1+i*6]);
2245 /*infostream<<"Server: GOTBLOCKS ("
2246 <<p.X<<","<<p.Y<<","<<p.Z<<")"<<std::endl;*/
2247 RemoteClient *client = getClient(peer_id);
2248 client->GotBlock(p);
2251 else if(command == TOSERVER_DELETEDBLOCKS)
2264 u16 count = data[2];
2265 for(u16 i=0; i<count; i++)
2267 if((s16)datasize < 2+1+(i+1)*6)
2268 throw con::InvalidIncomingDataException
2269 ("DELETEDBLOCKS length is too short");
2270 v3s16 p = readV3S16(&data[2+1+i*6]);
2271 /*infostream<<"Server: DELETEDBLOCKS ("
2272 <<p.X<<","<<p.Y<<","<<p.Z<<")"<<std::endl;*/
2273 RemoteClient *client = getClient(peer_id);
2274 client->SetBlockNotSent(p);
2277 else if(command == TOSERVER_CLICK_OBJECT)
2279 infostream<<"Server: CLICK_OBJECT not supported anymore"<<std::endl;
2282 else if(command == TOSERVER_CLICK_ACTIVEOBJECT)
2284 infostream<<"Server: CLICK_ACTIVEOBJECT not supported anymore"<<std::endl;
2287 else if(command == TOSERVER_GROUND_ACTION)
2289 infostream<<"Server: GROUND_ACTION not supported anymore"<<std::endl;
2293 else if(command == TOSERVER_RELEASE)
2295 infostream<<"Server: RELEASE not supported anymore"<<std::endl;
2298 else if(command == TOSERVER_SIGNTEXT)
2300 infostream<<"Server: SIGNTEXT not supported anymore"
2304 else if(command == TOSERVER_SIGNNODETEXT)
2306 infostream<<"Server: SIGNNODETEXT not supported anymore"
2310 else if(command == TOSERVER_INVENTORY_ACTION)
2312 // Strip command and create a stream
2313 std::string datastring((char*)&data[2], datasize-2);
2314 verbosestream<<"TOSERVER_INVENTORY_ACTION: data="<<datastring<<std::endl;
2315 std::istringstream is(datastring, std::ios_base::binary);
2317 InventoryAction *a = InventoryAction::deSerialize(is);
2320 infostream<<"TOSERVER_INVENTORY_ACTION: "
2321 <<"InventoryAction::deSerialize() returned NULL"
2326 // If something goes wrong, this player is to blame
2327 RollbackScopeActor rollback_scope(m_rollback,
2328 std::string("player:")+player->getName());
2331 Note: Always set inventory not sent, to repair cases
2332 where the client made a bad prediction.
2336 Handle restrictions and special cases of the move action
2338 if(a->getType() == IACTION_MOVE)
2340 IMoveAction *ma = (IMoveAction*)a;
2342 ma->from_inv.applyCurrentPlayer(player->getName());
2343 ma->to_inv.applyCurrentPlayer(player->getName());
2345 setInventoryModified(ma->from_inv);
2346 setInventoryModified(ma->to_inv);
2348 bool from_inv_is_current_player =
2349 (ma->from_inv.type == InventoryLocation::PLAYER) &&
2350 (ma->from_inv.name == player->getName());
2352 bool to_inv_is_current_player =
2353 (ma->to_inv.type == InventoryLocation::PLAYER) &&
2354 (ma->to_inv.name == player->getName());
2357 Disable moving items out of craftpreview
2359 if(ma->from_list == "craftpreview")
2361 infostream<<"Ignoring IMoveAction from "
2362 <<(ma->from_inv.dump())<<":"<<ma->from_list
2363 <<" to "<<(ma->to_inv.dump())<<":"<<ma->to_list
2364 <<" because src is "<<ma->from_list<<std::endl;
2370 Disable moving items into craftresult and craftpreview
2372 if(ma->to_list == "craftpreview" || ma->to_list == "craftresult")
2374 infostream<<"Ignoring IMoveAction from "
2375 <<(ma->from_inv.dump())<<":"<<ma->from_list
2376 <<" to "<<(ma->to_inv.dump())<<":"<<ma->to_list
2377 <<" because dst is "<<ma->to_list<<std::endl;
2382 // Disallow moving items in elsewhere than player's inventory
2383 // if not allowed to interact
2384 if(!checkPriv(player->getName(), "interact") &&
2385 (!from_inv_is_current_player ||
2386 !to_inv_is_current_player))
2388 infostream<<"Cannot move outside of player's inventory: "
2389 <<"No interact privilege"<<std::endl;
2395 Handle restrictions and special cases of the drop action
2397 else if(a->getType() == IACTION_DROP)
2399 IDropAction *da = (IDropAction*)a;
2401 da->from_inv.applyCurrentPlayer(player->getName());
2403 setInventoryModified(da->from_inv);
2405 // Disallow dropping items if not allowed to interact
2406 if(!checkPriv(player->getName(), "interact"))
2413 Handle restrictions and special cases of the craft action
2415 else if(a->getType() == IACTION_CRAFT)
2417 ICraftAction *ca = (ICraftAction*)a;
2419 ca->craft_inv.applyCurrentPlayer(player->getName());
2421 setInventoryModified(ca->craft_inv);
2423 //bool craft_inv_is_current_player =
2424 // (ca->craft_inv.type == InventoryLocation::PLAYER) &&
2425 // (ca->craft_inv.name == player->getName());
2427 // Disallow crafting if not allowed to interact
2428 if(!checkPriv(player->getName(), "interact"))
2430 infostream<<"Cannot craft: "
2431 <<"No interact privilege"<<std::endl;
2438 a->apply(this, playersao, this);
2442 else if(command == TOSERVER_CHAT_MESSAGE)
2450 std::string datastring((char*)&data[2], datasize-2);
2451 std::istringstream is(datastring, std::ios_base::binary);
2454 is.read((char*)buf, 2);
2455 u16 len = readU16(buf);
2457 std::wstring message;
2458 for(u16 i=0; i<len; i++)
2460 is.read((char*)buf, 2);
2461 message += (wchar_t)readU16(buf);
2464 // If something goes wrong, this player is to blame
2465 RollbackScopeActor rollback_scope(m_rollback,
2466 std::string("player:")+player->getName());
2468 // Get player name of this client
2469 std::wstring name = narrow_to_wide(player->getName());
2472 bool ate = scriptapi_on_chat_message(m_lua, player->getName(),
2473 wide_to_narrow(message));
2474 // If script ate the message, don't proceed
2478 // Line to send to players
2480 // Whether to send to the player that sent the line
2481 bool send_to_sender = false;
2482 // Whether to send to other players
2483 bool send_to_others = false;
2485 // Commands are implemented in Lua, so only catch invalid
2486 // commands that were not "eaten" and send an error back
2487 if(message[0] == L'/')
2489 message = message.substr(1);
2490 send_to_sender = true;
2491 if(message.length() == 0)
2492 line += L"-!- Empty command";
2494 line += L"-!- Invalid command: " + str_split(message, L' ')[0];
2498 if(checkPriv(player->getName(), "shout")){
2503 send_to_others = true;
2505 line += L"-!- You don't have permission to shout.";
2506 send_to_sender = true;
2513 actionstream<<"CHAT: "<<wide_to_narrow(line)<<std::endl;
2516 Send the message to clients
2518 for(std::map<u16, RemoteClient*>::iterator
2519 i = m_clients.begin();
2520 i != m_clients.end(); ++i)
2522 // Get client and check that it is valid
2523 RemoteClient *client = i->second;
2524 assert(client->peer_id == i->first);
2525 if(client->serialization_version == SER_FMT_VER_INVALID)
2529 bool sender_selected = (peer_id == client->peer_id);
2530 if(sender_selected == true && send_to_sender == false)
2532 if(sender_selected == false && send_to_others == false)
2535 SendChatMessage(client->peer_id, line);
2539 else if(command == TOSERVER_DAMAGE)
2541 std::string datastring((char*)&data[2], datasize-2);
2542 std::istringstream is(datastring, std::ios_base::binary);
2543 u8 damage = readU8(is);
2545 if(g_settings->getBool("enable_damage"))
2547 actionstream<<player->getName()<<" damaged by "
2548 <<(int)damage<<" hp at "<<PP(player->getPosition()/BS)
2551 playersao->setHP(playersao->getHP() - damage);
2553 if(playersao->getHP() == 0 && playersao->m_hp_not_sent)
2556 if(playersao->m_hp_not_sent)
2557 SendPlayerHP(peer_id);
2560 else if(command == TOSERVER_PASSWORD)
2563 [0] u16 TOSERVER_PASSWORD
2564 [2] u8[28] old password
2565 [30] u8[28] new password
2568 if(datasize != 2+PASSWORD_SIZE*2)
2570 /*char password[PASSWORD_SIZE];
2571 for(u32 i=0; i<PASSWORD_SIZE-1; i++)
2572 password[i] = data[2+i];
2573 password[PASSWORD_SIZE-1] = 0;*/
2575 for(u32 i=0; i<PASSWORD_SIZE-1; i++)
2583 for(u32 i=0; i<PASSWORD_SIZE-1; i++)
2585 char c = data[2+PASSWORD_SIZE+i];
2591 if(!base64_is_valid(newpwd)){
2592 infostream<<"Server: "<<player->getName()<<" supplied invalid password hash"<<std::endl;
2593 // Wrong old password supplied!!
2594 SendChatMessage(peer_id, L"Invalid new password hash supplied. Password NOT changed.");
2598 infostream<<"Server: Client requests a password change from "
2599 <<"'"<<oldpwd<<"' to '"<<newpwd<<"'"<<std::endl;
2601 std::string playername = player->getName();
2603 std::string checkpwd;
2604 scriptapi_get_auth(m_lua, playername, &checkpwd, NULL);
2606 if(oldpwd != checkpwd)
2608 infostream<<"Server: invalid old password"<<std::endl;
2609 // Wrong old password supplied!!
2610 SendChatMessage(peer_id, L"Invalid old password supplied. Password NOT changed.");
2614 bool success = scriptapi_set_password(m_lua, playername, newpwd);
2616 actionstream<<player->getName()<<" changes password"<<std::endl;
2617 SendChatMessage(peer_id, L"Password change successful.");
2619 actionstream<<player->getName()<<" tries to change password but "
2620 <<"it fails"<<std::endl;
2621 SendChatMessage(peer_id, L"Password change failed or inavailable.");
2624 else if(command == TOSERVER_PLAYERITEM)
2629 u16 item = readU16(&data[2]);
2630 playersao->setWieldIndex(item);
2632 else if(command == TOSERVER_RESPAWN)
2634 if(player->hp != 0 || !g_settings->getBool("enable_damage"))
2637 RespawnPlayer(peer_id);
2639 actionstream<<player->getName()<<" respawns at "
2640 <<PP(player->getPosition()/BS)<<std::endl;
2642 // ActiveObject is added to environment in AsyncRunStep after
2643 // the previous addition has been succesfully removed
2645 else if(command == TOSERVER_REQUEST_MEDIA) {
2646 std::string datastring((char*)&data[2], datasize-2);
2647 std::istringstream is(datastring, std::ios_base::binary);
2649 std::list<MediaRequest> tosend;
2650 u16 numfiles = readU16(is);
2652 infostream<<"Sending "<<numfiles<<" files to "
2653 <<getPlayerName(peer_id)<<std::endl;
2654 verbosestream<<"TOSERVER_REQUEST_MEDIA: "<<std::endl;
2656 for(int i = 0; i < numfiles; i++) {
2657 std::string name = deSerializeString(is);
2658 tosend.push_back(MediaRequest(name));
2659 verbosestream<<"TOSERVER_REQUEST_MEDIA: requested file "
2663 sendRequestedMedia(peer_id, tosend);
2665 // Now the client should know about everything
2666 // (definitions and files)
2667 getClient(peer_id)->definitions_sent = true;
2669 else if(command == TOSERVER_RECEIVED_MEDIA) {
2670 getClient(peer_id)->definitions_sent = true;
2672 else if(command == TOSERVER_INTERACT)
2674 std::string datastring((char*)&data[2], datasize-2);
2675 std::istringstream is(datastring, std::ios_base::binary);
2681 [5] u32 length of the next item
2682 [9] serialized PointedThing
2684 0: start digging (from undersurface) or use
2685 1: stop digging (all parameters ignored)
2686 2: digging completed
2687 3: place block or item (to abovesurface)
2690 u8 action = readU8(is);
2691 u16 item_i = readU16(is);
2692 std::istringstream tmp_is(deSerializeLongString(is), std::ios::binary);
2693 PointedThing pointed;
2694 pointed.deSerialize(tmp_is);
2696 verbosestream<<"TOSERVER_INTERACT: action="<<(int)action<<", item="
2697 <<item_i<<", pointed="<<pointed.dump()<<std::endl;
2701 verbosestream<<"TOSERVER_INTERACT: "<<player->getName()
2702 <<" tried to interact, but is dead!"<<std::endl;
2706 v3f player_pos = playersao->getLastGoodPosition();
2708 // Update wielded item
2709 playersao->setWieldIndex(item_i);
2711 // Get pointed to node (undefined if not POINTEDTYPE_NODE)
2712 v3s16 p_under = pointed.node_undersurface;
2713 v3s16 p_above = pointed.node_abovesurface;
2715 // Get pointed to object (NULL if not POINTEDTYPE_OBJECT)
2716 ServerActiveObject *pointed_object = NULL;
2717 if(pointed.type == POINTEDTHING_OBJECT)
2719 pointed_object = m_env->getActiveObject(pointed.object_id);
2720 if(pointed_object == NULL)
2722 verbosestream<<"TOSERVER_INTERACT: "
2723 "pointed object is NULL"<<std::endl;
2729 v3f pointed_pos_under = player_pos;
2730 v3f pointed_pos_above = player_pos;
2731 if(pointed.type == POINTEDTHING_NODE)
2733 pointed_pos_under = intToFloat(p_under, BS);
2734 pointed_pos_above = intToFloat(p_above, BS);
2736 else if(pointed.type == POINTEDTHING_OBJECT)
2738 pointed_pos_under = pointed_object->getBasePosition();
2739 pointed_pos_above = pointed_pos_under;
2743 Check that target is reasonably close
2744 (only when digging or placing things)
2746 if(action == 0 || action == 2 || action == 3)
2748 float d = player_pos.getDistanceFrom(pointed_pos_under);
2749 float max_d = BS * 14; // Just some large enough value
2751 actionstream<<"Player "<<player->getName()
2752 <<" tried to access "<<pointed.dump()
2754 <<"d="<<d<<", max_d="<<max_d
2755 <<". ignoring."<<std::endl;
2756 // Re-send block to revert change on client-side
2757 RemoteClient *client = getClient(peer_id);
2758 v3s16 blockpos = getNodeBlockPos(floatToInt(pointed_pos_under, BS));
2759 client->SetBlockNotSent(blockpos);
2766 Make sure the player is allowed to do it
2768 if(!checkPriv(player->getName(), "interact"))
2770 actionstream<<player->getName()<<" attempted to interact with "
2771 <<pointed.dump()<<" without 'interact' privilege"
2773 // Re-send block to revert change on client-side
2774 RemoteClient *client = getClient(peer_id);
2775 // Digging completed -> under
2777 v3s16 blockpos = getNodeBlockPos(floatToInt(pointed_pos_under, BS));
2778 client->SetBlockNotSent(blockpos);
2780 // Placement -> above
2782 v3s16 blockpos = getNodeBlockPos(floatToInt(pointed_pos_above, BS));
2783 client->SetBlockNotSent(blockpos);
2789 If something goes wrong, this player is to blame
2791 RollbackScopeActor rollback_scope(m_rollback,
2792 std::string("player:")+player->getName());
2795 0: start digging or punch object
2799 if(pointed.type == POINTEDTHING_NODE)
2802 NOTE: This can be used in the future to check if
2803 somebody is cheating, by checking the timing.
2805 MapNode n(CONTENT_IGNORE);
2808 n = m_env->getMap().getNode(p_under);
2810 catch(InvalidPositionException &e)
2812 infostream<<"Server: Not punching: Node not found."
2813 <<" Adding block to emerge queue."
2815 m_emerge->enqueueBlockEmerge(peer_id, getNodeBlockPos(p_above), false);
2817 if(n.getContent() != CONTENT_IGNORE)
2818 scriptapi_node_on_punch(m_lua, p_under, n, playersao);
2820 playersao->noCheatDigStart(p_under);
2822 else if(pointed.type == POINTEDTHING_OBJECT)
2824 // Skip if object has been removed
2825 if(pointed_object->m_removed)
2828 actionstream<<player->getName()<<" punches object "
2829 <<pointed.object_id<<": "
2830 <<pointed_object->getDescription()<<std::endl;
2832 ItemStack punchitem = playersao->getWieldedItem();
2833 ToolCapabilities toolcap =
2834 punchitem.getToolCapabilities(m_itemdef);
2835 v3f dir = (pointed_object->getBasePosition() -
2836 (player->getPosition() + player->getEyeOffset())
2838 float time_from_last_punch =
2839 playersao->resetTimeFromLastPunch();
2840 pointed_object->punch(dir, &toolcap, playersao,
2841 time_from_last_punch);
2849 else if(action == 1)
2854 2: Digging completed
2856 else if(action == 2)
2858 // Only digging of nodes
2859 if(pointed.type == POINTEDTHING_NODE)
2861 MapNode n(CONTENT_IGNORE);
2864 n = m_env->getMap().getNode(p_under);
2866 catch(InvalidPositionException &e)
2868 infostream<<"Server: Not finishing digging: Node not found."
2869 <<" Adding block to emerge queue."
2871 m_emerge->enqueueBlockEmerge(peer_id, getNodeBlockPos(p_above), false);
2874 /* Cheat prevention */
2875 bool is_valid_dig = true;
2876 if(!isSingleplayer() && !g_settings->getBool("disable_anticheat"))
2878 v3s16 nocheat_p = playersao->getNoCheatDigPos();
2879 float nocheat_t = playersao->getNoCheatDigTime();
2880 playersao->noCheatDigEnd();
2881 // If player didn't start digging this, ignore dig
2882 if(nocheat_p != p_under){
2883 infostream<<"Server: NoCheat: "<<player->getName()
2884 <<" started digging "
2885 <<PP(nocheat_p)<<" and completed digging "
2886 <<PP(p_under)<<"; not digging."<<std::endl;
2887 is_valid_dig = false;
2889 // Get player's wielded item
2890 ItemStack playeritem;
2891 InventoryList *mlist = playersao->getInventory()->getList("main");
2893 playeritem = mlist->getItem(playersao->getWieldIndex());
2894 ToolCapabilities playeritem_toolcap =
2895 playeritem.getToolCapabilities(m_itemdef);
2896 // Get diggability and expected digging time
2897 DigParams params = getDigParams(m_nodedef->get(n).groups,
2898 &playeritem_toolcap);
2899 // If can't dig, try hand
2900 if(!params.diggable){
2901 const ItemDefinition &hand = m_itemdef->get("");
2902 const ToolCapabilities *tp = hand.tool_capabilities;
2904 params = getDigParams(m_nodedef->get(n).groups, tp);
2906 // If can't dig, ignore dig
2907 if(!params.diggable){
2908 infostream<<"Server: NoCheat: "<<player->getName()
2909 <<" completed digging "<<PP(p_under)
2910 <<", which is not diggable with tool. not digging."
2912 is_valid_dig = false;
2914 // If time is considerably too short, ignore dig
2915 // Check time only for medium and slow timed digs
2916 if(params.diggable && params.time > 0.3 && nocheat_t < 0.5 * params.time){
2917 infostream<<"Server: NoCheat: "<<player->getName()
2918 <<" completed digging "
2919 <<PP(p_under)<<" in "<<nocheat_t<<"s; expected "
2920 <<params.time<<"s; not digging."<<std::endl;
2921 is_valid_dig = false;
2925 /* Actually dig node */
2927 if(is_valid_dig && n.getContent() != CONTENT_IGNORE)
2928 scriptapi_node_on_dig(m_lua, p_under, n, playersao);
2930 // Send unusual result (that is, node not being removed)
2931 if(m_env->getMap().getNodeNoEx(p_under).getContent() != CONTENT_AIR)
2933 // Re-send block to revert change on client-side
2934 RemoteClient *client = getClient(peer_id);
2935 v3s16 blockpos = getNodeBlockPos(floatToInt(pointed_pos_under, BS));
2936 client->SetBlockNotSent(blockpos);
2942 3: place block or right-click object
2944 else if(action == 3)
2946 ItemStack item = playersao->getWieldedItem();
2948 // Reset build time counter
2949 if(pointed.type == POINTEDTHING_NODE &&
2950 item.getDefinition(m_itemdef).type == ITEM_NODE)
2951 getClient(peer_id)->m_time_from_building = 0.0;
2953 if(pointed.type == POINTEDTHING_OBJECT)
2955 // Right click object
2957 // Skip if object has been removed
2958 if(pointed_object->m_removed)
2961 actionstream<<player->getName()<<" right-clicks object "
2962 <<pointed.object_id<<": "
2963 <<pointed_object->getDescription()<<std::endl;
2966 pointed_object->rightClick(playersao);
2968 else if(scriptapi_item_on_place(m_lua,
2969 item, playersao, pointed))
2971 // Placement was handled in lua
2973 // Apply returned ItemStack
2974 playersao->setWieldedItem(item);
2977 // If item has node placement prediction, always send the
2978 // blocks to make sure the client knows what exactly happened
2979 if(item.getDefinition(m_itemdef).node_placement_prediction != ""){
2980 RemoteClient *client = getClient(peer_id);
2981 v3s16 blockpos = getNodeBlockPos(floatToInt(pointed_pos_above, BS));
2982 client->SetBlockNotSent(blockpos);
2983 v3s16 blockpos2 = getNodeBlockPos(floatToInt(pointed_pos_under, BS));
2984 if(blockpos2 != blockpos){
2985 client->SetBlockNotSent(blockpos2);
2993 else if(action == 4)
2995 ItemStack item = playersao->getWieldedItem();
2997 actionstream<<player->getName()<<" uses "<<item.name
2998 <<", pointing at "<<pointed.dump()<<std::endl;
3000 if(scriptapi_item_on_use(m_lua,
3001 item, playersao, pointed))
3003 // Apply returned ItemStack
3004 playersao->setWieldedItem(item);
3011 Catch invalid actions
3015 infostream<<"WARNING: Server: Invalid action "
3016 <<action<<std::endl;
3019 else if(command == TOSERVER_REMOVED_SOUNDS)
3021 std::string datastring((char*)&data[2], datasize-2);
3022 std::istringstream is(datastring, std::ios_base::binary);
3024 int num = readU16(is);
3025 for(int k=0; k<num; k++){
3026 s32 id = readS32(is);
3027 std::map<s32, ServerPlayingSound>::iterator i =
3028 m_playing_sounds.find(id);
3029 if(i == m_playing_sounds.end())
3031 ServerPlayingSound &psound = i->second;
3032 psound.clients.erase(peer_id);
3033 if(psound.clients.size() == 0)
3034 m_playing_sounds.erase(i++);
3037 else if(command == TOSERVER_NODEMETA_FIELDS)
3039 std::string datastring((char*)&data[2], datasize-2);
3040 std::istringstream is(datastring, std::ios_base::binary);
3042 v3s16 p = readV3S16(is);
3043 std::string formname = deSerializeString(is);
3044 int num = readU16(is);
3045 std::map<std::string, std::string> fields;
3046 for(int k=0; k<num; k++){
3047 std::string fieldname = deSerializeString(is);
3048 std::string fieldvalue = deSerializeLongString(is);
3049 fields[fieldname] = fieldvalue;
3052 // If something goes wrong, this player is to blame
3053 RollbackScopeActor rollback_scope(m_rollback,
3054 std::string("player:")+player->getName());
3056 // Check the target node for rollback data; leave others unnoticed
3057 RollbackNode rn_old(&m_env->getMap(), p, this);
3059 scriptapi_node_on_receive_fields(m_lua, p, formname, fields,
3062 // Report rollback data
3063 RollbackNode rn_new(&m_env->getMap(), p, this);
3064 if(rollback() && rn_new != rn_old){
3065 RollbackAction action;
3066 action.setSetNode(p, rn_old, rn_new);
3067 rollback()->reportAction(action);
3070 else if(command == TOSERVER_INVENTORY_FIELDS)
3072 std::string datastring((char*)&data[2], datasize-2);
3073 std::istringstream is(datastring, std::ios_base::binary);
3075 std::string formname = deSerializeString(is);
3076 int num = readU16(is);
3077 std::map<std::string, std::string> fields;
3078 for(int k=0; k<num; k++){
3079 std::string fieldname = deSerializeString(is);
3080 std::string fieldvalue = deSerializeLongString(is);
3081 fields[fieldname] = fieldvalue;
3084 scriptapi_on_player_receive_fields(m_lua, playersao, formname, fields);
3088 infostream<<"Server::ProcessData(): Ignoring "
3089 "unknown command "<<command<<std::endl;
3093 catch(SendFailedException &e)
3095 errorstream<<"Server::ProcessData(): SendFailedException: "
3101 void Server::onMapEditEvent(MapEditEvent *event)
3103 //infostream<<"Server::onMapEditEvent()"<<std::endl;
3104 if(m_ignore_map_edit_events)
3106 if(m_ignore_map_edit_events_area.contains(event->getArea()))
3108 MapEditEvent *e = event->clone();
3109 m_unsent_map_edit_queue.push_back(e);
3112 Inventory* Server::getInventory(const InventoryLocation &loc)
3115 case InventoryLocation::UNDEFINED:
3118 case InventoryLocation::CURRENT_PLAYER:
3121 case InventoryLocation::PLAYER:
3123 Player *player = m_env->getPlayer(loc.name.c_str());
3126 PlayerSAO *playersao = player->getPlayerSAO();
3129 return playersao->getInventory();
3132 case InventoryLocation::NODEMETA:
3134 NodeMetadata *meta = m_env->getMap().getNodeMetadata(loc.p);
3137 return meta->getInventory();
3140 case InventoryLocation::DETACHED:
3142 if(m_detached_inventories.count(loc.name) == 0)
3144 return m_detached_inventories[loc.name];
3152 void Server::setInventoryModified(const InventoryLocation &loc)
3155 case InventoryLocation::UNDEFINED:
3158 case InventoryLocation::PLAYER:
3160 Player *player = m_env->getPlayer(loc.name.c_str());
3163 PlayerSAO *playersao = player->getPlayerSAO();
3166 playersao->m_inventory_not_sent = true;
3167 playersao->m_wielded_item_not_sent = true;
3170 case InventoryLocation::NODEMETA:
3172 v3s16 blockpos = getNodeBlockPos(loc.p);
3174 MapBlock *block = m_env->getMap().getBlockNoCreateNoEx(blockpos);
3176 block->raiseModified(MOD_STATE_WRITE_NEEDED);
3178 setBlockNotSent(blockpos);
3181 case InventoryLocation::DETACHED:
3183 sendDetachedInventoryToAll(loc.name);
3191 std::list<PlayerInfo> Server::getPlayerInfo()
3193 DSTACK(__FUNCTION_NAME);
3194 JMutexAutoLock envlock(m_env_mutex);
3195 JMutexAutoLock conlock(m_con_mutex);
3197 std::list<PlayerInfo> list;
3199 std::list<Player*> players = m_env->getPlayers();
3201 std::list<Player*>::iterator i;
3202 for(i = players.begin();
3203 i != players.end(); ++i)
3207 Player *player = *i;
3210 // Copy info from connection to info struct
3211 info.id = player->peer_id;
3212 info.address = m_con.GetPeerAddress(player->peer_id);
3213 info.avg_rtt = m_con.GetPeerAvgRTT(player->peer_id);
3215 catch(con::PeerNotFoundException &e)
3217 // Set dummy peer info
3219 info.address = Address(0,0,0,0,0);
3223 snprintf(info.name, PLAYERNAME_SIZE, "%s", player->getName());
3224 info.position = player->getPosition();
3226 list.push_back(info);
3233 void Server::peerAdded(con::Peer *peer)
3235 DSTACK(__FUNCTION_NAME);
3236 verbosestream<<"Server::peerAdded(): peer->id="
3237 <<peer->id<<std::endl;
3240 c.type = PEER_ADDED;
3241 c.peer_id = peer->id;
3243 m_peer_change_queue.push_back(c);
3246 void Server::deletingPeer(con::Peer *peer, bool timeout)
3248 DSTACK(__FUNCTION_NAME);
3249 verbosestream<<"Server::deletingPeer(): peer->id="
3250 <<peer->id<<", timeout="<<timeout<<std::endl;
3253 c.type = PEER_REMOVED;
3254 c.peer_id = peer->id;
3255 c.timeout = timeout;
3256 m_peer_change_queue.push_back(c);
3263 void Server::SendMovement(con::Connection &con, u16 peer_id)
3265 DSTACK(__FUNCTION_NAME);
3266 std::ostringstream os(std::ios_base::binary);
3268 writeU16(os, TOCLIENT_MOVEMENT);
3269 writeF1000(os, g_settings->getFloat("movement_acceleration_default"));
3270 writeF1000(os, g_settings->getFloat("movement_acceleration_air"));
3271 writeF1000(os, g_settings->getFloat("movement_acceleration_fast"));
3272 writeF1000(os, g_settings->getFloat("movement_speed_walk"));
3273 writeF1000(os, g_settings->getFloat("movement_speed_crouch"));
3274 writeF1000(os, g_settings->getFloat("movement_speed_fast"));
3275 writeF1000(os, g_settings->getFloat("movement_speed_climb"));
3276 writeF1000(os, g_settings->getFloat("movement_speed_jump"));
3277 writeF1000(os, g_settings->getFloat("movement_liquid_fluidity"));
3278 writeF1000(os, g_settings->getFloat("movement_liquid_fluidity_smooth"));
3279 writeF1000(os, g_settings->getFloat("movement_liquid_sink"));
3280 writeF1000(os, g_settings->getFloat("movement_gravity"));
3283 std::string s = os.str();
3284 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3286 con.Send(peer_id, 0, data, true);
3289 void Server::SendHP(con::Connection &con, u16 peer_id, u8 hp)
3291 DSTACK(__FUNCTION_NAME);
3292 std::ostringstream os(std::ios_base::binary);
3294 writeU16(os, TOCLIENT_HP);
3298 std::string s = os.str();
3299 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3301 con.Send(peer_id, 0, data, true);
3304 void Server::SendAccessDenied(con::Connection &con, u16 peer_id,
3305 const std::wstring &reason)
3307 DSTACK(__FUNCTION_NAME);
3308 std::ostringstream os(std::ios_base::binary);
3310 writeU16(os, TOCLIENT_ACCESS_DENIED);
3311 os<<serializeWideString(reason);
3314 std::string s = os.str();
3315 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3317 con.Send(peer_id, 0, data, true);
3320 void Server::SendDeathscreen(con::Connection &con, u16 peer_id,
3321 bool set_camera_point_target, v3f camera_point_target)
3323 DSTACK(__FUNCTION_NAME);
3324 std::ostringstream os(std::ios_base::binary);
3326 writeU16(os, TOCLIENT_DEATHSCREEN);
3327 writeU8(os, set_camera_point_target);
3328 writeV3F1000(os, camera_point_target);
3331 std::string s = os.str();
3332 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3334 con.Send(peer_id, 0, data, true);
3337 void Server::SendItemDef(con::Connection &con, u16 peer_id,
3338 IItemDefManager *itemdef, u16 protocol_version)
3340 DSTACK(__FUNCTION_NAME);
3341 std::ostringstream os(std::ios_base::binary);
3345 u32 length of the next item
3346 zlib-compressed serialized ItemDefManager
3348 writeU16(os, TOCLIENT_ITEMDEF);
3349 std::ostringstream tmp_os(std::ios::binary);
3350 itemdef->serialize(tmp_os, protocol_version);
3351 std::ostringstream tmp_os2(std::ios::binary);
3352 compressZlib(tmp_os.str(), tmp_os2);
3353 os<<serializeLongString(tmp_os2.str());
3356 std::string s = os.str();
3357 verbosestream<<"Server: Sending item definitions to id("<<peer_id
3358 <<"): size="<<s.size()<<std::endl;
3359 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3361 con.Send(peer_id, 0, data, true);
3364 void Server::SendNodeDef(con::Connection &con, u16 peer_id,
3365 INodeDefManager *nodedef, u16 protocol_version)
3367 DSTACK(__FUNCTION_NAME);
3368 std::ostringstream os(std::ios_base::binary);
3372 u32 length of the next item
3373 zlib-compressed serialized NodeDefManager
3375 writeU16(os, TOCLIENT_NODEDEF);
3376 std::ostringstream tmp_os(std::ios::binary);
3377 nodedef->serialize(tmp_os, protocol_version);
3378 std::ostringstream tmp_os2(std::ios::binary);
3379 compressZlib(tmp_os.str(), tmp_os2);
3380 os<<serializeLongString(tmp_os2.str());
3383 std::string s = os.str();
3384 verbosestream<<"Server: Sending node definitions to id("<<peer_id
3385 <<"): size="<<s.size()<<std::endl;
3386 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3388 con.Send(peer_id, 0, data, true);
3392 Non-static send methods
3395 void Server::SendInventory(u16 peer_id)
3397 DSTACK(__FUNCTION_NAME);
3399 PlayerSAO *playersao = getPlayerSAO(peer_id);
3402 playersao->m_inventory_not_sent = false;
3408 std::ostringstream os;
3409 playersao->getInventory()->serialize(os);
3411 std::string s = os.str();
3413 SharedBuffer<u8> data(s.size()+2);
3414 writeU16(&data[0], TOCLIENT_INVENTORY);
3415 memcpy(&data[2], s.c_str(), s.size());
3418 m_con.Send(peer_id, 0, data, true);
3421 void Server::SendChatMessage(u16 peer_id, const std::wstring &message)
3423 DSTACK(__FUNCTION_NAME);
3425 std::ostringstream os(std::ios_base::binary);
3429 writeU16(buf, TOCLIENT_CHAT_MESSAGE);
3430 os.write((char*)buf, 2);
3433 writeU16(buf, message.size());
3434 os.write((char*)buf, 2);
3437 for(u32 i=0; i<message.size(); i++)
3441 os.write((char*)buf, 2);
3445 std::string s = os.str();
3446 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3448 m_con.Send(peer_id, 0, data, true);
3451 void Server::SendShowFormspecMessage(u16 peer_id, const std::string formspec,
3452 const std::string formname)
3454 DSTACK(__FUNCTION_NAME);
3456 std::ostringstream os(std::ios_base::binary);
3460 writeU16(buf, TOCLIENT_SHOW_FORMSPEC);
3461 os.write((char*)buf, 2);
3462 os<<serializeLongString(formspec);
3463 os<<serializeString(formname);
3466 std::string s = os.str();
3467 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3469 m_con.Send(peer_id, 0, data, true);
3472 // Spawns a particle on peer with peer_id
3473 void Server::SendSpawnParticle(u16 peer_id, v3f pos, v3f velocity, v3f acceleration,
3474 float expirationtime, float size, bool collisiondetection,
3475 std::string texture)
3477 DSTACK(__FUNCTION_NAME);
3479 std::ostringstream os(std::ios_base::binary);
3480 writeU16(os, TOCLIENT_SPAWN_PARTICLE);
3481 writeV3F1000(os, pos);
3482 writeV3F1000(os, velocity);
3483 writeV3F1000(os, acceleration);
3484 writeF1000(os, expirationtime);
3485 writeF1000(os, size);
3486 writeU8(os, collisiondetection);
3487 os<<serializeLongString(texture);
3490 std::string s = os.str();
3491 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3493 m_con.Send(peer_id, 0, data, true);
3496 // Spawns a particle on all peers
3497 void Server::SendSpawnParticleAll(v3f pos, v3f velocity, v3f acceleration,
3498 float expirationtime, float size, bool collisiondetection,
3499 std::string texture)
3501 for(std::map<u16, RemoteClient*>::iterator
3502 i = m_clients.begin();
3503 i != m_clients.end(); i++)
3505 // Get client and check that it is valid
3506 RemoteClient *client = i->second;
3507 assert(client->peer_id == i->first);
3508 if(client->serialization_version == SER_FMT_VER_INVALID)
3511 SendSpawnParticle(client->peer_id, pos, velocity, acceleration,
3512 expirationtime, size, collisiondetection, texture);
3516 // Adds a ParticleSpawner on peer with peer_id
3517 void Server::SendAddParticleSpawner(u16 peer_id, u16 amount, float spawntime, v3f minpos, v3f maxpos,
3518 v3f minvel, v3f maxvel, v3f minacc, v3f maxacc, float minexptime, float maxexptime,
3519 float minsize, float maxsize, bool collisiondetection, std::string texture, u32 id)
3521 DSTACK(__FUNCTION_NAME);
3523 std::ostringstream os(std::ios_base::binary);
3524 writeU16(os, TOCLIENT_ADD_PARTICLESPAWNER);
3526 writeU16(os, amount);
3527 writeF1000(os, spawntime);
3528 writeV3F1000(os, minpos);
3529 writeV3F1000(os, maxpos);
3530 writeV3F1000(os, minvel);
3531 writeV3F1000(os, maxvel);
3532 writeV3F1000(os, minacc);
3533 writeV3F1000(os, maxacc);
3534 writeF1000(os, minexptime);
3535 writeF1000(os, maxexptime);
3536 writeF1000(os, minsize);
3537 writeF1000(os, maxsize);
3538 writeU8(os, collisiondetection);
3539 os<<serializeLongString(texture);
3543 std::string s = os.str();
3544 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3546 m_con.Send(peer_id, 0, data, true);
3549 // Adds a ParticleSpawner on all peers
3550 void Server::SendAddParticleSpawnerAll(u16 amount, float spawntime, v3f minpos, v3f maxpos,
3551 v3f minvel, v3f maxvel, v3f minacc, v3f maxacc, float minexptime, float maxexptime,
3552 float minsize, float maxsize, bool collisiondetection, std::string texture, u32 id)
3554 for(std::map<u16, RemoteClient*>::iterator
3555 i = m_clients.begin();
3556 i != m_clients.end(); i++)
3558 // Get client and check that it is valid
3559 RemoteClient *client = i->second;
3560 assert(client->peer_id == i->first);
3561 if(client->serialization_version == SER_FMT_VER_INVALID)
3564 SendAddParticleSpawner(client->peer_id, amount, spawntime,
3565 minpos, maxpos, minvel, maxvel, minacc, maxacc,
3566 minexptime, maxexptime, minsize, maxsize, collisiondetection, texture, id);
3570 void Server::SendDeleteParticleSpawner(u16 peer_id, u32 id)
3572 DSTACK(__FUNCTION_NAME);
3574 std::ostringstream os(std::ios_base::binary);
3575 writeU16(os, TOCLIENT_DELETE_PARTICLESPAWNER);
3580 std::string s = os.str();
3581 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3583 m_con.Send(peer_id, 0, data, true);
3586 void Server::SendDeleteParticleSpawnerAll(u32 id)
3588 for(std::map<u16, RemoteClient*>::iterator
3589 i = m_clients.begin();
3590 i != m_clients.end(); i++)
3592 // Get client and check that it is valid
3593 RemoteClient *client = i->second;
3594 assert(client->peer_id == i->first);
3595 if(client->serialization_version == SER_FMT_VER_INVALID)
3598 SendDeleteParticleSpawner(client->peer_id, id);
3602 void Server::SendHUDAdd(u16 peer_id, u32 id, HudElement *form)
3604 std::ostringstream os(std::ios_base::binary);
3607 writeU16(os, TOCLIENT_HUDADD);
3609 writeU8(os, (u8)form->type);
3610 writeV2F1000(os, form->pos);
3611 os << serializeString(form->name);
3612 writeV2F1000(os, form->scale);
3613 os << serializeString(form->text);
3614 writeU32(os, form->number);
3615 writeU32(os, form->item);
3616 writeU32(os, form->dir);
3617 writeV2F1000(os, form->align);
3618 writeV2F1000(os, form->offset);
3621 std::string s = os.str();
3622 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3624 m_con.Send(peer_id, 0, data, true);
3627 void Server::SendHUDRemove(u16 peer_id, u32 id)
3629 std::ostringstream os(std::ios_base::binary);
3632 writeU16(os, TOCLIENT_HUDRM);
3636 std::string s = os.str();
3637 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3639 m_con.Send(peer_id, 0, data, true);
3642 void Server::SendHUDChange(u16 peer_id, u32 id, HudElementStat stat, void *value)
3644 std::ostringstream os(std::ios_base::binary);
3647 writeU16(os, TOCLIENT_HUDCHANGE);
3649 writeU8(os, (u8)stat);
3652 case HUD_STAT_SCALE:
3653 case HUD_STAT_ALIGN:
3654 case HUD_STAT_OFFSET:
3655 writeV2F1000(os, *(v2f *)value);
3659 os << serializeString(*(std::string *)value);
3661 case HUD_STAT_NUMBER:
3665 writeU32(os, *(u32 *)value);
3670 std::string s = os.str();
3671 SharedBuffer<u8> data((u8 *)s.c_str(), s.size());
3673 m_con.Send(peer_id, 0, data, true);
3676 void Server::SendHUDSetFlags(u16 peer_id, u32 flags, u32 mask)
3678 std::ostringstream os(std::ios_base::binary);
3681 writeU16(os, TOCLIENT_HUD_SET_FLAGS);
3682 writeU32(os, flags);
3686 std::string s = os.str();
3687 SharedBuffer<u8> data((u8 *)s.c_str(), s.size());
3689 m_con.Send(peer_id, 0, data, true);
3692 void Server::BroadcastChatMessage(const std::wstring &message)
3694 for(std::map<u16, RemoteClient*>::iterator
3695 i = m_clients.begin();
3696 i != m_clients.end(); ++i)
3698 // Get client and check that it is valid
3699 RemoteClient *client = i->second;
3700 assert(client->peer_id == i->first);
3701 if(client->serialization_version == SER_FMT_VER_INVALID)
3704 SendChatMessage(client->peer_id, message);
3708 void Server::SendPlayerHP(u16 peer_id)
3710 DSTACK(__FUNCTION_NAME);
3711 PlayerSAO *playersao = getPlayerSAO(peer_id);
3713 playersao->m_hp_not_sent = false;
3714 SendHP(m_con, peer_id, playersao->getHP());
3717 void Server::SendMovePlayer(u16 peer_id)
3719 DSTACK(__FUNCTION_NAME);
3720 Player *player = m_env->getPlayer(peer_id);
3723 std::ostringstream os(std::ios_base::binary);
3724 writeU16(os, TOCLIENT_MOVE_PLAYER);
3725 writeV3F1000(os, player->getPosition());
3726 writeF1000(os, player->getPitch());
3727 writeF1000(os, player->getYaw());
3730 v3f pos = player->getPosition();
3731 f32 pitch = player->getPitch();
3732 f32 yaw = player->getYaw();
3733 verbosestream<<"Server: Sending TOCLIENT_MOVE_PLAYER"
3734 <<" pos=("<<pos.X<<","<<pos.Y<<","<<pos.Z<<")"
3741 std::string s = os.str();
3742 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3744 m_con.Send(peer_id, 0, data, true);
3747 void Server::SendPlayerPrivileges(u16 peer_id)
3749 Player *player = m_env->getPlayer(peer_id);
3751 if(player->peer_id == PEER_ID_INEXISTENT)
3754 std::set<std::string> privs;
3755 scriptapi_get_auth(m_lua, player->getName(), NULL, &privs);
3757 std::ostringstream os(std::ios_base::binary);
3758 writeU16(os, TOCLIENT_PRIVILEGES);
3759 writeU16(os, privs.size());
3760 for(std::set<std::string>::const_iterator i = privs.begin();
3761 i != privs.end(); i++){
3762 os<<serializeString(*i);
3766 std::string s = os.str();
3767 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3769 m_con.Send(peer_id, 0, data, true);
3772 void Server::SendPlayerInventoryFormspec(u16 peer_id)
3774 Player *player = m_env->getPlayer(peer_id);
3776 if(player->peer_id == PEER_ID_INEXISTENT)
3779 std::ostringstream os(std::ios_base::binary);
3780 writeU16(os, TOCLIENT_INVENTORY_FORMSPEC);
3781 os<<serializeLongString(player->inventory_formspec);
3784 std::string s = os.str();
3785 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3787 m_con.Send(peer_id, 0, data, true);
3790 s32 Server::playSound(const SimpleSoundSpec &spec,
3791 const ServerSoundParams ¶ms)
3793 // Find out initial position of sound
3794 bool pos_exists = false;
3795 v3f pos = params.getPos(m_env, &pos_exists);
3796 // If position is not found while it should be, cancel sound
3797 if(pos_exists != (params.type != ServerSoundParams::SSP_LOCAL))
3799 // Filter destination clients
3800 std::set<RemoteClient*> dst_clients;
3801 if(params.to_player != "")
3803 Player *player = m_env->getPlayer(params.to_player.c_str());
3805 infostream<<"Server::playSound: Player \""<<params.to_player
3806 <<"\" not found"<<std::endl;
3809 if(player->peer_id == PEER_ID_INEXISTENT){
3810 infostream<<"Server::playSound: Player \""<<params.to_player
3811 <<"\" not connected"<<std::endl;
3814 RemoteClient *client = getClient(player->peer_id);
3815 dst_clients.insert(client);
3819 for(std::map<u16, RemoteClient*>::iterator
3820 i = m_clients.begin(); i != m_clients.end(); ++i)
3822 RemoteClient *client = i->second;
3823 Player *player = m_env->getPlayer(client->peer_id);
3827 if(player->getPosition().getDistanceFrom(pos) >
3828 params.max_hear_distance)
3831 dst_clients.insert(client);
3834 if(dst_clients.size() == 0)
3837 s32 id = m_next_sound_id++;
3838 // The sound will exist as a reference in m_playing_sounds
3839 m_playing_sounds[id] = ServerPlayingSound();
3840 ServerPlayingSound &psound = m_playing_sounds[id];
3841 psound.params = params;
3842 for(std::set<RemoteClient*>::iterator i = dst_clients.begin();
3843 i != dst_clients.end(); i++)
3844 psound.clients.insert((*i)->peer_id);
3846 std::ostringstream os(std::ios_base::binary);
3847 writeU16(os, TOCLIENT_PLAY_SOUND);
3849 os<<serializeString(spec.name);
3850 writeF1000(os, spec.gain * params.gain);
3851 writeU8(os, params.type);
3852 writeV3F1000(os, pos);
3853 writeU16(os, params.object);
3854 writeU8(os, params.loop);
3856 std::string s = os.str();
3857 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3859 for(std::set<RemoteClient*>::iterator i = dst_clients.begin();
3860 i != dst_clients.end(); i++){
3862 m_con.Send((*i)->peer_id, 0, data, true);
3866 void Server::stopSound(s32 handle)
3868 // Get sound reference
3869 std::map<s32, ServerPlayingSound>::iterator i =
3870 m_playing_sounds.find(handle);
3871 if(i == m_playing_sounds.end())
3873 ServerPlayingSound &psound = i->second;
3875 std::ostringstream os(std::ios_base::binary);
3876 writeU16(os, TOCLIENT_STOP_SOUND);
3877 writeS32(os, handle);
3879 std::string s = os.str();
3880 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3882 for(std::set<u16>::iterator i = psound.clients.begin();
3883 i != psound.clients.end(); i++){
3885 m_con.Send(*i, 0, data, true);
3887 // Remove sound reference
3888 m_playing_sounds.erase(i);
3891 void Server::sendRemoveNode(v3s16 p, u16 ignore_id,
3892 std::list<u16> *far_players, float far_d_nodes)
3894 float maxd = far_d_nodes*BS;
3895 v3f p_f = intToFloat(p, BS);
3899 SharedBuffer<u8> reply(replysize);
3900 writeU16(&reply[0], TOCLIENT_REMOVENODE);
3901 writeS16(&reply[2], p.X);
3902 writeS16(&reply[4], p.Y);
3903 writeS16(&reply[6], p.Z);
3905 for(std::map<u16, RemoteClient*>::iterator
3906 i = m_clients.begin();
3907 i != m_clients.end(); ++i)
3909 // Get client and check that it is valid
3910 RemoteClient *client = i->second;
3911 assert(client->peer_id == i->first);
3912 if(client->serialization_version == SER_FMT_VER_INVALID)
3915 // Don't send if it's the same one
3916 if(client->peer_id == ignore_id)
3922 Player *player = m_env->getPlayer(client->peer_id);
3925 // If player is far away, only set modified blocks not sent
3926 v3f player_pos = player->getPosition();
3927 if(player_pos.getDistanceFrom(p_f) > maxd)
3929 far_players->push_back(client->peer_id);
3936 m_con.Send(client->peer_id, 0, reply, true);
3940 void Server::sendAddNode(v3s16 p, MapNode n, u16 ignore_id,
3941 std::list<u16> *far_players, float far_d_nodes)
3943 float maxd = far_d_nodes*BS;
3944 v3f p_f = intToFloat(p, BS);
3946 for(std::map<u16, RemoteClient*>::iterator
3947 i = m_clients.begin();
3948 i != m_clients.end(); ++i)
3950 // Get client and check that it is valid
3951 RemoteClient *client = i->second;
3952 assert(client->peer_id == i->first);
3953 if(client->serialization_version == SER_FMT_VER_INVALID)
3956 // Don't send if it's the same one
3957 if(client->peer_id == ignore_id)
3963 Player *player = m_env->getPlayer(client->peer_id);
3966 // If player is far away, only set modified blocks not sent
3967 v3f player_pos = player->getPosition();
3968 if(player_pos.getDistanceFrom(p_f) > maxd)
3970 far_players->push_back(client->peer_id);
3977 u32 replysize = 8 + MapNode::serializedLength(client->serialization_version);
3978 SharedBuffer<u8> reply(replysize);
3979 writeU16(&reply[0], TOCLIENT_ADDNODE);
3980 writeS16(&reply[2], p.X);
3981 writeS16(&reply[4], p.Y);
3982 writeS16(&reply[6], p.Z);
3983 n.serialize(&reply[8], client->serialization_version);
3986 m_con.Send(client->peer_id, 0, reply, true);
3990 void Server::setBlockNotSent(v3s16 p)
3992 for(std::map<u16, RemoteClient*>::iterator
3993 i = m_clients.begin();
3994 i != m_clients.end(); ++i)
3996 RemoteClient *client = i->second;
3997 client->SetBlockNotSent(p);
4001 void Server::SendBlockNoLock(u16 peer_id, MapBlock *block, u8 ver)
4003 DSTACK(__FUNCTION_NAME);
4005 v3s16 p = block->getPos();
4009 bool completely_air = true;
4010 for(s16 z0=0; z0<MAP_BLOCKSIZE; z0++)
4011 for(s16 x0=0; x0<MAP_BLOCKSIZE; x0++)
4012 for(s16 y0=0; y0<MAP_BLOCKSIZE; y0++)
4014 if(block->getNodeNoEx(v3s16(x0,y0,z0)).d != CONTENT_AIR)
4016 completely_air = false;
4017 x0 = y0 = z0 = MAP_BLOCKSIZE; // Break out
4022 infostream<<"Server: Sending block ("<<p.X<<","<<p.Y<<","<<p.Z<<"): ";
4024 infostream<<"[completely air] ";
4025 infostream<<std::endl;
4029 Create a packet with the block in the right format
4032 std::ostringstream os(std::ios_base::binary);
4033 block->serialize(os, ver, false);
4034 std::string s = os.str();
4035 SharedBuffer<u8> blockdata((u8*)s.c_str(), s.size());
4037 u32 replysize = 8 + blockdata.getSize();
4038 SharedBuffer<u8> reply(replysize);
4039 writeU16(&reply[0], TOCLIENT_BLOCKDATA);
4040 writeS16(&reply[2], p.X);
4041 writeS16(&reply[4], p.Y);
4042 writeS16(&reply[6], p.Z);
4043 memcpy(&reply[8], *blockdata, blockdata.getSize());
4045 /*infostream<<"Server: Sending block ("<<p.X<<","<<p.Y<<","<<p.Z<<")"
4046 <<": \tpacket size: "<<replysize<<std::endl;*/
4051 m_con.Send(peer_id, 1, reply, true);
4054 void Server::SendBlocks(float dtime)
4056 DSTACK(__FUNCTION_NAME);
4058 JMutexAutoLock envlock(m_env_mutex);
4059 JMutexAutoLock conlock(m_con_mutex);
4061 ScopeProfiler sp(g_profiler, "Server: sel and send blocks to clients");
4063 std::vector<PrioritySortedBlockTransfer> queue;
4065 s32 total_sending = 0;
4068 ScopeProfiler sp(g_profiler, "Server: selecting blocks for sending");
4070 for(std::map<u16, RemoteClient*>::iterator
4071 i = m_clients.begin();
4072 i != m_clients.end(); ++i)
4074 RemoteClient *client = i->second;
4075 assert(client->peer_id == i->first);
4077 // If definitions and textures have not been sent, don't
4078 // send MapBlocks either
4079 if(!client->definitions_sent)
4082 total_sending += client->SendingCount();
4084 if(client->serialization_version == SER_FMT_VER_INVALID)
4087 client->GetNextBlocks(this, dtime, queue);
4092 // Lowest priority number comes first.
4093 // Lowest is most important.
4094 std::sort(queue.begin(), queue.end());
4096 for(u32 i=0; i<queue.size(); i++)
4098 //TODO: Calculate limit dynamically
4099 if(total_sending >= g_settings->getS32
4100 ("max_simultaneous_block_sends_server_total"))
4103 PrioritySortedBlockTransfer q = queue[i];
4105 MapBlock *block = NULL;
4108 block = m_env->getMap().getBlockNoCreate(q.pos);
4110 catch(InvalidPositionException &e)
4115 RemoteClient *client = getClient(q.peer_id);
4117 SendBlockNoLock(q.peer_id, block, client->serialization_version);
4119 client->SentBlock(q.pos);
4125 void Server::fillMediaCache()
4127 DSTACK(__FUNCTION_NAME);
4129 infostream<<"Server: Calculating media file checksums"<<std::endl;
4131 // Collect all media file paths
4132 std::list<std::string> paths;
4133 for(std::vector<ModSpec>::iterator i = m_mods.begin();
4134 i != m_mods.end(); i++){
4135 const ModSpec &mod = *i;
4136 paths.push_back(mod.path + DIR_DELIM + "textures");
4137 paths.push_back(mod.path + DIR_DELIM + "sounds");
4138 paths.push_back(mod.path + DIR_DELIM + "media");
4139 paths.push_back(mod.path + DIR_DELIM + "models");
4141 std::string path_all = "textures";
4142 paths.push_back(path_all + DIR_DELIM + "all");
4144 // Collect media file information from paths into cache
4145 for(std::list<std::string>::iterator i = paths.begin();
4146 i != paths.end(); i++)
4148 std::string mediapath = *i;
4149 std::vector<fs::DirListNode> dirlist = fs::GetDirListing(mediapath);
4150 for(u32 j=0; j<dirlist.size(); j++){
4151 if(dirlist[j].dir) // Ignode dirs
4153 std::string filename = dirlist[j].name;
4154 // If name contains illegal characters, ignore the file
4155 if(!string_allowed(filename, TEXTURENAME_ALLOWED_CHARS)){
4156 infostream<<"Server: ignoring illegal file name: \""
4157 <<filename<<"\""<<std::endl;
4160 // If name is not in a supported format, ignore it
4161 const char *supported_ext[] = {
4162 ".png", ".jpg", ".bmp", ".tga",
4163 ".pcx", ".ppm", ".psd", ".wal", ".rgb",
4165 ".x", ".b3d", ".md2", ".obj",
4168 if(removeStringEnd(filename, supported_ext) == ""){
4169 infostream<<"Server: ignoring unsupported file extension: \""
4170 <<filename<<"\""<<std::endl;
4173 // Ok, attempt to load the file and add to cache
4174 std::string filepath = mediapath + DIR_DELIM + filename;
4176 std::ifstream fis(filepath.c_str(), std::ios_base::binary);
4177 if(fis.good() == false){
4178 errorstream<<"Server::fillMediaCache(): Could not open \""
4179 <<filename<<"\" for reading"<<std::endl;
4182 std::ostringstream tmp_os(std::ios_base::binary);
4186 fis.read(buf, 1024);
4187 std::streamsize len = fis.gcount();
4188 tmp_os.write(buf, len);
4197 errorstream<<"Server::fillMediaCache(): Failed to read \""
4198 <<filename<<"\""<<std::endl;
4201 if(tmp_os.str().length() == 0){
4202 errorstream<<"Server::fillMediaCache(): Empty file \""
4203 <<filepath<<"\""<<std::endl;
4208 sha1.addBytes(tmp_os.str().c_str(), tmp_os.str().length());
4210 unsigned char *digest = sha1.getDigest();
4211 std::string sha1_base64 = base64_encode(digest, 20);
4212 std::string sha1_hex = hex_encode((char*)digest, 20);
4216 this->m_media[filename] = MediaInfo(filepath, sha1_base64);
4217 verbosestream<<"Server: "<<sha1_hex<<" is "<<filename<<std::endl;
4222 struct SendableMediaAnnouncement
4225 std::string sha1_digest;
4227 SendableMediaAnnouncement(const std::string name_="",
4228 const std::string sha1_digest_=""):
4230 sha1_digest(sha1_digest_)
4234 void Server::sendMediaAnnouncement(u16 peer_id)
4236 DSTACK(__FUNCTION_NAME);
4238 verbosestream<<"Server: Announcing files to id("<<peer_id<<")"
4241 std::list<SendableMediaAnnouncement> file_announcements;
4243 for(std::map<std::string, MediaInfo>::iterator i = m_media.begin();
4244 i != m_media.end(); i++){
4246 file_announcements.push_back(
4247 SendableMediaAnnouncement(i->first, i->second.sha1_digest));
4251 std::ostringstream os(std::ios_base::binary);
4259 u16 length of sha1_digest
4264 writeU16(os, TOCLIENT_ANNOUNCE_MEDIA);
4265 writeU16(os, file_announcements.size());
4267 for(std::list<SendableMediaAnnouncement>::iterator
4268 j = file_announcements.begin();
4269 j != file_announcements.end(); ++j){
4270 os<<serializeString(j->name);
4271 os<<serializeString(j->sha1_digest);
4273 os<<serializeString(g_settings->get("remote_media"));
4276 std::string s = os.str();
4277 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
4280 m_con.Send(peer_id, 0, data, true);
4283 struct SendableMedia
4289 SendableMedia(const std::string &name_="", const std::string path_="",
4290 const std::string &data_=""):
4297 void Server::sendRequestedMedia(u16 peer_id,
4298 const std::list<MediaRequest> &tosend)
4300 DSTACK(__FUNCTION_NAME);
4302 verbosestream<<"Server::sendRequestedMedia(): "
4303 <<"Sending files to client"<<std::endl;
4307 // Put 5kB in one bunch (this is not accurate)
4308 u32 bytes_per_bunch = 5000;
4310 std::vector< std::list<SendableMedia> > file_bunches;
4311 file_bunches.push_back(std::list<SendableMedia>());
4313 u32 file_size_bunch_total = 0;
4315 for(std::list<MediaRequest>::const_iterator i = tosend.begin();
4316 i != tosend.end(); ++i)
4318 if(m_media.find(i->name) == m_media.end()){
4319 errorstream<<"Server::sendRequestedMedia(): Client asked for "
4320 <<"unknown file \""<<(i->name)<<"\""<<std::endl;
4324 //TODO get path + name
4325 std::string tpath = m_media[(*i).name].path;
4328 std::ifstream fis(tpath.c_str(), std::ios_base::binary);
4329 if(fis.good() == false){
4330 errorstream<<"Server::sendRequestedMedia(): Could not open \""
4331 <<tpath<<"\" for reading"<<std::endl;
4334 std::ostringstream tmp_os(std::ios_base::binary);
4338 fis.read(buf, 1024);
4339 std::streamsize len = fis.gcount();
4340 tmp_os.write(buf, len);
4341 file_size_bunch_total += len;
4350 errorstream<<"Server::sendRequestedMedia(): Failed to read \""
4351 <<(*i).name<<"\""<<std::endl;
4354 /*infostream<<"Server::sendRequestedMedia(): Loaded \""
4355 <<tname<<"\""<<std::endl;*/
4357 file_bunches[file_bunches.size()-1].push_back(
4358 SendableMedia((*i).name, tpath, tmp_os.str()));
4360 // Start next bunch if got enough data
4361 if(file_size_bunch_total >= bytes_per_bunch){
4362 file_bunches.push_back(std::list<SendableMedia>());
4363 file_size_bunch_total = 0;
4368 /* Create and send packets */
4370 u32 num_bunches = file_bunches.size();
4371 for(u32 i=0; i<num_bunches; i++)
4373 std::ostringstream os(std::ios_base::binary);
4377 u16 total number of texture bunches
4378 u16 index of this bunch
4379 u32 number of files in this bunch
4388 writeU16(os, TOCLIENT_MEDIA);
4389 writeU16(os, num_bunches);
4391 writeU32(os, file_bunches[i].size());
4393 for(std::list<SendableMedia>::iterator
4394 j = file_bunches[i].begin();
4395 j != file_bunches[i].end(); ++j){
4396 os<<serializeString(j->name);
4397 os<<serializeLongString(j->data);
4401 std::string s = os.str();
4402 verbosestream<<"Server::sendRequestedMedia(): bunch "
4403 <<i<<"/"<<num_bunches
4404 <<" files="<<file_bunches[i].size()
4405 <<" size=" <<s.size()<<std::endl;
4406 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
4408 m_con.Send(peer_id, 0, data, true);
4412 void Server::sendDetachedInventory(const std::string &name, u16 peer_id)
4414 if(m_detached_inventories.count(name) == 0){
4415 errorstream<<__FUNCTION_NAME<<": \""<<name<<"\" not found"<<std::endl;
4418 Inventory *inv = m_detached_inventories[name];
4420 std::ostringstream os(std::ios_base::binary);
4421 writeU16(os, TOCLIENT_DETACHED_INVENTORY);
4422 os<<serializeString(name);
4426 std::string s = os.str();
4427 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
4429 m_con.Send(peer_id, 0, data, true);
4432 void Server::sendDetachedInventoryToAll(const std::string &name)
4434 DSTACK(__FUNCTION_NAME);
4436 for(std::map<u16, RemoteClient*>::iterator
4437 i = m_clients.begin();
4438 i != m_clients.end(); ++i){
4439 RemoteClient *client = i->second;
4440 sendDetachedInventory(name, client->peer_id);
4444 void Server::sendDetachedInventories(u16 peer_id)
4446 DSTACK(__FUNCTION_NAME);
4448 for(std::map<std::string, Inventory*>::iterator
4449 i = m_detached_inventories.begin();
4450 i != m_detached_inventories.end(); i++){
4451 const std::string &name = i->first;
4452 //Inventory *inv = i->second;
4453 sendDetachedInventory(name, peer_id);
4461 void Server::DiePlayer(u16 peer_id)
4463 DSTACK(__FUNCTION_NAME);
4465 PlayerSAO *playersao = getPlayerSAO(peer_id);
4468 infostream<<"Server::DiePlayer(): Player "
4469 <<playersao->getPlayer()->getName()
4470 <<" dies"<<std::endl;
4472 playersao->setHP(0);
4474 // Trigger scripted stuff
4475 scriptapi_on_dieplayer(m_lua, playersao);
4477 SendPlayerHP(peer_id);
4478 SendDeathscreen(m_con, peer_id, false, v3f(0,0,0));
4481 void Server::RespawnPlayer(u16 peer_id)
4483 DSTACK(__FUNCTION_NAME);
4485 PlayerSAO *playersao = getPlayerSAO(peer_id);
4488 infostream<<"Server::RespawnPlayer(): Player "
4489 <<playersao->getPlayer()->getName()
4490 <<" respawns"<<std::endl;
4492 playersao->setHP(PLAYER_MAX_HP);
4494 bool repositioned = scriptapi_on_respawnplayer(m_lua, playersao);
4496 v3f pos = findSpawnPos(m_env->getServerMap());
4497 playersao->setPos(pos);
4501 void Server::UpdateCrafting(u16 peer_id)
4503 DSTACK(__FUNCTION_NAME);
4505 Player* player = m_env->getPlayer(peer_id);
4508 // Get a preview for crafting
4510 getCraftingResult(&player->inventory, preview, false, this);
4512 // Put the new preview in
4513 InventoryList *plist = player->inventory.getList("craftpreview");
4515 assert(plist->getSize() >= 1);
4516 plist->changeItem(0, preview);
4519 RemoteClient* Server::getClient(u16 peer_id)
4521 DSTACK(__FUNCTION_NAME);
4522 //JMutexAutoLock lock(m_con_mutex);
4523 std::map<u16, RemoteClient*>::iterator n;
4524 n = m_clients.find(peer_id);
4525 // A client should exist for all peers
4526 assert(n != m_clients.end());
4530 std::wstring Server::getStatusString()
4532 std::wostringstream os(std::ios_base::binary);
4535 os<<L"version="<<narrow_to_wide(VERSION_STRING);
4537 os<<L", uptime="<<m_uptime.get();
4538 // Information about clients
4539 std::map<u16, RemoteClient*>::iterator i;
4542 for(i = m_clients.begin(), first = true;
4543 i != m_clients.end(); ++i)
4545 // Get client and check that it is valid
4546 RemoteClient *client = i->second;
4547 assert(client->peer_id == i->first);
4548 if(client->serialization_version == SER_FMT_VER_INVALID)
4551 Player *player = m_env->getPlayer(client->peer_id);
4552 // Get name of player
4553 std::wstring name = L"unknown";
4555 name = narrow_to_wide(player->getName());
4556 // Add name to information string
4564 if(((ServerMap*)(&m_env->getMap()))->isSavingEnabled() == false)
4565 os<<std::endl<<L"# Server: "<<" WARNING: Map saving is disabled.";
4566 if(g_settings->get("motd") != "")
4567 os<<std::endl<<L"# Server: "<<narrow_to_wide(g_settings->get("motd"));
4571 std::set<std::string> Server::getPlayerEffectivePrivs(const std::string &name)
4573 std::set<std::string> privs;
4574 scriptapi_get_auth(m_lua, name, NULL, &privs);
4578 bool Server::checkPriv(const std::string &name, const std::string &priv)
4580 std::set<std::string> privs = getPlayerEffectivePrivs(name);
4581 return (privs.count(priv) != 0);
4584 void Server::reportPrivsModified(const std::string &name)
4587 for(std::map<u16, RemoteClient*>::iterator
4588 i = m_clients.begin();
4589 i != m_clients.end(); ++i){
4590 RemoteClient *client = i->second;
4591 Player *player = m_env->getPlayer(client->peer_id);
4592 reportPrivsModified(player->getName());
4595 Player *player = m_env->getPlayer(name.c_str());
4598 SendPlayerPrivileges(player->peer_id);
4599 PlayerSAO *sao = player->getPlayerSAO();
4602 sao->updatePrivileges(
4603 getPlayerEffectivePrivs(name),
4608 void Server::reportInventoryFormspecModified(const std::string &name)
4610 Player *player = m_env->getPlayer(name.c_str());
4613 SendPlayerInventoryFormspec(player->peer_id);
4616 // Saves g_settings to configpath given at initialization
4617 void Server::saveConfig()
4619 if(m_path_config != "")
4620 g_settings->updateConfigFile(m_path_config.c_str());
4623 void Server::notifyPlayer(const char *name, const std::wstring msg, const bool prepend = true)
4625 Player *player = m_env->getPlayer(name);
4629 SendChatMessage(player->peer_id, std::wstring(L"Server -!- ")+msg);
4631 SendChatMessage(player->peer_id, msg);
4634 bool Server::showFormspec(const char *playername, const std::string &formspec, const std::string &formname)
4636 Player *player = m_env->getPlayer(playername);
4640 infostream<<"showFormspec: couldn't find player:"<<playername<<std::endl;
4644 SendShowFormspecMessage(player->peer_id, formspec, formname);
4648 u32 Server::hudAdd(Player *player, HudElement *form) {
4652 u32 id = hud_get_free_id(player);
4653 if (id < player->hud.size())
4654 player->hud[id] = form;
4656 player->hud.push_back(form);
4658 SendHUDAdd(player->peer_id, id, form);
4662 bool Server::hudRemove(Player *player, u32 id) {
4663 if (!player || id >= player->hud.size() || !player->hud[id])
4666 delete player->hud[id];
4667 player->hud[id] = NULL;
4669 SendHUDRemove(player->peer_id, id);
4673 bool Server::hudChange(Player *player, u32 id, HudElementStat stat, void *data) {
4677 SendHUDChange(player->peer_id, id, stat, data);
4681 bool Server::hudSetFlags(Player *player, u32 flags, u32 mask) {
4685 SendHUDSetFlags(player->peer_id, flags, mask);
4689 void Server::notifyPlayers(const std::wstring msg)
4691 BroadcastChatMessage(msg);
4694 void Server::spawnParticle(const char *playername, v3f pos,
4695 v3f velocity, v3f acceleration,
4696 float expirationtime, float size, bool
4697 collisiondetection, std::string texture)
4699 Player *player = m_env->getPlayer(playername);
4702 SendSpawnParticle(player->peer_id, pos, velocity, acceleration,
4703 expirationtime, size, collisiondetection, texture);
4706 void Server::spawnParticleAll(v3f pos, v3f velocity, v3f acceleration,
4707 float expirationtime, float size,
4708 bool collisiondetection, std::string texture)
4710 SendSpawnParticleAll(pos, velocity, acceleration,
4711 expirationtime, size, collisiondetection, texture);
4714 u32 Server::addParticleSpawner(const char *playername,
4715 u16 amount, float spawntime,
4716 v3f minpos, v3f maxpos,
4717 v3f minvel, v3f maxvel,
4718 v3f minacc, v3f maxacc,
4719 float minexptime, float maxexptime,
4720 float minsize, float maxsize,
4721 bool collisiondetection, std::string texture)
4723 Player *player = m_env->getPlayer(playername);
4728 for(;;) // look for unused particlespawner id
4731 if (std::find(m_particlespawner_ids.begin(),
4732 m_particlespawner_ids.end(), id)
4733 == m_particlespawner_ids.end())
4735 m_particlespawner_ids.push_back(id);
4740 SendAddParticleSpawner(player->peer_id, amount, spawntime,
4741 minpos, maxpos, minvel, maxvel, minacc, maxacc,
4742 minexptime, maxexptime, minsize, maxsize,
4743 collisiondetection, texture, id);
4748 u32 Server::addParticleSpawnerAll(u16 amount, float spawntime,
4749 v3f minpos, v3f maxpos,
4750 v3f minvel, v3f maxvel,
4751 v3f minacc, v3f maxacc,
4752 float minexptime, float maxexptime,
4753 float minsize, float maxsize,
4754 bool collisiondetection, std::string texture)
4757 for(;;) // look for unused particlespawner id
4760 if (std::find(m_particlespawner_ids.begin(),
4761 m_particlespawner_ids.end(), id)
4762 == m_particlespawner_ids.end())
4764 m_particlespawner_ids.push_back(id);
4769 SendAddParticleSpawnerAll(amount, spawntime,
4770 minpos, maxpos, minvel, maxvel, minacc, maxacc,
4771 minexptime, maxexptime, minsize, maxsize,
4772 collisiondetection, texture, id);
4777 void Server::deleteParticleSpawner(const char *playername, u32 id)
4779 Player *player = m_env->getPlayer(playername);
4783 m_particlespawner_ids.erase(
4784 std::remove(m_particlespawner_ids.begin(),
4785 m_particlespawner_ids.end(), id),
4786 m_particlespawner_ids.end());
4787 SendDeleteParticleSpawner(player->peer_id, id);
4790 void Server::deleteParticleSpawnerAll(u32 id)
4792 m_particlespawner_ids.erase(
4793 std::remove(m_particlespawner_ids.begin(),
4794 m_particlespawner_ids.end(), id),
4795 m_particlespawner_ids.end());
4796 SendDeleteParticleSpawnerAll(id);
4799 void Server::queueBlockEmerge(v3s16 blockpos, bool allow_generate)
4801 m_emerge->enqueueBlockEmerge(PEER_ID_INEXISTENT, blockpos, allow_generate);
4804 Inventory* Server::createDetachedInventory(const std::string &name)
4806 if(m_detached_inventories.count(name) > 0){
4807 infostream<<"Server clearing detached inventory \""<<name<<"\""<<std::endl;
4808 delete m_detached_inventories[name];
4810 infostream<<"Server creating detached inventory \""<<name<<"\""<<std::endl;
4812 Inventory *inv = new Inventory(m_itemdef);
4814 m_detached_inventories[name] = inv;
4815 sendDetachedInventoryToAll(name);
4822 BoolScopeSet(bool *dst, bool val):
4825 m_orig_state = *m_dst;
4830 *m_dst = m_orig_state;
4837 // actions: time-reversed list
4838 // Return value: success/failure
4839 bool Server::rollbackRevertActions(const std::list<RollbackAction> &actions,
4840 std::list<std::string> *log)
4842 infostream<<"Server::rollbackRevertActions(len="<<actions.size()<<")"<<std::endl;
4843 ServerMap *map = (ServerMap*)(&m_env->getMap());
4844 // Disable rollback report sink while reverting
4845 BoolScopeSet rollback_scope_disable(&m_rollback_sink_enabled, false);
4847 // Fail if no actions to handle
4848 if(actions.empty()){
4849 log->push_back("Nothing to do.");
4856 for(std::list<RollbackAction>::const_iterator
4857 i = actions.begin();
4858 i != actions.end(); i++)
4860 const RollbackAction &action = *i;
4862 bool success = action.applyRevert(map, this, this);
4865 std::ostringstream os;
4866 os<<"Revert of step ("<<num_tried<<") "<<action.toString()<<" failed";
4867 infostream<<"Map::rollbackRevertActions(): "<<os.str()<<std::endl;
4869 log->push_back(os.str());
4871 std::ostringstream os;
4872 os<<"Successfully reverted step ("<<num_tried<<") "<<action.toString();
4873 infostream<<"Map::rollbackRevertActions(): "<<os.str()<<std::endl;
4875 log->push_back(os.str());
4879 infostream<<"Map::rollbackRevertActions(): "<<num_failed<<"/"<<num_tried
4880 <<" failed"<<std::endl;
4882 // Call it done if less than half failed
4883 return num_failed <= num_tried/2;
4886 // IGameDef interface
4888 IItemDefManager* Server::getItemDefManager()
4892 INodeDefManager* Server::getNodeDefManager()
4896 ICraftDefManager* Server::getCraftDefManager()
4900 ITextureSource* Server::getTextureSource()
4904 IShaderSource* Server::getShaderSource()
4908 u16 Server::allocateUnknownNodeId(const std::string &name)
4910 return m_nodedef->allocateDummy(name);
4912 ISoundManager* Server::getSoundManager()
4914 return &dummySoundManager;
4916 MtEventManager* Server::getEventManager()
4920 IRollbackReportSink* Server::getRollbackReportSink()
4922 if(!m_enable_rollback_recording)
4924 if(!m_rollback_sink_enabled)
4929 IWritableItemDefManager* Server::getWritableItemDefManager()
4933 IWritableNodeDefManager* Server::getWritableNodeDefManager()
4937 IWritableCraftDefManager* Server::getWritableCraftDefManager()
4942 const ModSpec* Server::getModSpec(const std::string &modname)
4944 for(std::vector<ModSpec>::iterator i = m_mods.begin();
4945 i != m_mods.end(); i++){
4946 const ModSpec &mod = *i;
4947 if(mod.name == modname)
4952 void Server::getModNames(std::list<std::string> &modlist)
4954 for(std::vector<ModSpec>::iterator i = m_mods.begin(); i != m_mods.end(); i++)
4956 modlist.push_back(i->name);
4959 std::string Server::getBuiltinLuaPath()
4961 return porting::path_share + DIR_DELIM + "builtin";
4964 v3f findSpawnPos(ServerMap &map)
4966 //return v3f(50,50,50)*BS;
4971 nodepos = v2s16(0,0);
4976 s16 water_level = map.m_mgparams->water_level;
4978 // Try to find a good place a few times
4979 for(s32 i=0; i<1000; i++)
4982 // We're going to try to throw the player to this position
4983 v2s16 nodepos2d = v2s16(
4984 -range + (myrand() % (range * 2)),
4985 -range + (myrand() % (range * 2)));
4987 // Get ground height at point
4988 s16 groundheight = map.findGroundLevel(nodepos2d);
4989 if (groundheight <= water_level) // Don't go underwater
4991 if (groundheight > water_level + 6) // Don't go to high places
4994 nodepos = v3s16(nodepos2d.X, groundheight, nodepos2d.Y);
4995 bool is_good = false;
4997 for (s32 i = 0; i < 10; i++) {
4998 v3s16 blockpos = getNodeBlockPos(nodepos);
4999 map.emergeBlock(blockpos, true);
5000 content_t c = map.getNodeNoEx(nodepos).getContent();
5001 if (c == CONTENT_AIR || c == CONTENT_IGNORE) {
5003 if (air_count >= 2){
5011 // Found a good place
5012 //infostream<<"Searched through "<<i<<" places."<<std::endl;
5018 return intToFloat(nodepos, BS);
5021 PlayerSAO* Server::emergePlayer(const char *name, u16 peer_id)
5023 RemotePlayer *player = NULL;
5024 bool newplayer = false;
5027 Try to get an existing player
5029 player = static_cast<RemotePlayer*>(m_env->getPlayer(name));
5031 // If player is already connected, cancel
5032 if(player != NULL && player->peer_id != 0)
5034 infostream<<"emergePlayer(): Player already connected"<<std::endl;
5039 If player with the wanted peer_id already exists, cancel.
5041 if(m_env->getPlayer(peer_id) != NULL)
5043 infostream<<"emergePlayer(): Player with wrong name but same"
5044 " peer_id already exists"<<std::endl;
5049 Create a new player if it doesn't exist yet
5054 player = new RemotePlayer(this);
5055 player->updateName(name);
5057 /* Set player position */
5058 infostream<<"Server: Finding spawn place for player \""
5059 <<name<<"\""<<std::endl;
5060 v3f pos = findSpawnPos(m_env->getServerMap());
5061 player->setPosition(pos);
5063 /* Add player to environment */
5064 m_env->addPlayer(player);
5068 Create a new player active object
5070 PlayerSAO *playersao = new PlayerSAO(m_env, player, peer_id,
5071 getPlayerEffectivePrivs(player->getName()),
5074 /* Clean up old HUD elements from previous sessions */
5075 player->hud.clear();
5077 /* Add object to environment */
5078 m_env->addActiveObject(playersao);
5082 scriptapi_on_newplayer(m_lua, playersao);
5084 scriptapi_on_joinplayer(m_lua, playersao);
5089 void Server::handlePeerChange(PeerChange &c)
5091 JMutexAutoLock envlock(m_env_mutex);
5092 JMutexAutoLock conlock(m_con_mutex);
5094 if(c.type == PEER_ADDED)
5101 std::map<u16, RemoteClient*>::iterator n;
5102 n = m_clients.find(c.peer_id);
5103 // The client shouldn't already exist
5104 assert(n == m_clients.end());
5107 RemoteClient *client = new RemoteClient();
5108 client->peer_id = c.peer_id;
5109 m_clients[client->peer_id] = client;
5112 else if(c.type == PEER_REMOVED)
5119 std::map<u16, RemoteClient*>::iterator n;
5120 n = m_clients.find(c.peer_id);
5121 // The client should exist
5122 assert(n != m_clients.end());
5125 Mark objects to be not known by the client
5127 RemoteClient *client = n->second;
5129 for(std::set<u16>::iterator
5130 i = client->m_known_objects.begin();
5131 i != client->m_known_objects.end(); ++i)
5135 ServerActiveObject* obj = m_env->getActiveObject(id);
5137 if(obj && obj->m_known_by_count > 0)
5138 obj->m_known_by_count--;
5142 Clear references to playing sounds
5144 for(std::map<s32, ServerPlayingSound>::iterator
5145 i = m_playing_sounds.begin();
5146 i != m_playing_sounds.end();)
5148 ServerPlayingSound &psound = i->second;
5149 psound.clients.erase(c.peer_id);
5150 if(psound.clients.size() == 0)
5151 m_playing_sounds.erase(i++);
5156 Player *player = m_env->getPlayer(c.peer_id);
5158 // Collect information about leaving in chat
5159 std::wstring message;
5163 std::wstring name = narrow_to_wide(player->getName());
5166 message += L" left the game.";
5168 message += L" (timed out)";
5172 /* Run scripts and remove from environment */
5176 PlayerSAO *playersao = player->getPlayerSAO();
5179 scriptapi_on_leaveplayer(m_lua, playersao);
5181 playersao->disconnected();
5191 std::ostringstream os(std::ios_base::binary);
5192 for(std::map<u16, RemoteClient*>::iterator
5193 i = m_clients.begin();
5194 i != m_clients.end(); ++i)
5196 RemoteClient *client = i->second;
5197 assert(client->peer_id == i->first);
5198 if(client->serialization_version == SER_FMT_VER_INVALID)
5201 Player *player = m_env->getPlayer(client->peer_id);
5204 // Get name of player
5205 os<<player->getName()<<" ";
5208 actionstream<<player->getName()<<" "
5209 <<(c.timeout?"times out.":"leaves game.")
5210 <<" List of players: "
5211 <<os.str()<<std::endl;
5216 delete m_clients[c.peer_id];
5217 m_clients.erase(c.peer_id);
5219 // Send player info to all remaining clients
5220 //SendPlayerInfos();
5222 // Send leave chat message to all remaining clients
5223 if(message.length() != 0)
5224 BroadcastChatMessage(message);
5233 void Server::handlePeerChanges()
5235 while(m_peer_change_queue.size() > 0)
5237 PeerChange c = m_peer_change_queue.pop_front();
5239 verbosestream<<"Server: Handling peer change: "
5240 <<"id="<<c.peer_id<<", timeout="<<c.timeout
5243 handlePeerChange(c);
5247 void dedicated_server_loop(Server &server, bool &kill)
5249 DSTACK(__FUNCTION_NAME);
5251 verbosestream<<"dedicated_server_loop()"<<std::endl;
5253 IntervalLimiter m_profiler_interval;
5257 float steplen = g_settings->getFloat("dedicated_server_step");
5258 // This is kind of a hack but can be done like this
5259 // because server.step() is very light
5261 ScopeProfiler sp(g_profiler, "dedicated server sleep");
5262 sleep_ms((int)(steplen*1000.0));
5264 server.step(steplen);
5266 if(server.getShutdownRequested() || kill)
5268 infostream<<"Dedicated server quitting"<<std::endl;
5270 if(g_settings->getBool("server_announce") == true)
5271 ServerList::sendAnnounce("delete");
5279 float profiler_print_interval =
5280 g_settings->getFloat("profiler_print_interval");
5281 if(profiler_print_interval != 0)
5283 if(m_profiler_interval.step(steplen, profiler_print_interval))
5285 infostream<<"Profiler:"<<std::endl;
5286 g_profiler->print(infostream);
5287 g_profiler->clear();