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"
37 #include "script/cpp_api/scriptapi.h"
44 #include "content_mapnode.h"
45 #include "content_nodemeta.h"
46 #include "content_abm.h"
47 #include "content_sao.h"
52 #include "sound.h" // dummySoundManager
53 #include "event_manager.h"
55 #include "serverlist.h"
56 #include "util/string.h"
57 #include "util/pointedthing.h"
58 #include "util/mathconstants.h"
60 #include "util/serialize.h"
61 #include "defaultsettings.h"
63 void * ServerThread::Thread()
67 log_register_thread("ServerThread");
69 DSTACK(__FUNCTION_NAME);
71 BEGIN_DEBUG_EXCEPTION_HANDLER
76 //TimeTaker timer("AsyncRunStep() + Receive()");
79 //TimeTaker timer("AsyncRunStep()");
80 m_server->AsyncRunStep();
83 //infostream<<"Running m_server->Receive()"<<std::endl;
86 catch(con::NoIncomingDataException &e)
89 catch(con::PeerNotFoundException &e)
91 infostream<<"Server: PeerNotFoundException"<<std::endl;
93 catch(con::ConnectionBindFailed &e)
95 m_server->setAsyncFatalError(e.what());
99 m_server->setAsyncFatalError(e.what());
103 END_DEBUG_EXCEPTION_HANDLER(errorstream)
108 v3f ServerSoundParams::getPos(ServerEnvironment *env, bool *pos_exists) const
110 if(pos_exists) *pos_exists = false;
115 if(pos_exists) *pos_exists = true;
120 ServerActiveObject *sao = env->getActiveObject(object);
123 if(pos_exists) *pos_exists = true;
124 return sao->getBasePosition(); }
129 void RemoteClient::GetNextBlocks(Server *server, float dtime,
130 std::vector<PrioritySortedBlockTransfer> &dest)
132 DSTACK(__FUNCTION_NAME);
135 TimeTaker timer("RemoteClient::GetNextBlocks", &timer_result);*/
138 m_nothing_to_send_pause_timer -= dtime;
139 m_nearest_unsent_reset_timer += dtime;
141 if(m_nothing_to_send_pause_timer >= 0)
144 Player *player = server->m_env->getPlayer(peer_id);
145 // This can happen sometimes; clients and players are not in perfect sync.
149 // Won't send anything if already sending
150 if(m_blocks_sending.size() >= g_settings->getU16
151 ("max_simultaneous_block_sends_per_client"))
153 //infostream<<"Not sending any blocks, Queue full."<<std::endl;
157 //TimeTaker timer("RemoteClient::GetNextBlocks");
159 v3f playerpos = player->getPosition();
160 v3f playerspeed = player->getSpeed();
161 v3f playerspeeddir(0,0,0);
162 if(playerspeed.getLength() > 1.0*BS)
163 playerspeeddir = playerspeed / playerspeed.getLength();
164 // Predict to next block
165 v3f playerpos_predicted = playerpos + playerspeeddir*MAP_BLOCKSIZE*BS;
167 v3s16 center_nodepos = floatToInt(playerpos_predicted, BS);
169 v3s16 center = getNodeBlockPos(center_nodepos);
171 // Camera position and direction
172 v3f camera_pos = player->getEyePosition();
173 v3f camera_dir = v3f(0,0,1);
174 camera_dir.rotateYZBy(player->getPitch());
175 camera_dir.rotateXZBy(player->getYaw());
177 /*infostream<<"camera_dir=("<<camera_dir.X<<","<<camera_dir.Y<<","
178 <<camera_dir.Z<<")"<<std::endl;*/
181 Get the starting value of the block finder radius.
184 if(m_last_center != center)
186 m_nearest_unsent_d = 0;
187 m_last_center = center;
190 /*infostream<<"m_nearest_unsent_reset_timer="
191 <<m_nearest_unsent_reset_timer<<std::endl;*/
193 // Reset periodically to workaround for some bugs or stuff
194 if(m_nearest_unsent_reset_timer > 20.0)
196 m_nearest_unsent_reset_timer = 0;
197 m_nearest_unsent_d = 0;
198 //infostream<<"Resetting m_nearest_unsent_d for "
199 // <<server->getPlayerName(peer_id)<<std::endl;
202 //s16 last_nearest_unsent_d = m_nearest_unsent_d;
203 s16 d_start = m_nearest_unsent_d;
205 //infostream<<"d_start="<<d_start<<std::endl;
207 u16 max_simul_sends_setting = g_settings->getU16
208 ("max_simultaneous_block_sends_per_client");
209 u16 max_simul_sends_usually = max_simul_sends_setting;
212 Check the time from last addNode/removeNode.
214 Decrease send rate if player is building stuff.
216 m_time_from_building += dtime;
217 if(m_time_from_building < g_settings->getFloat(
218 "full_block_send_enable_min_time_from_building"))
220 max_simul_sends_usually
221 = LIMITED_MAX_SIMULTANEOUS_BLOCK_SENDS;
225 Number of blocks sending + number of blocks selected for sending
227 u32 num_blocks_selected = m_blocks_sending.size();
230 next time d will be continued from the d from which the nearest
231 unsent block was found this time.
233 This is because not necessarily any of the blocks found this
234 time are actually sent.
236 s32 new_nearest_unsent_d = -1;
238 s16 d_max = g_settings->getS16("max_block_send_distance");
239 s16 d_max_gen = g_settings->getS16("max_block_generate_distance");
241 // Don't loop very much at a time
242 s16 max_d_increment_at_time = 2;
243 if(d_max > d_start + max_d_increment_at_time)
244 d_max = d_start + max_d_increment_at_time;
245 /*if(d_max_gen > d_start+2)
246 d_max_gen = d_start+2;*/
248 //infostream<<"Starting from "<<d_start<<std::endl;
250 s32 nearest_emerged_d = -1;
251 s32 nearest_emergefull_d = -1;
252 s32 nearest_sent_d = -1;
253 bool queue_is_full = false;
256 for(d = d_start; d <= d_max; d++)
258 /*errorstream<<"checking d="<<d<<" for "
259 <<server->getPlayerName(peer_id)<<std::endl;*/
260 //infostream<<"RemoteClient::SendBlocks(): d="<<d<<std::endl;
263 If m_nearest_unsent_d was changed by the EmergeThread
264 (it can change it to 0 through SetBlockNotSent),
266 Else update m_nearest_unsent_d
268 /*if(m_nearest_unsent_d != last_nearest_unsent_d)
270 d = m_nearest_unsent_d;
271 last_nearest_unsent_d = m_nearest_unsent_d;
275 Get the border/face dot coordinates of a "d-radiused"
278 std::list<v3s16> list;
279 getFacePositions(list, d);
281 std::list<v3s16>::iterator li;
282 for(li=list.begin(); li!=list.end(); ++li)
284 v3s16 p = *li + center;
288 - Don't allow too many simultaneous transfers
289 - EXCEPT when the blocks are very close
291 Also, don't send blocks that are already flying.
294 // Start with the usual maximum
295 u16 max_simul_dynamic = max_simul_sends_usually;
297 // If block is very close, allow full maximum
298 if(d <= BLOCK_SEND_DISABLE_LIMITS_MAX_D)
299 max_simul_dynamic = max_simul_sends_setting;
301 // Don't select too many blocks for sending
302 if(num_blocks_selected >= max_simul_dynamic)
304 queue_is_full = true;
305 goto queue_full_break;
308 // Don't send blocks that are currently being transferred
309 if(m_blocks_sending.find(p) != m_blocks_sending.end())
315 if(p.X < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
316 || p.X > MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
317 || p.Y < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
318 || p.Y > MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
319 || p.Z < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
320 || p.Z > MAP_GENERATION_LIMIT / MAP_BLOCKSIZE)
323 // If this is true, inexistent block will be made from scratch
324 bool generate = d <= d_max_gen;
327 /*// Limit the generating area vertically to 2/3
328 if(abs(p.Y - center.Y) > d_max_gen - d_max_gen / 3)
331 // Limit the send area vertically to 1/2
332 if(abs(p.Y - center.Y) > d_max / 2)
338 If block is far away, don't generate it unless it is
344 // Block center y in nodes
345 f32 y = (f32)(p.Y * MAP_BLOCKSIZE + MAP_BLOCKSIZE/2);
346 // Don't generate if it's very high or very low
347 if(y < -64 || y > 64)
351 v2s16 p2d_nodes_center(
355 // Get ground height in nodes
356 s16 gh = server->m_env->getServerMap().findGroundLevel(
359 // If differs a lot, don't generate
360 if(fabs(gh - y) > MAP_BLOCKSIZE*2)
362 // Actually, don't even send it
368 //infostream<<"d="<<d<<std::endl;
371 Don't generate or send if not in sight
372 FIXME This only works if the client uses a small enough
373 FOV setting. The default of 72 degrees is fine.
376 float camera_fov = (72.0*M_PI/180) * 4./3.;
377 if(isBlockInSight(p, camera_pos, camera_dir, camera_fov, 10000*BS) == false)
383 Don't send already sent blocks
386 if(m_blocks_sent.find(p) != m_blocks_sent.end())
393 Check if map has this block
395 MapBlock *block = server->m_env->getMap().getBlockNoCreateNoEx(p);
397 bool surely_not_found_on_disk = false;
398 bool block_is_invalid = false;
401 // Reset usage timer, this block will be of use in the future.
402 block->resetUsageTimer();
404 // Block is dummy if data doesn't exist.
405 // It means it has been not found from disk and not generated
408 surely_not_found_on_disk = true;
411 // Block is valid if lighting is up-to-date and data exists
412 if(block->isValid() == false)
414 block_is_invalid = true;
417 /*if(block->isFullyGenerated() == false)
419 block_is_invalid = true;
424 ServerMap *map = (ServerMap*)(&server->m_env->getMap());
425 v2s16 chunkpos = map->sector_to_chunk(p2d);
426 if(map->chunkNonVolatile(chunkpos) == false)
427 block_is_invalid = true;
429 if(block->isGenerated() == false)
430 block_is_invalid = true;
433 If block is not close, don't send it unless it is near
436 Block is near ground level if night-time mesh
437 differs from day-time mesh.
441 if(block->getDayNightDiff() == false)
448 If block has been marked to not exist on disk (dummy)
449 and generating new ones is not wanted, skip block.
451 if(generate == false && surely_not_found_on_disk == true)
458 Add inexistent block to emerge queue.
460 if(block == NULL || surely_not_found_on_disk || block_is_invalid)
462 /* //TODO: Get value from somewhere
463 // Allow only one block in emerge queue
464 //if(server->m_emerge_queue.peerItemCount(peer_id) < 1)
465 // Allow two blocks in queue per client
466 //if(server->m_emerge_queue.peerItemCount(peer_id) < 2)
468 // Make it more responsive when needing to generate stuff
469 if(surely_not_found_on_disk)
471 if(server->m_emerge_queue.peerItemCount(peer_id) < max_emerge)
473 //infostream<<"Adding block to emerge queue"<<std::endl;
475 // Add it to the emerge queue and trigger the thread
478 if(generate == false)
479 flags |= BLOCK_EMERGE_FLAG_FROMDISK;
481 server->m_emerge_queue.addBlock(peer_id, p, flags);
482 server->m_emergethread.trigger();
484 if(nearest_emerged_d == -1)
485 nearest_emerged_d = d;
487 if(nearest_emergefull_d == -1)
488 nearest_emergefull_d = d;
489 goto queue_full_break;
493 if (server->m_emerge->enqueueBlockEmerge(peer_id, p, generate)) {
494 if (nearest_emerged_d == -1)
495 nearest_emerged_d = d;
497 if (nearest_emergefull_d == -1)
498 nearest_emergefull_d = d;
499 goto queue_full_break;
506 if(nearest_sent_d == -1)
510 Add block to send queue
513 /*errorstream<<"sending from d="<<d<<" to "
514 <<server->getPlayerName(peer_id)<<std::endl;*/
516 PrioritySortedBlockTransfer q((float)d, p, peer_id);
520 num_blocks_selected += 1;
525 //infostream<<"Stopped at "<<d<<std::endl;
527 // If nothing was found for sending and nothing was queued for
528 // emerging, continue next time browsing from here
529 if(nearest_emerged_d != -1){
530 new_nearest_unsent_d = nearest_emerged_d;
531 } else if(nearest_emergefull_d != -1){
532 new_nearest_unsent_d = nearest_emergefull_d;
534 if(d > g_settings->getS16("max_block_send_distance")){
535 new_nearest_unsent_d = 0;
536 m_nothing_to_send_pause_timer = 2.0;
537 /*infostream<<"GetNextBlocks(): d wrapped around for "
538 <<server->getPlayerName(peer_id)
539 <<"; setting to 0 and pausing"<<std::endl;*/
541 if(nearest_sent_d != -1)
542 new_nearest_unsent_d = nearest_sent_d;
544 new_nearest_unsent_d = d;
548 if(new_nearest_unsent_d != -1)
549 m_nearest_unsent_d = new_nearest_unsent_d;
551 /*timer_result = timer.stop(true);
552 if(timer_result != 0)
553 infostream<<"GetNextBlocks timeout: "<<timer_result<<" (!=0)"<<std::endl;*/
556 void RemoteClient::GotBlock(v3s16 p)
558 if(m_blocks_sending.find(p) != m_blocks_sending.end())
559 m_blocks_sending.erase(p);
562 /*infostream<<"RemoteClient::GotBlock(): Didn't find in"
563 " m_blocks_sending"<<std::endl;*/
564 m_excess_gotblocks++;
566 m_blocks_sent.insert(p);
569 void RemoteClient::SentBlock(v3s16 p)
571 if(m_blocks_sending.find(p) == m_blocks_sending.end())
572 m_blocks_sending[p] = 0.0;
574 infostream<<"RemoteClient::SentBlock(): Sent block"
575 " already in m_blocks_sending"<<std::endl;
578 void RemoteClient::SetBlockNotSent(v3s16 p)
580 m_nearest_unsent_d = 0;
582 if(m_blocks_sending.find(p) != m_blocks_sending.end())
583 m_blocks_sending.erase(p);
584 if(m_blocks_sent.find(p) != m_blocks_sent.end())
585 m_blocks_sent.erase(p);
588 void RemoteClient::SetBlocksNotSent(std::map<v3s16, MapBlock*> &blocks)
590 m_nearest_unsent_d = 0;
592 for(std::map<v3s16, MapBlock*>::iterator
594 i != blocks.end(); ++i)
598 if(m_blocks_sending.find(p) != m_blocks_sending.end())
599 m_blocks_sending.erase(p);
600 if(m_blocks_sent.find(p) != m_blocks_sent.end())
601 m_blocks_sent.erase(p);
609 PlayerInfo::PlayerInfo()
615 void PlayerInfo::PrintLine(std::ostream *s)
618 (*s)<<"\""<<name<<"\" ("
619 <<(position.X/10)<<","<<(position.Y/10)
620 <<","<<(position.Z/10)<<") ";
622 (*s)<<" avg_rtt="<<avg_rtt;
631 const std::string &path_world,
632 const std::string &path_config,
633 const SubgameSpec &gamespec,
634 bool simple_singleplayer_mode
636 m_path_world(path_world),
637 m_path_config(path_config),
638 m_gamespec(gamespec),
639 m_simple_singleplayer_mode(simple_singleplayer_mode),
640 m_async_fatal_error(""),
642 m_con(PROTOCOL_ID, 512, CONNECTION_TIMEOUT, this),
643 m_banmanager(path_world+DIR_DELIM+"ipban.txt"),
645 m_rollback_sink_enabled(true),
646 m_enable_rollback_recording(false),
649 m_itemdef(createItemDefManager()),
650 m_nodedef(createNodeDefManager()),
651 m_craftdef(createCraftDefManager()),
652 m_event(new EventManager()),
654 m_time_of_day_send_timer(0),
656 m_shutdown_requested(false),
657 m_ignore_map_edit_events(false),
658 m_ignore_map_edit_events_peer_id(0)
660 m_liquid_transform_timer = 0.0;
661 m_liquid_transform_every = 1.0;
662 m_print_info_timer = 0.0;
663 m_masterserver_timer = 0.0;
664 m_objectdata_timer = 0.0;
665 m_emergethread_trigger_timer = 0.0;
666 m_savemap_timer = 0.0;
667 m_clients_number = 0;
671 m_step_dtime_mutex.Init();
675 throw ServerError("Supplied empty world path");
677 if(!gamespec.isValid())
678 throw ServerError("Supplied invalid gamespec");
680 infostream<<"Server created for gameid \""<<m_gamespec.id<<"\"";
681 if(m_simple_singleplayer_mode)
682 infostream<<" in simple singleplayer mode"<<std::endl;
684 infostream<<std::endl;
685 infostream<<"- world: "<<m_path_world<<std::endl;
686 infostream<<"- config: "<<m_path_config<<std::endl;
687 infostream<<"- game: "<<m_gamespec.path<<std::endl;
689 // Initialize default settings and override defaults with those provided
691 set_default_settings(g_settings);
692 Settings gamedefaults;
693 getGameMinetestConfig(gamespec.path, gamedefaults);
694 override_default_settings(g_settings, &gamedefaults);
696 // Create emerge manager
697 m_emerge = new EmergeManager(this);
699 // Create rollback manager
700 std::string rollback_path = m_path_world+DIR_DELIM+"rollback.txt";
701 m_rollback = createRollbackManager(rollback_path, this);
703 // Create world if it doesn't exist
704 if(!initializeWorld(m_path_world, m_gamespec.id))
705 throw ServerError("Failed to initialize world");
707 ModConfiguration modconf(m_path_world);
708 m_mods = modconf.getMods();
709 std::vector<ModSpec> unsatisfied_mods = modconf.getUnsatisfiedMods();
710 // complain about mods with unsatisfied dependencies
711 if(!modconf.isConsistent())
713 for(std::vector<ModSpec>::iterator it = unsatisfied_mods.begin();
714 it != unsatisfied_mods.end(); ++it)
717 errorstream << "mod \"" << mod.name << "\" has unsatisfied dependencies: ";
718 for(std::set<std::string>::iterator dep_it = mod.unsatisfied_depends.begin();
719 dep_it != mod.unsatisfied_depends.end(); ++dep_it)
720 errorstream << " \"" << *dep_it << "\"";
721 errorstream << std::endl;
725 Settings worldmt_settings;
726 std::string worldmt = m_path_world + DIR_DELIM + "world.mt";
727 worldmt_settings.readConfigFile(worldmt.c_str());
728 std::vector<std::string> names = worldmt_settings.getNames();
729 std::set<std::string> load_mod_names;
730 for(std::vector<std::string>::iterator it = names.begin();
731 it != names.end(); ++it)
733 std::string name = *it;
734 if(name.compare(0,9,"load_mod_")==0 && worldmt_settings.getBool(name))
735 load_mod_names.insert(name.substr(9));
737 // complain about mods declared to be loaded, but not found
738 for(std::vector<ModSpec>::iterator it = m_mods.begin();
739 it != m_mods.end(); ++it)
740 load_mod_names.erase((*it).name);
741 for(std::vector<ModSpec>::iterator it = unsatisfied_mods.begin();
742 it != unsatisfied_mods.end(); ++it)
743 load_mod_names.erase((*it).name);
744 if(!load_mod_names.empty())
746 errorstream << "The following mods could not be found:";
747 for(std::set<std::string>::iterator it = load_mod_names.begin();
748 it != load_mod_names.end(); ++it)
749 errorstream << " \"" << (*it) << "\"";
750 errorstream << std::endl;
753 // Path to builtin.lua
754 std::string builtinpath = getBuiltinLuaPath() + DIR_DELIM + "builtin.lua";
757 JMutexAutoLock envlock(m_env_mutex);
758 JMutexAutoLock conlock(m_con_mutex);
760 // Initialize scripting
762 infostream<<"Server: Initializing Lua"<<std::endl;
764 m_script = new ScriptApi(this);
767 // Load and run builtin.lua
768 infostream<<"Server: Loading builtin.lua [\""
769 <<builtinpath<<"\"]"<<std::endl;
770 bool success = m_script->loadMod(builtinpath, "__builtin");
772 errorstream<<"Server: Failed to load and run "
773 <<builtinpath<<std::endl;
774 throw ModError("Failed to load and run "+builtinpath);
777 infostream<<"Server: Loading mods: ";
778 for(std::vector<ModSpec>::iterator i = m_mods.begin();
779 i != m_mods.end(); i++){
780 const ModSpec &mod = *i;
781 infostream<<mod.name<<" ";
783 infostream<<std::endl;
784 // Load and run "mod" scripts
785 for(std::vector<ModSpec>::iterator i = m_mods.begin();
786 i != m_mods.end(); i++){
787 const ModSpec &mod = *i;
788 std::string scriptpath = mod.path + DIR_DELIM + "init.lua";
789 infostream<<" ["<<padStringRight(mod.name, 12)<<"] [\""
790 <<scriptpath<<"\"]"<<std::endl;
791 bool success = m_script->loadMod(scriptpath, mod.name);
793 errorstream<<"Server: Failed to load and run "
794 <<scriptpath<<std::endl;
795 throw ModError("Failed to load and run "+scriptpath);
799 // Read Textures and calculate sha1 sums
802 // Apply item aliases in the node definition manager
803 m_nodedef->updateAliases(m_itemdef);
805 // Initialize Environment
806 ServerMap *servermap = new ServerMap(path_world, this, m_emerge);
807 m_env = new ServerEnvironment(servermap, m_script, this, this);
809 m_emerge->initMapgens(servermap->getMapgenParams());
811 // Give environment reference to scripting api
812 m_script->initializeEnvironment(m_env);
814 // Register us to receive map edit events
815 servermap->addEventReceiver(this);
817 // If file exists, load environment metadata
818 if(fs::PathExists(m_path_world+DIR_DELIM+"env_meta.txt"))
820 infostream<<"Server: Loading environment metadata"<<std::endl;
821 m_env->loadMeta(m_path_world);
825 infostream<<"Server: Loading players"<<std::endl;
826 m_env->deSerializePlayers(m_path_world);
829 Add some test ActiveBlockModifiers to environment
831 add_legacy_abms(m_env, m_nodedef);
833 m_liquid_transform_every = g_settings->getFloat("liquid_update");
838 infostream<<"Server destructing"<<std::endl;
841 Send shutdown message
844 JMutexAutoLock conlock(m_con_mutex);
846 std::wstring line = L"*** Server shutting down";
849 Send the message to clients
851 for(std::map<u16, RemoteClient*>::iterator
852 i = m_clients.begin();
853 i != m_clients.end(); ++i)
855 // Get client and check that it is valid
856 RemoteClient *client = i->second;
857 assert(client->peer_id == i->first);
858 if(client->serialization_version == SER_FMT_VER_INVALID)
862 SendChatMessage(client->peer_id, line);
864 catch(con::PeerNotFoundException &e)
870 JMutexAutoLock envlock(m_env_mutex);
871 JMutexAutoLock conlock(m_con_mutex);
874 Execute script shutdown hooks
876 m_script->on_shutdown();
880 JMutexAutoLock envlock(m_env_mutex);
885 infostream<<"Server: Saving players"<<std::endl;
886 m_env->serializePlayers(m_path_world);
889 Save environment metadata
891 infostream<<"Server: Saving environment metadata"<<std::endl;
892 m_env->saveMeta(m_path_world);
900 //shutdown all emerge threads first!
907 JMutexAutoLock clientslock(m_con_mutex);
909 for(std::map<u16, RemoteClient*>::iterator
910 i = m_clients.begin();
911 i != m_clients.end(); ++i)
919 // Delete things in the reverse order of creation
927 // Deinitialize scripting
928 infostream<<"Server: Deinitializing scripting"<<std::endl;
931 // Delete detached inventories
933 for(std::map<std::string, Inventory*>::iterator
934 i = m_detached_inventories.begin();
935 i != m_detached_inventories.end(); i++){
941 void Server::start(unsigned short port)
943 DSTACK(__FUNCTION_NAME);
944 infostream<<"Starting server on port "<<port<<"..."<<std::endl;
946 // Stop thread if already running
949 // Initialize connection
950 m_con.SetTimeoutMs(30);
954 m_thread.setRun(true);
957 // ASCII art for the win!
959 <<" .__ __ __ "<<std::endl
960 <<" _____ |__| ____ _____/ |_ ____ _______/ |_ "<<std::endl
961 <<" / \\| |/ \\_/ __ \\ __\\/ __ \\ / ___/\\ __\\"<<std::endl
962 <<"| Y Y \\ | | \\ ___/| | \\ ___/ \\___ \\ | | "<<std::endl
963 <<"|__|_| /__|___| /\\___ >__| \\___ >____ > |__| "<<std::endl
964 <<" \\/ \\/ \\/ \\/ \\/ "<<std::endl;
965 actionstream<<"World at ["<<m_path_world<<"]"<<std::endl;
966 actionstream<<"Server for gameid=\""<<m_gamespec.id
967 <<"\" listening on port "<<port<<"."<<std::endl;
972 DSTACK(__FUNCTION_NAME);
974 infostream<<"Server: Stopping and waiting threads"<<std::endl;
976 // Stop threads (set run=false first so both start stopping)
977 m_thread.setRun(false);
978 //m_emergethread.setRun(false);
980 //m_emergethread.stop();
982 infostream<<"Server: Threads stopped"<<std::endl;
985 void Server::step(float dtime)
987 DSTACK(__FUNCTION_NAME);
992 JMutexAutoLock lock(m_step_dtime_mutex);
993 m_step_dtime += dtime;
995 // Throw if fatal error occurred in thread
996 std::string async_err = m_async_fatal_error.get();
998 throw ServerError(async_err);
1002 void Server::AsyncRunStep()
1004 DSTACK(__FUNCTION_NAME);
1006 g_profiler->add("Server::AsyncRunStep (num)", 1);
1010 JMutexAutoLock lock1(m_step_dtime_mutex);
1011 dtime = m_step_dtime;
1015 // Send blocks to clients
1022 g_profiler->add("Server::AsyncRunStep with dtime (num)", 1);
1024 //infostream<<"Server steps "<<dtime<<std::endl;
1025 //infostream<<"Server::AsyncRunStep(): dtime="<<dtime<<std::endl;
1028 JMutexAutoLock lock1(m_step_dtime_mutex);
1029 m_step_dtime -= dtime;
1036 m_uptime.set(m_uptime.get() + dtime);
1040 // Process connection's timeouts
1041 JMutexAutoLock lock2(m_con_mutex);
1042 ScopeProfiler sp(g_profiler, "Server: connection timeout processing");
1043 m_con.RunTimeouts(dtime);
1047 // This has to be called so that the client list gets synced
1048 // with the peer list of the connection
1049 handlePeerChanges();
1053 Update time of day and overall game time
1056 JMutexAutoLock envlock(m_env_mutex);
1058 m_env->setTimeOfDaySpeed(g_settings->getFloat("time_speed"));
1061 Send to clients at constant intervals
1064 m_time_of_day_send_timer -= dtime;
1065 if(m_time_of_day_send_timer < 0.0)
1067 m_time_of_day_send_timer = g_settings->getFloat("time_send_interval");
1069 //JMutexAutoLock envlock(m_env_mutex);
1070 JMutexAutoLock conlock(m_con_mutex);
1072 for(std::map<u16, RemoteClient*>::iterator
1073 i = m_clients.begin();
1074 i != m_clients.end(); ++i)
1076 RemoteClient *client = i->second;
1077 SharedBuffer<u8> data = makePacket_TOCLIENT_TIME_OF_DAY(
1078 m_env->getTimeOfDay(), g_settings->getFloat("time_speed"));
1080 m_con.Send(client->peer_id, 0, data, true);
1086 JMutexAutoLock lock(m_env_mutex);
1088 ScopeProfiler sp(g_profiler, "SEnv step");
1089 ScopeProfiler sp2(g_profiler, "SEnv step avg", SPT_AVG);
1093 const float map_timer_and_unload_dtime = 2.92;
1094 if(m_map_timer_and_unload_interval.step(dtime, map_timer_and_unload_dtime))
1096 JMutexAutoLock lock(m_env_mutex);
1097 // Run Map's timers and unload unused data
1098 ScopeProfiler sp(g_profiler, "Server: map timer and unload");
1099 m_env->getMap().timerUpdate(map_timer_and_unload_dtime,
1100 g_settings->getFloat("server_unload_unused_data_timeout"));
1111 JMutexAutoLock lock(m_env_mutex);
1112 JMutexAutoLock lock2(m_con_mutex);
1114 ScopeProfiler sp(g_profiler, "Server: handle players");
1116 for(std::map<u16, RemoteClient*>::iterator
1117 i = m_clients.begin();
1118 i != m_clients.end(); ++i)
1120 RemoteClient *client = i->second;
1121 PlayerSAO *playersao = getPlayerSAO(client->peer_id);
1122 if(playersao == NULL)
1126 Handle player HPs (die if hp=0)
1128 if(playersao->m_hp_not_sent && g_settings->getBool("enable_damage"))
1130 if(playersao->getHP() == 0)
1131 DiePlayer(client->peer_id);
1133 SendPlayerHP(client->peer_id);
1137 Send player inventories if necessary
1139 if(playersao->m_moved){
1140 SendMovePlayer(client->peer_id);
1141 playersao->m_moved = false;
1143 if(playersao->m_inventory_not_sent){
1144 UpdateCrafting(client->peer_id);
1145 SendInventory(client->peer_id);
1150 /* Transform liquids */
1151 m_liquid_transform_timer += dtime;
1152 if(m_liquid_transform_timer >= m_liquid_transform_every)
1154 m_liquid_transform_timer -= m_liquid_transform_every;
1156 JMutexAutoLock lock(m_env_mutex);
1158 ScopeProfiler sp(g_profiler, "Server: liquid transform");
1160 std::map<v3s16, MapBlock*> modified_blocks;
1161 m_env->getMap().transformLiquids(modified_blocks);
1166 core::map<v3s16, MapBlock*> lighting_modified_blocks;
1167 ServerMap &map = ((ServerMap&)m_env->getMap());
1168 map.updateLighting(modified_blocks, lighting_modified_blocks);
1170 // Add blocks modified by lighting to modified_blocks
1171 for(core::map<v3s16, MapBlock*>::Iterator
1172 i = lighting_modified_blocks.getIterator();
1173 i.atEnd() == false; i++)
1175 MapBlock *block = i.getNode()->getValue();
1176 modified_blocks.insert(block->getPos(), block);
1180 Set the modified blocks unsent for all the clients
1183 JMutexAutoLock lock2(m_con_mutex);
1185 for(std::map<u16, RemoteClient*>::iterator
1186 i = m_clients.begin();
1187 i != m_clients.end(); ++i)
1189 RemoteClient *client = i->second;
1191 if(modified_blocks.size() > 0)
1193 // Remove block from sent history
1194 client->SetBlocksNotSent(modified_blocks);
1199 // Periodically print some info
1201 float &counter = m_print_info_timer;
1207 JMutexAutoLock lock2(m_con_mutex);
1208 m_clients_number = 0;
1209 if(m_clients.size() != 0)
1210 infostream<<"Players:"<<std::endl;
1211 for(std::map<u16, RemoteClient*>::iterator
1212 i = m_clients.begin();
1213 i != m_clients.end(); ++i)
1215 //u16 peer_id = i.getNode()->getKey();
1216 RemoteClient *client = i->second;
1217 Player *player = m_env->getPlayer(client->peer_id);
1220 infostream<<"* "<<player->getName()<<"\t";
1221 client->PrintInfo(infostream);
1229 // send masterserver announce
1231 float &counter = m_masterserver_timer;
1232 if((!counter || counter >= 300.0) && g_settings->getBool("server_announce") == true)
1234 ServerList::sendAnnounce(!counter ? "start" : "update", m_clients_number, m_uptime.get(), m_gamespec.id);
1241 //if(g_settings->getBool("enable_experimental"))
1245 Check added and deleted active objects
1248 //infostream<<"Server: Checking added and deleted active objects"<<std::endl;
1249 JMutexAutoLock envlock(m_env_mutex);
1250 JMutexAutoLock conlock(m_con_mutex);
1252 ScopeProfiler sp(g_profiler, "Server: checking added and deleted objs");
1254 // Radius inside which objects are active
1255 s16 radius = g_settings->getS16("active_object_send_range_blocks");
1256 radius *= MAP_BLOCKSIZE;
1258 for(std::map<u16, RemoteClient*>::iterator
1259 i = m_clients.begin();
1260 i != m_clients.end(); ++i)
1262 RemoteClient *client = i->second;
1264 // If definitions and textures have not been sent, don't
1265 // send objects either
1266 if(!client->definitions_sent)
1269 Player *player = m_env->getPlayer(client->peer_id);
1272 // This can happen if the client timeouts somehow
1273 /*infostream<<"WARNING: "<<__FUNCTION_NAME<<": Client "
1275 <<" has no associated player"<<std::endl;*/
1278 v3s16 pos = floatToInt(player->getPosition(), BS);
1280 std::set<u16> removed_objects;
1281 std::set<u16> added_objects;
1282 m_env->getRemovedActiveObjects(pos, radius,
1283 client->m_known_objects, removed_objects);
1284 m_env->getAddedActiveObjects(pos, radius,
1285 client->m_known_objects, added_objects);
1287 // Ignore if nothing happened
1288 if(removed_objects.size() == 0 && added_objects.size() == 0)
1290 //infostream<<"active objects: none changed"<<std::endl;
1294 std::string data_buffer;
1298 // Handle removed objects
1299 writeU16((u8*)buf, removed_objects.size());
1300 data_buffer.append(buf, 2);
1301 for(std::set<u16>::iterator
1302 i = removed_objects.begin();
1303 i != removed_objects.end(); ++i)
1307 ServerActiveObject* obj = m_env->getActiveObject(id);
1309 // Add to data buffer for sending
1310 writeU16((u8*)buf, id);
1311 data_buffer.append(buf, 2);
1313 // Remove from known objects
1314 client->m_known_objects.erase(id);
1316 if(obj && obj->m_known_by_count > 0)
1317 obj->m_known_by_count--;
1320 // Handle added objects
1321 writeU16((u8*)buf, added_objects.size());
1322 data_buffer.append(buf, 2);
1323 for(std::set<u16>::iterator
1324 i = added_objects.begin();
1325 i != added_objects.end(); ++i)
1329 ServerActiveObject* obj = m_env->getActiveObject(id);
1332 u8 type = ACTIVEOBJECT_TYPE_INVALID;
1334 infostream<<"WARNING: "<<__FUNCTION_NAME
1335 <<": NULL object"<<std::endl;
1337 type = obj->getSendType();
1339 // Add to data buffer for sending
1340 writeU16((u8*)buf, id);
1341 data_buffer.append(buf, 2);
1342 writeU8((u8*)buf, type);
1343 data_buffer.append(buf, 1);
1346 data_buffer.append(serializeLongString(
1347 obj->getClientInitializationData(client->net_proto_version)));
1349 data_buffer.append(serializeLongString(""));
1351 // Add to known objects
1352 client->m_known_objects.insert(id);
1355 obj->m_known_by_count++;
1359 SharedBuffer<u8> reply(2 + data_buffer.size());
1360 writeU16(&reply[0], TOCLIENT_ACTIVE_OBJECT_REMOVE_ADD);
1361 memcpy((char*)&reply[2], data_buffer.c_str(),
1362 data_buffer.size());
1364 m_con.Send(client->peer_id, 0, reply, true);
1366 verbosestream<<"Server: Sent object remove/add: "
1367 <<removed_objects.size()<<" removed, "
1368 <<added_objects.size()<<" added, "
1369 <<"packet size is "<<reply.getSize()<<std::endl;
1374 Collect a list of all the objects known by the clients
1375 and report it back to the environment.
1378 core::map<u16, bool> all_known_objects;
1380 for(core::map<u16, RemoteClient*>::Iterator
1381 i = m_clients.getIterator();
1382 i.atEnd() == false; i++)
1384 RemoteClient *client = i.getNode()->getValue();
1385 // Go through all known objects of client
1386 for(core::map<u16, bool>::Iterator
1387 i = client->m_known_objects.getIterator();
1388 i.atEnd()==false; i++)
1390 u16 id = i.getNode()->getKey();
1391 all_known_objects[id] = true;
1395 m_env->setKnownActiveObjects(whatever);
1401 Send object messages
1404 JMutexAutoLock envlock(m_env_mutex);
1405 JMutexAutoLock conlock(m_con_mutex);
1407 ScopeProfiler sp(g_profiler, "Server: sending object messages");
1410 // Value = data sent by object
1411 std::map<u16, std::list<ActiveObjectMessage>* > buffered_messages;
1413 // Get active object messages from environment
1416 ActiveObjectMessage aom = m_env->getActiveObjectMessage();
1420 std::list<ActiveObjectMessage>* message_list = NULL;
1421 std::map<u16, std::list<ActiveObjectMessage>* >::iterator n;
1422 n = buffered_messages.find(aom.id);
1423 if(n == buffered_messages.end())
1425 message_list = new std::list<ActiveObjectMessage>;
1426 buffered_messages[aom.id] = message_list;
1430 message_list = n->second;
1432 message_list->push_back(aom);
1435 // Route data to every client
1436 for(std::map<u16, RemoteClient*>::iterator
1437 i = m_clients.begin();
1438 i != m_clients.end(); ++i)
1440 RemoteClient *client = i->second;
1441 std::string reliable_data;
1442 std::string unreliable_data;
1443 // Go through all objects in message buffer
1444 for(std::map<u16, std::list<ActiveObjectMessage>* >::iterator
1445 j = buffered_messages.begin();
1446 j != buffered_messages.end(); ++j)
1448 // If object is not known by client, skip it
1450 if(client->m_known_objects.find(id) == client->m_known_objects.end())
1452 // Get message list of object
1453 std::list<ActiveObjectMessage>* list = j->second;
1454 // Go through every message
1455 for(std::list<ActiveObjectMessage>::iterator
1456 k = list->begin(); k != list->end(); ++k)
1458 // Compose the full new data with header
1459 ActiveObjectMessage aom = *k;
1460 std::string new_data;
1463 writeU16((u8*)&buf[0], aom.id);
1464 new_data.append(buf, 2);
1466 new_data += serializeString(aom.datastring);
1467 // Add data to buffer
1469 reliable_data += new_data;
1471 unreliable_data += new_data;
1475 reliable_data and unreliable_data are now ready.
1478 if(reliable_data.size() > 0)
1480 SharedBuffer<u8> reply(2 + reliable_data.size());
1481 writeU16(&reply[0], TOCLIENT_ACTIVE_OBJECT_MESSAGES);
1482 memcpy((char*)&reply[2], reliable_data.c_str(),
1483 reliable_data.size());
1485 m_con.Send(client->peer_id, 0, reply, true);
1487 if(unreliable_data.size() > 0)
1489 SharedBuffer<u8> reply(2 + unreliable_data.size());
1490 writeU16(&reply[0], TOCLIENT_ACTIVE_OBJECT_MESSAGES);
1491 memcpy((char*)&reply[2], unreliable_data.c_str(),
1492 unreliable_data.size());
1493 // Send as unreliable
1494 m_con.Send(client->peer_id, 0, reply, false);
1497 /*if(reliable_data.size() > 0 || unreliable_data.size() > 0)
1499 infostream<<"Server: Size of object message data: "
1500 <<"reliable: "<<reliable_data.size()
1501 <<", unreliable: "<<unreliable_data.size()
1506 // Clear buffered_messages
1507 for(std::map<u16, std::list<ActiveObjectMessage>* >::iterator
1508 i = buffered_messages.begin();
1509 i != buffered_messages.end(); ++i)
1515 } // enable_experimental
1518 Send queued-for-sending map edit events.
1521 // We will be accessing the environment and the connection
1522 JMutexAutoLock lock(m_env_mutex);
1523 JMutexAutoLock conlock(m_con_mutex);
1525 // Don't send too many at a time
1528 // Single change sending is disabled if queue size is not small
1529 bool disable_single_change_sending = false;
1530 if(m_unsent_map_edit_queue.size() >= 4)
1531 disable_single_change_sending = true;
1533 int event_count = m_unsent_map_edit_queue.size();
1535 // We'll log the amount of each
1538 while(m_unsent_map_edit_queue.size() != 0)
1540 MapEditEvent* event = m_unsent_map_edit_queue.pop_front();
1542 // Players far away from the change are stored here.
1543 // Instead of sending the changes, MapBlocks are set not sent
1545 std::list<u16> far_players;
1547 if(event->type == MEET_ADDNODE)
1549 //infostream<<"Server: MEET_ADDNODE"<<std::endl;
1550 prof.add("MEET_ADDNODE", 1);
1551 if(disable_single_change_sending)
1552 sendAddNode(event->p, event->n, event->already_known_by_peer,
1555 sendAddNode(event->p, event->n, event->already_known_by_peer,
1558 else if(event->type == MEET_REMOVENODE)
1560 //infostream<<"Server: MEET_REMOVENODE"<<std::endl;
1561 prof.add("MEET_REMOVENODE", 1);
1562 if(disable_single_change_sending)
1563 sendRemoveNode(event->p, event->already_known_by_peer,
1566 sendRemoveNode(event->p, event->already_known_by_peer,
1569 else if(event->type == MEET_BLOCK_NODE_METADATA_CHANGED)
1571 infostream<<"Server: MEET_BLOCK_NODE_METADATA_CHANGED"<<std::endl;
1572 prof.add("MEET_BLOCK_NODE_METADATA_CHANGED", 1);
1573 setBlockNotSent(event->p);
1575 else if(event->type == MEET_OTHER)
1577 infostream<<"Server: MEET_OTHER"<<std::endl;
1578 prof.add("MEET_OTHER", 1);
1579 for(std::set<v3s16>::iterator
1580 i = event->modified_blocks.begin();
1581 i != event->modified_blocks.end(); ++i)
1583 setBlockNotSent(*i);
1588 prof.add("unknown", 1);
1589 infostream<<"WARNING: Server: Unknown MapEditEvent "
1590 <<((u32)event->type)<<std::endl;
1594 Set blocks not sent to far players
1596 if(far_players.size() > 0)
1598 // Convert list format to that wanted by SetBlocksNotSent
1599 std::map<v3s16, MapBlock*> modified_blocks2;
1600 for(std::set<v3s16>::iterator
1601 i = event->modified_blocks.begin();
1602 i != event->modified_blocks.end(); ++i)
1604 modified_blocks2[*i] =
1605 m_env->getMap().getBlockNoCreateNoEx(*i);
1607 // Set blocks not sent
1608 for(std::list<u16>::iterator
1609 i = far_players.begin();
1610 i != far_players.end(); ++i)
1613 RemoteClient *client = getClient(peer_id);
1616 client->SetBlocksNotSent(modified_blocks2);
1622 /*// Don't send too many at a time
1624 if(count >= 1 && m_unsent_map_edit_queue.size() < 100)
1628 if(event_count >= 5){
1629 infostream<<"Server: MapEditEvents:"<<std::endl;
1630 prof.print(infostream);
1631 } else if(event_count != 0){
1632 verbosestream<<"Server: MapEditEvents:"<<std::endl;
1633 prof.print(verbosestream);
1639 Trigger emergethread (it somehow gets to a non-triggered but
1640 bysy state sometimes)
1643 float &counter = m_emergethread_trigger_timer;
1649 for (unsigned int i = 0; i != m_emerge->emergethread.size(); i++)
1650 m_emerge->emergethread[i]->trigger();
1652 // Update m_enable_rollback_recording here too
1653 m_enable_rollback_recording =
1654 g_settings->getBool("enable_rollback_recording");
1658 // Save map, players and auth stuff
1660 float &counter = m_savemap_timer;
1662 if(counter >= g_settings->getFloat("server_map_save_interval"))
1665 JMutexAutoLock lock(m_env_mutex);
1667 ScopeProfiler sp(g_profiler, "Server: saving stuff");
1670 if(m_banmanager.isModified())
1671 m_banmanager.save();
1673 // Save changed parts of map
1674 m_env->getMap().save(MOD_STATE_WRITE_NEEDED);
1677 m_env->serializePlayers(m_path_world);
1679 // Save environment metadata
1680 m_env->saveMeta(m_path_world);
1685 void Server::Receive()
1687 DSTACK(__FUNCTION_NAME);
1688 SharedBuffer<u8> data;
1693 JMutexAutoLock conlock(m_con_mutex);
1694 datasize = m_con.Receive(peer_id, data);
1697 // This has to be called so that the client list gets synced
1698 // with the peer list of the connection
1699 handlePeerChanges();
1701 ProcessData(*data, datasize, peer_id);
1703 catch(con::InvalidIncomingDataException &e)
1705 infostream<<"Server::Receive(): "
1706 "InvalidIncomingDataException: what()="
1707 <<e.what()<<std::endl;
1709 catch(con::PeerNotFoundException &e)
1711 //NOTE: This is not needed anymore
1713 // The peer has been disconnected.
1714 // Find the associated player and remove it.
1716 /*JMutexAutoLock envlock(m_env_mutex);
1718 infostream<<"ServerThread: peer_id="<<peer_id
1719 <<" has apparently closed connection. "
1720 <<"Removing player."<<std::endl;
1722 m_env->removePlayer(peer_id);*/
1726 void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
1728 DSTACK(__FUNCTION_NAME);
1729 // Environment is locked first.
1730 JMutexAutoLock envlock(m_env_mutex);
1731 JMutexAutoLock conlock(m_con_mutex);
1733 ScopeProfiler sp(g_profiler, "Server::ProcessData");
1736 Address address = m_con.GetPeerAddress(peer_id);
1737 std::string addr_s = address.serializeString();
1739 // drop player if is ip is banned
1740 if(m_banmanager.isIpBanned(addr_s)){
1741 infostream<<"Server: A banned client tried to connect from "
1742 <<addr_s<<"; banned name was "
1743 <<m_banmanager.getBanName(addr_s)<<std::endl;
1744 // This actually doesn't seem to transfer to the client
1745 SendAccessDenied(m_con, peer_id,
1746 L"Your ip is banned. Banned name was "
1747 +narrow_to_wide(m_banmanager.getBanName(addr_s)));
1748 m_con.DeletePeer(peer_id);
1752 catch(con::PeerNotFoundException &e)
1754 infostream<<"Server::ProcessData(): Cancelling: peer "
1755 <<peer_id<<" not found"<<std::endl;
1759 std::string addr_s = m_con.GetPeerAddress(peer_id).serializeString();
1761 u8 peer_ser_ver = getClient(peer_id)->serialization_version;
1769 ToServerCommand command = (ToServerCommand)readU16(&data[0]);
1771 if(command == TOSERVER_INIT)
1773 // [0] u16 TOSERVER_INIT
1774 // [2] u8 SER_FMT_VER_HIGHEST
1775 // [3] u8[20] player_name
1776 // [23] u8[28] password <--- can be sent without this, from old versions
1778 if(datasize < 2+1+PLAYERNAME_SIZE)
1781 verbosestream<<"Server: Got TOSERVER_INIT from "
1782 <<peer_id<<std::endl;
1784 // First byte after command is maximum supported
1785 // serialization version
1786 u8 client_max = data[2];
1787 u8 our_max = SER_FMT_VER_HIGHEST;
1788 // Use the highest version supported by both
1789 u8 deployed = std::min(client_max, our_max);
1790 // If it's lower than the lowest supported, give up.
1791 if(deployed < SER_FMT_VER_LOWEST)
1792 deployed = SER_FMT_VER_INVALID;
1794 //peer->serialization_version = deployed;
1795 getClient(peer_id)->pending_serialization_version = deployed;
1797 if(deployed == SER_FMT_VER_INVALID)
1799 actionstream<<"Server: A mismatched client tried to connect from "
1800 <<addr_s<<std::endl;
1801 infostream<<"Server: Cannot negotiate "
1802 "serialization version with peer "
1803 <<peer_id<<std::endl;
1804 SendAccessDenied(m_con, peer_id, std::wstring(
1805 L"Your client's version is not supported.\n"
1806 L"Server version is ")
1807 + narrow_to_wide(VERSION_STRING) + L"."
1813 Read and check network protocol version
1816 u16 min_net_proto_version = 0;
1817 if(datasize >= 2+1+PLAYERNAME_SIZE+PASSWORD_SIZE+2)
1818 min_net_proto_version = readU16(&data[2+1+PLAYERNAME_SIZE+PASSWORD_SIZE]);
1820 // Use same version as minimum and maximum if maximum version field
1821 // doesn't exist (backwards compatibility)
1822 u16 max_net_proto_version = min_net_proto_version;
1823 if(datasize >= 2+1+PLAYERNAME_SIZE+PASSWORD_SIZE+2+2)
1824 max_net_proto_version = readU16(&data[2+1+PLAYERNAME_SIZE+PASSWORD_SIZE+2]);
1826 // Start with client's maximum version
1827 u16 net_proto_version = max_net_proto_version;
1829 // Figure out a working version if it is possible at all
1830 if(max_net_proto_version >= SERVER_PROTOCOL_VERSION_MIN ||
1831 min_net_proto_version <= SERVER_PROTOCOL_VERSION_MAX)
1833 // If maximum is larger than our maximum, go with our maximum
1834 if(max_net_proto_version > SERVER_PROTOCOL_VERSION_MAX)
1835 net_proto_version = SERVER_PROTOCOL_VERSION_MAX;
1836 // Else go with client's maximum
1838 net_proto_version = max_net_proto_version;
1841 verbosestream<<"Server: "<<peer_id<<" Protocol version: min: "
1842 <<min_net_proto_version<<", max: "<<max_net_proto_version
1843 <<", chosen: "<<net_proto_version<<std::endl;
1845 getClient(peer_id)->net_proto_version = net_proto_version;
1847 if(net_proto_version < SERVER_PROTOCOL_VERSION_MIN ||
1848 net_proto_version > SERVER_PROTOCOL_VERSION_MAX)
1850 actionstream<<"Server: A mismatched client tried to connect from "<<addr_s
1852 SendAccessDenied(m_con, peer_id, std::wstring(
1853 L"Your client's version is not supported.\n"
1854 L"Server version is ")
1855 + narrow_to_wide(VERSION_STRING) + L",\n"
1856 + L"server's PROTOCOL_VERSION is "
1857 + narrow_to_wide(itos(SERVER_PROTOCOL_VERSION_MIN))
1859 + narrow_to_wide(itos(SERVER_PROTOCOL_VERSION_MAX))
1860 + L", client's PROTOCOL_VERSION is "
1861 + narrow_to_wide(itos(min_net_proto_version))
1863 + narrow_to_wide(itos(max_net_proto_version))
1868 if(g_settings->getBool("strict_protocol_version_checking"))
1870 if(net_proto_version != LATEST_PROTOCOL_VERSION)
1872 actionstream<<"Server: A mismatched (strict) client tried to "
1873 <<"connect from "<<addr_s<<std::endl;
1874 SendAccessDenied(m_con, peer_id, std::wstring(
1875 L"Your client's version is not supported.\n"
1876 L"Server version is ")
1877 + narrow_to_wide(VERSION_STRING) + L",\n"
1878 + L"server's PROTOCOL_VERSION (strict) is "
1879 + narrow_to_wide(itos(LATEST_PROTOCOL_VERSION))
1880 + L", client's PROTOCOL_VERSION is "
1881 + narrow_to_wide(itos(min_net_proto_version))
1883 + narrow_to_wide(itos(max_net_proto_version))
1894 char playername[PLAYERNAME_SIZE];
1895 for(u32 i=0; i<PLAYERNAME_SIZE-1; i++)
1897 playername[i] = data[3+i];
1899 playername[PLAYERNAME_SIZE-1] = 0;
1901 if(playername[0]=='\0')
1903 actionstream<<"Server: Player with an empty name "
1904 <<"tried to connect from "<<addr_s<<std::endl;
1905 SendAccessDenied(m_con, peer_id,
1910 if(string_allowed(playername, PLAYERNAME_ALLOWED_CHARS)==false)
1912 actionstream<<"Server: Player with an invalid name "
1913 <<"tried to connect from "<<addr_s<<std::endl;
1914 SendAccessDenied(m_con, peer_id,
1915 L"Name contains unallowed characters");
1919 infostream<<"Server: New connection: \""<<playername<<"\" from "
1920 <<m_con.GetPeerAddress(peer_id).serializeString()<<std::endl;
1923 char given_password[PASSWORD_SIZE];
1924 if(datasize < 2+1+PLAYERNAME_SIZE+PASSWORD_SIZE)
1926 // old version - assume blank password
1927 given_password[0] = 0;
1931 for(u32 i=0; i<PASSWORD_SIZE-1; i++)
1933 given_password[i] = data[23+i];
1935 given_password[PASSWORD_SIZE-1] = 0;
1938 if(!base64_is_valid(given_password)){
1939 infostream<<"Server: "<<playername
1940 <<" supplied invalid password hash"<<std::endl;
1941 SendAccessDenied(m_con, peer_id, L"Invalid password hash");
1945 std::string checkpwd; // Password hash to check against
1946 bool has_auth = m_script->getAuth(playername, &checkpwd, NULL);
1948 // If no authentication info exists for user, create it
1950 if(!isSingleplayer() &&
1951 g_settings->getBool("disallow_empty_password") &&
1952 std::string(given_password) == ""){
1953 SendAccessDenied(m_con, peer_id, L"Empty passwords are "
1954 L"disallowed. Set a password and try again.");
1957 std::wstring raw_default_password =
1958 narrow_to_wide(g_settings->get("default_password"));
1959 std::string initial_password =
1960 translatePassword(playername, raw_default_password);
1962 // If default_password is empty, allow any initial password
1963 if (raw_default_password.length() == 0)
1964 initial_password = given_password;
1966 m_script->createAuth(playername, initial_password);
1969 has_auth = m_script->getAuth(playername, &checkpwd, NULL);
1972 SendAccessDenied(m_con, peer_id, L"Not allowed to login");
1976 if(given_password != checkpwd){
1977 infostream<<"Server: peer_id="<<peer_id
1978 <<": supplied invalid password for "
1979 <<playername<<std::endl;
1980 SendAccessDenied(m_con, peer_id, L"Invalid password");
1984 // Do not allow multiple players in simple singleplayer mode.
1985 // This isn't a perfect way to do it, but will suffice for now.
1986 if(m_simple_singleplayer_mode && m_clients.size() > 1){
1987 infostream<<"Server: Not allowing another client to connect in"
1988 <<" simple singleplayer mode"<<std::endl;
1989 SendAccessDenied(m_con, peer_id,
1990 L"Running in simple singleplayer mode.");
1994 // Enforce user limit.
1995 // Don't enforce for users that have some admin right
1996 if(m_clients.size() >= g_settings->getU16("max_users") &&
1997 !checkPriv(playername, "server") &&
1998 !checkPriv(playername, "ban") &&
1999 !checkPriv(playername, "privs") &&
2000 !checkPriv(playername, "password") &&
2001 playername != g_settings->get("name"))
2003 actionstream<<"Server: "<<playername<<" tried to join, but there"
2004 <<" are already max_users="
2005 <<g_settings->getU16("max_users")<<" players."<<std::endl;
2006 SendAccessDenied(m_con, peer_id, L"Too many users.");
2011 PlayerSAO *playersao = emergePlayer(playername, peer_id);
2013 // If failed, cancel
2014 if(playersao == NULL)
2016 errorstream<<"Server: peer_id="<<peer_id
2017 <<": failed to emerge player"<<std::endl;
2022 Answer with a TOCLIENT_INIT
2025 SharedBuffer<u8> reply(2+1+6+8+4);
2026 writeU16(&reply[0], TOCLIENT_INIT);
2027 writeU8(&reply[2], deployed);
2028 writeV3S16(&reply[2+1], floatToInt(playersao->getPlayer()->getPosition()+v3f(0,BS/2,0), BS));
2029 writeU64(&reply[2+1+6], m_env->getServerMap().getSeed());
2030 writeF1000(&reply[2+1+6+8], g_settings->getFloat("dedicated_server_step"));
2033 m_con.Send(peer_id, 0, reply, true);
2037 Send complete position information
2039 SendMovePlayer(peer_id);
2044 if(command == TOSERVER_INIT2)
2046 verbosestream<<"Server: Got TOSERVER_INIT2 from "
2047 <<peer_id<<std::endl;
2049 Player *player = m_env->getPlayer(peer_id);
2051 verbosestream<<"Server: TOSERVER_INIT2: "
2052 <<"Player not found; ignoring."<<std::endl;
2056 RemoteClient *client = getClient(peer_id);
2057 client->serialization_version =
2058 getClient(peer_id)->pending_serialization_version;
2061 Send some initialization data
2064 infostream<<"Server: Sending content to "
2065 <<getPlayerName(peer_id)<<std::endl;
2067 // Send player movement settings
2068 SendMovement(m_con, peer_id);
2070 // Send item definitions
2071 SendItemDef(m_con, peer_id, m_itemdef, client->net_proto_version);
2073 // Send node definitions
2074 SendNodeDef(m_con, peer_id, m_nodedef, client->net_proto_version);
2076 // Send media announcement
2077 sendMediaAnnouncement(peer_id);
2080 SendPlayerPrivileges(peer_id);
2082 // Send inventory formspec
2083 SendPlayerInventoryFormspec(peer_id);
2086 UpdateCrafting(peer_id);
2087 SendInventory(peer_id);
2090 if(g_settings->getBool("enable_damage"))
2091 SendPlayerHP(peer_id);
2093 // Send detached inventories
2094 sendDetachedInventories(peer_id);
2096 // Show death screen if necessary
2098 SendDeathscreen(m_con, peer_id, false, v3f(0,0,0));
2102 SharedBuffer<u8> data = makePacket_TOCLIENT_TIME_OF_DAY(
2103 m_env->getTimeOfDay(), g_settings->getFloat("time_speed"));
2104 m_con.Send(peer_id, 0, data, true);
2107 // Note things in chat if not in simple singleplayer mode
2108 if(!m_simple_singleplayer_mode)
2110 // Send information about server to player in chat
2111 SendChatMessage(peer_id, getStatusString());
2113 // Send information about joining in chat
2115 std::wstring name = L"unknown";
2116 Player *player = m_env->getPlayer(peer_id);
2118 name = narrow_to_wide(player->getName());
2120 std::wstring message;
2123 message += L" joined the game.";
2124 BroadcastChatMessage(message);
2128 // Warnings about protocol version can be issued here
2129 if(getClient(peer_id)->net_proto_version < LATEST_PROTOCOL_VERSION)
2131 SendChatMessage(peer_id, L"# Server: WARNING: YOUR CLIENT'S "
2132 L"VERSION MAY NOT BE FULLY COMPATIBLE WITH THIS SERVER!");
2139 std::ostringstream os(std::ios_base::binary);
2140 for(std::map<u16, RemoteClient*>::iterator
2141 i = m_clients.begin();
2142 i != m_clients.end(); ++i)
2144 RemoteClient *client = i->second;
2145 assert(client->peer_id == i->first);
2146 if(client->serialization_version == SER_FMT_VER_INVALID)
2149 Player *player = m_env->getPlayer(client->peer_id);
2152 // Get name of player
2153 os<<player->getName()<<" ";
2156 actionstream<<player->getName()<<" joins game. List of players: "
2157 <<os.str()<<std::endl;
2163 if(peer_ser_ver == SER_FMT_VER_INVALID)
2165 infostream<<"Server::ProcessData(): Cancelling: Peer"
2166 " serialization format invalid or not initialized."
2167 " Skipping incoming command="<<command<<std::endl;
2171 Player *player = m_env->getPlayer(peer_id);
2173 infostream<<"Server::ProcessData(): Cancelling: "
2174 "No player for peer_id="<<peer_id
2179 PlayerSAO *playersao = player->getPlayerSAO();
2180 if(playersao == NULL){
2181 infostream<<"Server::ProcessData(): Cancelling: "
2182 "No player object for peer_id="<<peer_id
2187 if(command == TOSERVER_PLAYERPOS)
2189 if(datasize < 2+12+12+4+4)
2193 v3s32 ps = readV3S32(&data[start+2]);
2194 v3s32 ss = readV3S32(&data[start+2+12]);
2195 f32 pitch = (f32)readS32(&data[2+12+12]) / 100.0;
2196 f32 yaw = (f32)readS32(&data[2+12+12+4]) / 100.0;
2198 if(datasize >= 2+12+12+4+4+4)
2199 keyPressed = (u32)readU32(&data[2+12+12+4+4]);
2200 v3f position((f32)ps.X/100., (f32)ps.Y/100., (f32)ps.Z/100.);
2201 v3f speed((f32)ss.X/100., (f32)ss.Y/100., (f32)ss.Z/100.);
2202 pitch = wrapDegrees(pitch);
2203 yaw = wrapDegrees(yaw);
2205 player->setPosition(position);
2206 player->setSpeed(speed);
2207 player->setPitch(pitch);
2208 player->setYaw(yaw);
2209 player->keyPressed=keyPressed;
2210 player->control.up = (bool)(keyPressed&1);
2211 player->control.down = (bool)(keyPressed&2);
2212 player->control.left = (bool)(keyPressed&4);
2213 player->control.right = (bool)(keyPressed&8);
2214 player->control.jump = (bool)(keyPressed&16);
2215 player->control.aux1 = (bool)(keyPressed&32);
2216 player->control.sneak = (bool)(keyPressed&64);
2217 player->control.LMB = (bool)(keyPressed&128);
2218 player->control.RMB = (bool)(keyPressed&256);
2220 /*infostream<<"Server::ProcessData(): Moved player "<<peer_id<<" to "
2221 <<"("<<position.X<<","<<position.Y<<","<<position.Z<<")"
2222 <<" pitch="<<pitch<<" yaw="<<yaw<<std::endl;*/
2224 else if(command == TOSERVER_GOTBLOCKS)
2237 u16 count = data[2];
2238 for(u16 i=0; i<count; i++)
2240 if((s16)datasize < 2+1+(i+1)*6)
2241 throw con::InvalidIncomingDataException
2242 ("GOTBLOCKS length is too short");
2243 v3s16 p = readV3S16(&data[2+1+i*6]);
2244 /*infostream<<"Server: GOTBLOCKS ("
2245 <<p.X<<","<<p.Y<<","<<p.Z<<")"<<std::endl;*/
2246 RemoteClient *client = getClient(peer_id);
2247 client->GotBlock(p);
2250 else if(command == TOSERVER_DELETEDBLOCKS)
2263 u16 count = data[2];
2264 for(u16 i=0; i<count; i++)
2266 if((s16)datasize < 2+1+(i+1)*6)
2267 throw con::InvalidIncomingDataException
2268 ("DELETEDBLOCKS length is too short");
2269 v3s16 p = readV3S16(&data[2+1+i*6]);
2270 /*infostream<<"Server: DELETEDBLOCKS ("
2271 <<p.X<<","<<p.Y<<","<<p.Z<<")"<<std::endl;*/
2272 RemoteClient *client = getClient(peer_id);
2273 client->SetBlockNotSent(p);
2276 else if(command == TOSERVER_CLICK_OBJECT)
2278 infostream<<"Server: CLICK_OBJECT not supported anymore"<<std::endl;
2281 else if(command == TOSERVER_CLICK_ACTIVEOBJECT)
2283 infostream<<"Server: CLICK_ACTIVEOBJECT not supported anymore"<<std::endl;
2286 else if(command == TOSERVER_GROUND_ACTION)
2288 infostream<<"Server: GROUND_ACTION not supported anymore"<<std::endl;
2292 else if(command == TOSERVER_RELEASE)
2294 infostream<<"Server: RELEASE not supported anymore"<<std::endl;
2297 else if(command == TOSERVER_SIGNTEXT)
2299 infostream<<"Server: SIGNTEXT not supported anymore"
2303 else if(command == TOSERVER_SIGNNODETEXT)
2305 infostream<<"Server: SIGNNODETEXT not supported anymore"
2309 else if(command == TOSERVER_INVENTORY_ACTION)
2311 // Strip command and create a stream
2312 std::string datastring((char*)&data[2], datasize-2);
2313 verbosestream<<"TOSERVER_INVENTORY_ACTION: data="<<datastring<<std::endl;
2314 std::istringstream is(datastring, std::ios_base::binary);
2316 InventoryAction *a = InventoryAction::deSerialize(is);
2319 infostream<<"TOSERVER_INVENTORY_ACTION: "
2320 <<"InventoryAction::deSerialize() returned NULL"
2325 // If something goes wrong, this player is to blame
2326 RollbackScopeActor rollback_scope(m_rollback,
2327 std::string("player:")+player->getName());
2330 Note: Always set inventory not sent, to repair cases
2331 where the client made a bad prediction.
2335 Handle restrictions and special cases of the move action
2337 if(a->getType() == IACTION_MOVE)
2339 IMoveAction *ma = (IMoveAction*)a;
2341 ma->from_inv.applyCurrentPlayer(player->getName());
2342 ma->to_inv.applyCurrentPlayer(player->getName());
2344 setInventoryModified(ma->from_inv);
2345 setInventoryModified(ma->to_inv);
2347 bool from_inv_is_current_player =
2348 (ma->from_inv.type == InventoryLocation::PLAYER) &&
2349 (ma->from_inv.name == player->getName());
2351 bool to_inv_is_current_player =
2352 (ma->to_inv.type == InventoryLocation::PLAYER) &&
2353 (ma->to_inv.name == player->getName());
2356 Disable moving items out of craftpreview
2358 if(ma->from_list == "craftpreview")
2360 infostream<<"Ignoring IMoveAction from "
2361 <<(ma->from_inv.dump())<<":"<<ma->from_list
2362 <<" to "<<(ma->to_inv.dump())<<":"<<ma->to_list
2363 <<" because src is "<<ma->from_list<<std::endl;
2369 Disable moving items into craftresult and craftpreview
2371 if(ma->to_list == "craftpreview" || ma->to_list == "craftresult")
2373 infostream<<"Ignoring IMoveAction from "
2374 <<(ma->from_inv.dump())<<":"<<ma->from_list
2375 <<" to "<<(ma->to_inv.dump())<<":"<<ma->to_list
2376 <<" because dst is "<<ma->to_list<<std::endl;
2381 // Disallow moving items in elsewhere than player's inventory
2382 // if not allowed to interact
2383 if(!checkPriv(player->getName(), "interact") &&
2384 (!from_inv_is_current_player ||
2385 !to_inv_is_current_player))
2387 infostream<<"Cannot move outside of player's inventory: "
2388 <<"No interact privilege"<<std::endl;
2394 Handle restrictions and special cases of the drop action
2396 else if(a->getType() == IACTION_DROP)
2398 IDropAction *da = (IDropAction*)a;
2400 da->from_inv.applyCurrentPlayer(player->getName());
2402 setInventoryModified(da->from_inv);
2404 // Disallow dropping items if not allowed to interact
2405 if(!checkPriv(player->getName(), "interact"))
2412 Handle restrictions and special cases of the craft action
2414 else if(a->getType() == IACTION_CRAFT)
2416 ICraftAction *ca = (ICraftAction*)a;
2418 ca->craft_inv.applyCurrentPlayer(player->getName());
2420 setInventoryModified(ca->craft_inv);
2422 //bool craft_inv_is_current_player =
2423 // (ca->craft_inv.type == InventoryLocation::PLAYER) &&
2424 // (ca->craft_inv.name == player->getName());
2426 // Disallow crafting if not allowed to interact
2427 if(!checkPriv(player->getName(), "interact"))
2429 infostream<<"Cannot craft: "
2430 <<"No interact privilege"<<std::endl;
2437 a->apply(this, playersao, this);
2441 else if(command == TOSERVER_CHAT_MESSAGE)
2449 std::string datastring((char*)&data[2], datasize-2);
2450 std::istringstream is(datastring, std::ios_base::binary);
2453 is.read((char*)buf, 2);
2454 u16 len = readU16(buf);
2456 std::wstring message;
2457 for(u16 i=0; i<len; i++)
2459 is.read((char*)buf, 2);
2460 message += (wchar_t)readU16(buf);
2463 // If something goes wrong, this player is to blame
2464 RollbackScopeActor rollback_scope(m_rollback,
2465 std::string("player:")+player->getName());
2467 // Get player name of this client
2468 std::wstring name = narrow_to_wide(player->getName());
2471 bool ate = m_script->on_chat_message(player->getName(),
2472 wide_to_narrow(message));
2473 // If script ate the message, don't proceed
2477 // Line to send to players
2479 // Whether to send to the player that sent the line
2480 bool send_to_sender = false;
2481 // Whether to send to other players
2482 bool send_to_others = false;
2484 // Commands are implemented in Lua, so only catch invalid
2485 // commands that were not "eaten" and send an error back
2486 if(message[0] == L'/')
2488 message = message.substr(1);
2489 send_to_sender = true;
2490 if(message.length() == 0)
2491 line += L"-!- Empty command";
2493 line += L"-!- Invalid command: " + str_split(message, L' ')[0];
2497 if(checkPriv(player->getName(), "shout")){
2502 send_to_others = true;
2504 line += L"-!- You don't have permission to shout.";
2505 send_to_sender = true;
2512 actionstream<<"CHAT: "<<wide_to_narrow(line)<<std::endl;
2515 Send the message to clients
2517 for(std::map<u16, RemoteClient*>::iterator
2518 i = m_clients.begin();
2519 i != m_clients.end(); ++i)
2521 // Get client and check that it is valid
2522 RemoteClient *client = i->second;
2523 assert(client->peer_id == i->first);
2524 if(client->serialization_version == SER_FMT_VER_INVALID)
2528 bool sender_selected = (peer_id == client->peer_id);
2529 if(sender_selected == true && send_to_sender == false)
2531 if(sender_selected == false && send_to_others == false)
2534 SendChatMessage(client->peer_id, line);
2538 else if(command == TOSERVER_DAMAGE)
2540 std::string datastring((char*)&data[2], datasize-2);
2541 std::istringstream is(datastring, std::ios_base::binary);
2542 u8 damage = readU8(is);
2544 if(g_settings->getBool("enable_damage"))
2546 actionstream<<player->getName()<<" damaged by "
2547 <<(int)damage<<" hp at "<<PP(player->getPosition()/BS)
2550 playersao->setHP(playersao->getHP() - damage);
2552 if(playersao->getHP() == 0 && playersao->m_hp_not_sent)
2555 if(playersao->m_hp_not_sent)
2556 SendPlayerHP(peer_id);
2559 else if(command == TOSERVER_PASSWORD)
2562 [0] u16 TOSERVER_PASSWORD
2563 [2] u8[28] old password
2564 [30] u8[28] new password
2567 if(datasize != 2+PASSWORD_SIZE*2)
2569 /*char password[PASSWORD_SIZE];
2570 for(u32 i=0; i<PASSWORD_SIZE-1; i++)
2571 password[i] = data[2+i];
2572 password[PASSWORD_SIZE-1] = 0;*/
2574 for(u32 i=0; i<PASSWORD_SIZE-1; i++)
2582 for(u32 i=0; i<PASSWORD_SIZE-1; i++)
2584 char c = data[2+PASSWORD_SIZE+i];
2590 if(!base64_is_valid(newpwd)){
2591 infostream<<"Server: "<<player->getName()<<" supplied invalid password hash"<<std::endl;
2592 // Wrong old password supplied!!
2593 SendChatMessage(peer_id, L"Invalid new password hash supplied. Password NOT changed.");
2597 infostream<<"Server: Client requests a password change from "
2598 <<"'"<<oldpwd<<"' to '"<<newpwd<<"'"<<std::endl;
2600 std::string playername = player->getName();
2602 std::string checkpwd;
2603 m_script->getAuth(playername, &checkpwd, NULL);
2605 if(oldpwd != checkpwd)
2607 infostream<<"Server: invalid old password"<<std::endl;
2608 // Wrong old password supplied!!
2609 SendChatMessage(peer_id, L"Invalid old password supplied. Password NOT changed.");
2613 bool success = m_script->setPassword(playername, newpwd);
2615 actionstream<<player->getName()<<" changes password"<<std::endl;
2616 SendChatMessage(peer_id, L"Password change successful.");
2618 actionstream<<player->getName()<<" tries to change password but "
2619 <<"it fails"<<std::endl;
2620 SendChatMessage(peer_id, L"Password change failed or inavailable.");
2623 else if(command == TOSERVER_PLAYERITEM)
2628 u16 item = readU16(&data[2]);
2629 playersao->setWieldIndex(item);
2631 else if(command == TOSERVER_RESPAWN)
2633 if(player->hp != 0 || !g_settings->getBool("enable_damage"))
2636 RespawnPlayer(peer_id);
2638 actionstream<<player->getName()<<" respawns at "
2639 <<PP(player->getPosition()/BS)<<std::endl;
2641 // ActiveObject is added to environment in AsyncRunStep after
2642 // the previous addition has been succesfully removed
2644 else if(command == TOSERVER_REQUEST_MEDIA) {
2645 std::string datastring((char*)&data[2], datasize-2);
2646 std::istringstream is(datastring, std::ios_base::binary);
2648 std::list<MediaRequest> tosend;
2649 u16 numfiles = readU16(is);
2651 infostream<<"Sending "<<numfiles<<" files to "
2652 <<getPlayerName(peer_id)<<std::endl;
2653 verbosestream<<"TOSERVER_REQUEST_MEDIA: "<<std::endl;
2655 for(int i = 0; i < numfiles; i++) {
2656 std::string name = deSerializeString(is);
2657 tosend.push_back(MediaRequest(name));
2658 verbosestream<<"TOSERVER_REQUEST_MEDIA: requested file "
2662 sendRequestedMedia(peer_id, tosend);
2664 // Now the client should know about everything
2665 // (definitions and files)
2666 getClient(peer_id)->definitions_sent = true;
2668 else if(command == TOSERVER_RECEIVED_MEDIA) {
2669 getClient(peer_id)->definitions_sent = true;
2671 else if(command == TOSERVER_INTERACT)
2673 std::string datastring((char*)&data[2], datasize-2);
2674 std::istringstream is(datastring, std::ios_base::binary);
2680 [5] u32 length of the next item
2681 [9] serialized PointedThing
2683 0: start digging (from undersurface) or use
2684 1: stop digging (all parameters ignored)
2685 2: digging completed
2686 3: place block or item (to abovesurface)
2689 u8 action = readU8(is);
2690 u16 item_i = readU16(is);
2691 std::istringstream tmp_is(deSerializeLongString(is), std::ios::binary);
2692 PointedThing pointed;
2693 pointed.deSerialize(tmp_is);
2695 verbosestream<<"TOSERVER_INTERACT: action="<<(int)action<<", item="
2696 <<item_i<<", pointed="<<pointed.dump()<<std::endl;
2700 verbosestream<<"TOSERVER_INTERACT: "<<player->getName()
2701 <<" tried to interact, but is dead!"<<std::endl;
2705 v3f player_pos = playersao->getLastGoodPosition();
2707 // Update wielded item
2708 playersao->setWieldIndex(item_i);
2710 // Get pointed to node (undefined if not POINTEDTYPE_NODE)
2711 v3s16 p_under = pointed.node_undersurface;
2712 v3s16 p_above = pointed.node_abovesurface;
2714 // Get pointed to object (NULL if not POINTEDTYPE_OBJECT)
2715 ServerActiveObject *pointed_object = NULL;
2716 if(pointed.type == POINTEDTHING_OBJECT)
2718 pointed_object = m_env->getActiveObject(pointed.object_id);
2719 if(pointed_object == NULL)
2721 verbosestream<<"TOSERVER_INTERACT: "
2722 "pointed object is NULL"<<std::endl;
2728 v3f pointed_pos_under = player_pos;
2729 v3f pointed_pos_above = player_pos;
2730 if(pointed.type == POINTEDTHING_NODE)
2732 pointed_pos_under = intToFloat(p_under, BS);
2733 pointed_pos_above = intToFloat(p_above, BS);
2735 else if(pointed.type == POINTEDTHING_OBJECT)
2737 pointed_pos_under = pointed_object->getBasePosition();
2738 pointed_pos_above = pointed_pos_under;
2742 Check that target is reasonably close
2743 (only when digging or placing things)
2745 if(action == 0 || action == 2 || action == 3)
2747 float d = player_pos.getDistanceFrom(pointed_pos_under);
2748 float max_d = BS * 14; // Just some large enough value
2750 actionstream<<"Player "<<player->getName()
2751 <<" tried to access "<<pointed.dump()
2753 <<"d="<<d<<", max_d="<<max_d
2754 <<". ignoring."<<std::endl;
2755 // Re-send block to revert change on client-side
2756 RemoteClient *client = getClient(peer_id);
2757 v3s16 blockpos = getNodeBlockPos(floatToInt(pointed_pos_under, BS));
2758 client->SetBlockNotSent(blockpos);
2765 Make sure the player is allowed to do it
2767 if(!checkPriv(player->getName(), "interact"))
2769 actionstream<<player->getName()<<" attempted to interact with "
2770 <<pointed.dump()<<" without 'interact' privilege"
2772 // Re-send block to revert change on client-side
2773 RemoteClient *client = getClient(peer_id);
2774 // Digging completed -> under
2776 v3s16 blockpos = getNodeBlockPos(floatToInt(pointed_pos_under, BS));
2777 client->SetBlockNotSent(blockpos);
2779 // Placement -> above
2781 v3s16 blockpos = getNodeBlockPos(floatToInt(pointed_pos_above, BS));
2782 client->SetBlockNotSent(blockpos);
2788 If something goes wrong, this player is to blame
2790 RollbackScopeActor rollback_scope(m_rollback,
2791 std::string("player:")+player->getName());
2794 0: start digging or punch object
2798 if(pointed.type == POINTEDTHING_NODE)
2801 NOTE: This can be used in the future to check if
2802 somebody is cheating, by checking the timing.
2804 MapNode n(CONTENT_IGNORE);
2807 n = m_env->getMap().getNode(p_under);
2809 catch(InvalidPositionException &e)
2811 infostream<<"Server: Not punching: Node not found."
2812 <<" Adding block to emerge queue."
2814 m_emerge->enqueueBlockEmerge(peer_id, getNodeBlockPos(p_above), false);
2816 if(n.getContent() != CONTENT_IGNORE)
2817 m_script->node_on_punch(p_under, n, playersao);
2819 playersao->noCheatDigStart(p_under);
2821 else if(pointed.type == POINTEDTHING_OBJECT)
2823 // Skip if object has been removed
2824 if(pointed_object->m_removed)
2827 actionstream<<player->getName()<<" punches object "
2828 <<pointed.object_id<<": "
2829 <<pointed_object->getDescription()<<std::endl;
2831 ItemStack punchitem = playersao->getWieldedItem();
2832 ToolCapabilities toolcap =
2833 punchitem.getToolCapabilities(m_itemdef);
2834 v3f dir = (pointed_object->getBasePosition() -
2835 (player->getPosition() + player->getEyeOffset())
2837 float time_from_last_punch =
2838 playersao->resetTimeFromLastPunch();
2839 pointed_object->punch(dir, &toolcap, playersao,
2840 time_from_last_punch);
2848 else if(action == 1)
2853 2: Digging completed
2855 else if(action == 2)
2857 // Only digging of nodes
2858 if(pointed.type == POINTEDTHING_NODE)
2860 MapNode n(CONTENT_IGNORE);
2863 n = m_env->getMap().getNode(p_under);
2865 catch(InvalidPositionException &e)
2867 infostream<<"Server: Not finishing digging: Node not found."
2868 <<" Adding block to emerge queue."
2870 m_emerge->enqueueBlockEmerge(peer_id, getNodeBlockPos(p_above), false);
2873 /* Cheat prevention */
2874 bool is_valid_dig = true;
2875 if(!isSingleplayer() && !g_settings->getBool("disable_anticheat"))
2877 v3s16 nocheat_p = playersao->getNoCheatDigPos();
2878 float nocheat_t = playersao->getNoCheatDigTime();
2879 playersao->noCheatDigEnd();
2880 // If player didn't start digging this, ignore dig
2881 if(nocheat_p != p_under){
2882 infostream<<"Server: NoCheat: "<<player->getName()
2883 <<" started digging "
2884 <<PP(nocheat_p)<<" and completed digging "
2885 <<PP(p_under)<<"; not digging."<<std::endl;
2886 is_valid_dig = false;
2888 // Get player's wielded item
2889 ItemStack playeritem;
2890 InventoryList *mlist = playersao->getInventory()->getList("main");
2892 playeritem = mlist->getItem(playersao->getWieldIndex());
2893 ToolCapabilities playeritem_toolcap =
2894 playeritem.getToolCapabilities(m_itemdef);
2895 // Get diggability and expected digging time
2896 DigParams params = getDigParams(m_nodedef->get(n).groups,
2897 &playeritem_toolcap);
2898 // If can't dig, try hand
2899 if(!params.diggable){
2900 const ItemDefinition &hand = m_itemdef->get("");
2901 const ToolCapabilities *tp = hand.tool_capabilities;
2903 params = getDigParams(m_nodedef->get(n).groups, tp);
2905 // If can't dig, ignore dig
2906 if(!params.diggable){
2907 infostream<<"Server: NoCheat: "<<player->getName()
2908 <<" completed digging "<<PP(p_under)
2909 <<", which is not diggable with tool. not digging."
2911 is_valid_dig = false;
2913 // If time is considerably too short, ignore dig
2914 // Check time only for medium and slow timed digs
2915 if(params.diggable && params.time > 0.3 && nocheat_t < 0.5 * params.time){
2916 infostream<<"Server: NoCheat: "<<player->getName()
2917 <<" completed digging "
2918 <<PP(p_under)<<" in "<<nocheat_t<<"s; expected "
2919 <<params.time<<"s; not digging."<<std::endl;
2920 is_valid_dig = false;
2924 /* Actually dig node */
2926 if(is_valid_dig && n.getContent() != CONTENT_IGNORE)
2927 m_script->node_on_dig(p_under, n, playersao);
2929 // Send unusual result (that is, node not being removed)
2930 if(m_env->getMap().getNodeNoEx(p_under).getContent() != CONTENT_AIR)
2932 // Re-send block to revert change on client-side
2933 RemoteClient *client = getClient(peer_id);
2934 v3s16 blockpos = getNodeBlockPos(floatToInt(pointed_pos_under, BS));
2935 client->SetBlockNotSent(blockpos);
2941 3: place block or right-click object
2943 else if(action == 3)
2945 ItemStack item = playersao->getWieldedItem();
2947 // Reset build time counter
2948 if(pointed.type == POINTEDTHING_NODE &&
2949 item.getDefinition(m_itemdef).type == ITEM_NODE)
2950 getClient(peer_id)->m_time_from_building = 0.0;
2952 if(pointed.type == POINTEDTHING_OBJECT)
2954 // Right click object
2956 // Skip if object has been removed
2957 if(pointed_object->m_removed)
2960 actionstream<<player->getName()<<" right-clicks object "
2961 <<pointed.object_id<<": "
2962 <<pointed_object->getDescription()<<std::endl;
2965 pointed_object->rightClick(playersao);
2967 else if(m_script->item_OnPlace(
2968 item, playersao, pointed))
2970 // Placement was handled in lua
2972 // Apply returned ItemStack
2973 playersao->setWieldedItem(item);
2976 // If item has node placement prediction, always send the
2977 // blocks to make sure the client knows what exactly happened
2978 if(item.getDefinition(m_itemdef).node_placement_prediction != ""){
2979 RemoteClient *client = getClient(peer_id);
2980 v3s16 blockpos = getNodeBlockPos(floatToInt(pointed_pos_above, BS));
2981 client->SetBlockNotSent(blockpos);
2982 v3s16 blockpos2 = getNodeBlockPos(floatToInt(pointed_pos_under, BS));
2983 if(blockpos2 != blockpos){
2984 client->SetBlockNotSent(blockpos2);
2992 else if(action == 4)
2994 ItemStack item = playersao->getWieldedItem();
2996 actionstream<<player->getName()<<" uses "<<item.name
2997 <<", pointing at "<<pointed.dump()<<std::endl;
2999 if(m_script->item_OnUse(
3000 item, playersao, pointed))
3002 // Apply returned ItemStack
3003 playersao->setWieldedItem(item);
3010 Catch invalid actions
3014 infostream<<"WARNING: Server: Invalid action "
3015 <<action<<std::endl;
3018 else if(command == TOSERVER_REMOVED_SOUNDS)
3020 std::string datastring((char*)&data[2], datasize-2);
3021 std::istringstream is(datastring, std::ios_base::binary);
3023 int num = readU16(is);
3024 for(int k=0; k<num; k++){
3025 s32 id = readS32(is);
3026 std::map<s32, ServerPlayingSound>::iterator i =
3027 m_playing_sounds.find(id);
3028 if(i == m_playing_sounds.end())
3030 ServerPlayingSound &psound = i->second;
3031 psound.clients.erase(peer_id);
3032 if(psound.clients.size() == 0)
3033 m_playing_sounds.erase(i++);
3036 else if(command == TOSERVER_NODEMETA_FIELDS)
3038 std::string datastring((char*)&data[2], datasize-2);
3039 std::istringstream is(datastring, std::ios_base::binary);
3041 v3s16 p = readV3S16(is);
3042 std::string formname = deSerializeString(is);
3043 int num = readU16(is);
3044 std::map<std::string, std::string> fields;
3045 for(int k=0; k<num; k++){
3046 std::string fieldname = deSerializeString(is);
3047 std::string fieldvalue = deSerializeLongString(is);
3048 fields[fieldname] = fieldvalue;
3051 // If something goes wrong, this player is to blame
3052 RollbackScopeActor rollback_scope(m_rollback,
3053 std::string("player:")+player->getName());
3055 // Check the target node for rollback data; leave others unnoticed
3056 RollbackNode rn_old(&m_env->getMap(), p, this);
3058 m_script->node_on_receive_fields(p, formname, fields,playersao);
3060 // Report rollback data
3061 RollbackNode rn_new(&m_env->getMap(), p, this);
3062 if(rollback() && rn_new != rn_old){
3063 RollbackAction action;
3064 action.setSetNode(p, rn_old, rn_new);
3065 rollback()->reportAction(action);
3068 else if(command == TOSERVER_INVENTORY_FIELDS)
3070 std::string datastring((char*)&data[2], datasize-2);
3071 std::istringstream is(datastring, std::ios_base::binary);
3073 std::string formname = deSerializeString(is);
3074 int num = readU16(is);
3075 std::map<std::string, std::string> fields;
3076 for(int k=0; k<num; k++){
3077 std::string fieldname = deSerializeString(is);
3078 std::string fieldvalue = deSerializeLongString(is);
3079 fields[fieldname] = fieldvalue;
3082 m_script->on_playerReceiveFields(playersao, formname, fields);
3086 infostream<<"Server::ProcessData(): Ignoring "
3087 "unknown command "<<command<<std::endl;
3091 catch(SendFailedException &e)
3093 errorstream<<"Server::ProcessData(): SendFailedException: "
3099 void Server::onMapEditEvent(MapEditEvent *event)
3101 //infostream<<"Server::onMapEditEvent()"<<std::endl;
3102 if(m_ignore_map_edit_events)
3104 if(m_ignore_map_edit_events_area.contains(event->getArea()))
3106 MapEditEvent *e = event->clone();
3107 m_unsent_map_edit_queue.push_back(e);
3110 Inventory* Server::getInventory(const InventoryLocation &loc)
3113 case InventoryLocation::UNDEFINED:
3116 case InventoryLocation::CURRENT_PLAYER:
3119 case InventoryLocation::PLAYER:
3121 Player *player = m_env->getPlayer(loc.name.c_str());
3124 PlayerSAO *playersao = player->getPlayerSAO();
3127 return playersao->getInventory();
3130 case InventoryLocation::NODEMETA:
3132 NodeMetadata *meta = m_env->getMap().getNodeMetadata(loc.p);
3135 return meta->getInventory();
3138 case InventoryLocation::DETACHED:
3140 if(m_detached_inventories.count(loc.name) == 0)
3142 return m_detached_inventories[loc.name];
3150 void Server::setInventoryModified(const InventoryLocation &loc)
3153 case InventoryLocation::UNDEFINED:
3156 case InventoryLocation::PLAYER:
3158 Player *player = m_env->getPlayer(loc.name.c_str());
3161 PlayerSAO *playersao = player->getPlayerSAO();
3164 playersao->m_inventory_not_sent = true;
3165 playersao->m_wielded_item_not_sent = true;
3168 case InventoryLocation::NODEMETA:
3170 v3s16 blockpos = getNodeBlockPos(loc.p);
3172 MapBlock *block = m_env->getMap().getBlockNoCreateNoEx(blockpos);
3174 block->raiseModified(MOD_STATE_WRITE_NEEDED);
3176 setBlockNotSent(blockpos);
3179 case InventoryLocation::DETACHED:
3181 sendDetachedInventoryToAll(loc.name);
3189 //std::list<PlayerInfo> Server::getPlayerInfo()
3191 // DSTACK(__FUNCTION_NAME);
3192 // JMutexAutoLock envlock(m_env_mutex);
3193 // JMutexAutoLock conlock(m_con_mutex);
3195 // std::list<PlayerInfo> list;
3197 // std::list<Player*> players = m_env->getPlayers();
3199 // std::list<Player*>::iterator i;
3200 // for(i = players.begin();
3201 // i != players.end(); ++i)
3205 // Player *player = *i;
3208 // // Copy info from connection to info struct
3209 // info.id = player->peer_id;
3210 // info.address = m_con.GetPeerAddress(player->peer_id);
3211 // info.avg_rtt = m_con.GetPeerAvgRTT(player->peer_id);
3213 // catch(con::PeerNotFoundException &e)
3215 // // Set dummy peer info
3217 // info.address = Address(0,0,0,0,0);
3218 // info.avg_rtt = 0.0;
3221 // snprintf(info.name, PLAYERNAME_SIZE, "%s", player->getName());
3222 // info.position = player->getPosition();
3224 // list.push_back(info);
3231 void Server::peerAdded(con::Peer *peer)
3233 DSTACK(__FUNCTION_NAME);
3234 verbosestream<<"Server::peerAdded(): peer->id="
3235 <<peer->id<<std::endl;
3238 c.type = PEER_ADDED;
3239 c.peer_id = peer->id;
3241 m_peer_change_queue.push_back(c);
3244 void Server::deletingPeer(con::Peer *peer, bool timeout)
3246 DSTACK(__FUNCTION_NAME);
3247 verbosestream<<"Server::deletingPeer(): peer->id="
3248 <<peer->id<<", timeout="<<timeout<<std::endl;
3251 c.type = PEER_REMOVED;
3252 c.peer_id = peer->id;
3253 c.timeout = timeout;
3254 m_peer_change_queue.push_back(c);
3261 void Server::SendMovement(con::Connection &con, u16 peer_id)
3263 DSTACK(__FUNCTION_NAME);
3264 std::ostringstream os(std::ios_base::binary);
3266 writeU16(os, TOCLIENT_MOVEMENT);
3267 writeF1000(os, g_settings->getFloat("movement_acceleration_default"));
3268 writeF1000(os, g_settings->getFloat("movement_acceleration_air"));
3269 writeF1000(os, g_settings->getFloat("movement_acceleration_fast"));
3270 writeF1000(os, g_settings->getFloat("movement_speed_walk"));
3271 writeF1000(os, g_settings->getFloat("movement_speed_crouch"));
3272 writeF1000(os, g_settings->getFloat("movement_speed_fast"));
3273 writeF1000(os, g_settings->getFloat("movement_speed_climb"));
3274 writeF1000(os, g_settings->getFloat("movement_speed_jump"));
3275 writeF1000(os, g_settings->getFloat("movement_liquid_fluidity"));
3276 writeF1000(os, g_settings->getFloat("movement_liquid_fluidity_smooth"));
3277 writeF1000(os, g_settings->getFloat("movement_liquid_sink"));
3278 writeF1000(os, g_settings->getFloat("movement_gravity"));
3281 std::string s = os.str();
3282 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3284 con.Send(peer_id, 0, data, true);
3287 void Server::SendHP(con::Connection &con, u16 peer_id, u8 hp)
3289 DSTACK(__FUNCTION_NAME);
3290 std::ostringstream os(std::ios_base::binary);
3292 writeU16(os, TOCLIENT_HP);
3296 std::string s = os.str();
3297 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3299 con.Send(peer_id, 0, data, true);
3302 void Server::SendAccessDenied(con::Connection &con, u16 peer_id,
3303 const std::wstring &reason)
3305 DSTACK(__FUNCTION_NAME);
3306 std::ostringstream os(std::ios_base::binary);
3308 writeU16(os, TOCLIENT_ACCESS_DENIED);
3309 os<<serializeWideString(reason);
3312 std::string s = os.str();
3313 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3315 con.Send(peer_id, 0, data, true);
3318 void Server::SendDeathscreen(con::Connection &con, u16 peer_id,
3319 bool set_camera_point_target, v3f camera_point_target)
3321 DSTACK(__FUNCTION_NAME);
3322 std::ostringstream os(std::ios_base::binary);
3324 writeU16(os, TOCLIENT_DEATHSCREEN);
3325 writeU8(os, set_camera_point_target);
3326 writeV3F1000(os, camera_point_target);
3329 std::string s = os.str();
3330 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3332 con.Send(peer_id, 0, data, true);
3335 void Server::SendItemDef(con::Connection &con, u16 peer_id,
3336 IItemDefManager *itemdef, u16 protocol_version)
3338 DSTACK(__FUNCTION_NAME);
3339 std::ostringstream os(std::ios_base::binary);
3343 u32 length of the next item
3344 zlib-compressed serialized ItemDefManager
3346 writeU16(os, TOCLIENT_ITEMDEF);
3347 std::ostringstream tmp_os(std::ios::binary);
3348 itemdef->serialize(tmp_os, protocol_version);
3349 std::ostringstream tmp_os2(std::ios::binary);
3350 compressZlib(tmp_os.str(), tmp_os2);
3351 os<<serializeLongString(tmp_os2.str());
3354 std::string s = os.str();
3355 verbosestream<<"Server: Sending item definitions to id("<<peer_id
3356 <<"): size="<<s.size()<<std::endl;
3357 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3359 con.Send(peer_id, 0, data, true);
3362 void Server::SendNodeDef(con::Connection &con, u16 peer_id,
3363 INodeDefManager *nodedef, u16 protocol_version)
3365 DSTACK(__FUNCTION_NAME);
3366 std::ostringstream os(std::ios_base::binary);
3370 u32 length of the next item
3371 zlib-compressed serialized NodeDefManager
3373 writeU16(os, TOCLIENT_NODEDEF);
3374 std::ostringstream tmp_os(std::ios::binary);
3375 nodedef->serialize(tmp_os, protocol_version);
3376 std::ostringstream tmp_os2(std::ios::binary);
3377 compressZlib(tmp_os.str(), tmp_os2);
3378 os<<serializeLongString(tmp_os2.str());
3381 std::string s = os.str();
3382 verbosestream<<"Server: Sending node definitions to id("<<peer_id
3383 <<"): size="<<s.size()<<std::endl;
3384 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3386 con.Send(peer_id, 0, data, true);
3390 Non-static send methods
3393 void Server::SendInventory(u16 peer_id)
3395 DSTACK(__FUNCTION_NAME);
3397 PlayerSAO *playersao = getPlayerSAO(peer_id);
3400 playersao->m_inventory_not_sent = false;
3406 std::ostringstream os;
3407 playersao->getInventory()->serialize(os);
3409 std::string s = os.str();
3411 SharedBuffer<u8> data(s.size()+2);
3412 writeU16(&data[0], TOCLIENT_INVENTORY);
3413 memcpy(&data[2], s.c_str(), s.size());
3416 m_con.Send(peer_id, 0, data, true);
3419 void Server::SendChatMessage(u16 peer_id, const std::wstring &message)
3421 DSTACK(__FUNCTION_NAME);
3423 std::ostringstream os(std::ios_base::binary);
3427 writeU16(buf, TOCLIENT_CHAT_MESSAGE);
3428 os.write((char*)buf, 2);
3431 writeU16(buf, message.size());
3432 os.write((char*)buf, 2);
3435 for(u32 i=0; i<message.size(); i++)
3439 os.write((char*)buf, 2);
3443 std::string s = os.str();
3444 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3446 m_con.Send(peer_id, 0, data, true);
3449 void Server::SendShowFormspecMessage(u16 peer_id, const std::string formspec,
3450 const std::string formname)
3452 DSTACK(__FUNCTION_NAME);
3454 std::ostringstream os(std::ios_base::binary);
3458 writeU16(buf, TOCLIENT_SHOW_FORMSPEC);
3459 os.write((char*)buf, 2);
3460 os<<serializeLongString(formspec);
3461 os<<serializeString(formname);
3464 std::string s = os.str();
3465 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3467 m_con.Send(peer_id, 0, data, true);
3470 // Spawns a particle on peer with peer_id
3471 void Server::SendSpawnParticle(u16 peer_id, v3f pos, v3f velocity, v3f acceleration,
3472 float expirationtime, float size, bool collisiondetection,
3473 std::string texture)
3475 DSTACK(__FUNCTION_NAME);
3477 std::ostringstream os(std::ios_base::binary);
3478 writeU16(os, TOCLIENT_SPAWN_PARTICLE);
3479 writeV3F1000(os, pos);
3480 writeV3F1000(os, velocity);
3481 writeV3F1000(os, acceleration);
3482 writeF1000(os, expirationtime);
3483 writeF1000(os, size);
3484 writeU8(os, collisiondetection);
3485 os<<serializeLongString(texture);
3488 std::string s = os.str();
3489 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3491 m_con.Send(peer_id, 0, data, true);
3494 // Spawns a particle on all peers
3495 void Server::SendSpawnParticleAll(v3f pos, v3f velocity, v3f acceleration,
3496 float expirationtime, float size, bool collisiondetection,
3497 std::string texture)
3499 for(std::map<u16, RemoteClient*>::iterator
3500 i = m_clients.begin();
3501 i != m_clients.end(); i++)
3503 // Get client and check that it is valid
3504 RemoteClient *client = i->second;
3505 assert(client->peer_id == i->first);
3506 if(client->serialization_version == SER_FMT_VER_INVALID)
3509 SendSpawnParticle(client->peer_id, pos, velocity, acceleration,
3510 expirationtime, size, collisiondetection, texture);
3514 // Adds a ParticleSpawner on peer with peer_id
3515 void Server::SendAddParticleSpawner(u16 peer_id, u16 amount, float spawntime, v3f minpos, v3f maxpos,
3516 v3f minvel, v3f maxvel, v3f minacc, v3f maxacc, float minexptime, float maxexptime,
3517 float minsize, float maxsize, bool collisiondetection, std::string texture, u32 id)
3519 DSTACK(__FUNCTION_NAME);
3521 std::ostringstream os(std::ios_base::binary);
3522 writeU16(os, TOCLIENT_ADD_PARTICLESPAWNER);
3524 writeU16(os, amount);
3525 writeF1000(os, spawntime);
3526 writeV3F1000(os, minpos);
3527 writeV3F1000(os, maxpos);
3528 writeV3F1000(os, minvel);
3529 writeV3F1000(os, maxvel);
3530 writeV3F1000(os, minacc);
3531 writeV3F1000(os, maxacc);
3532 writeF1000(os, minexptime);
3533 writeF1000(os, maxexptime);
3534 writeF1000(os, minsize);
3535 writeF1000(os, maxsize);
3536 writeU8(os, collisiondetection);
3537 os<<serializeLongString(texture);
3541 std::string s = os.str();
3542 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3544 m_con.Send(peer_id, 0, data, true);
3547 // Adds a ParticleSpawner on all peers
3548 void Server::SendAddParticleSpawnerAll(u16 amount, float spawntime, v3f minpos, v3f maxpos,
3549 v3f minvel, v3f maxvel, v3f minacc, v3f maxacc, float minexptime, float maxexptime,
3550 float minsize, float maxsize, bool collisiondetection, std::string texture, u32 id)
3552 for(std::map<u16, RemoteClient*>::iterator
3553 i = m_clients.begin();
3554 i != m_clients.end(); i++)
3556 // Get client and check that it is valid
3557 RemoteClient *client = i->second;
3558 assert(client->peer_id == i->first);
3559 if(client->serialization_version == SER_FMT_VER_INVALID)
3562 SendAddParticleSpawner(client->peer_id, amount, spawntime,
3563 minpos, maxpos, minvel, maxvel, minacc, maxacc,
3564 minexptime, maxexptime, minsize, maxsize, collisiondetection, texture, id);
3568 void Server::SendDeleteParticleSpawner(u16 peer_id, u32 id)
3570 DSTACK(__FUNCTION_NAME);
3572 std::ostringstream os(std::ios_base::binary);
3573 writeU16(os, TOCLIENT_DELETE_PARTICLESPAWNER);
3578 std::string s = os.str();
3579 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3581 m_con.Send(peer_id, 0, data, true);
3584 void Server::SendDeleteParticleSpawnerAll(u32 id)
3586 for(std::map<u16, RemoteClient*>::iterator
3587 i = m_clients.begin();
3588 i != m_clients.end(); i++)
3590 // Get client and check that it is valid
3591 RemoteClient *client = i->second;
3592 assert(client->peer_id == i->first);
3593 if(client->serialization_version == SER_FMT_VER_INVALID)
3596 SendDeleteParticleSpawner(client->peer_id, id);
3600 void Server::SendHUDAdd(u16 peer_id, u32 id, HudElement *form)
3602 std::ostringstream os(std::ios_base::binary);
3605 writeU16(os, TOCLIENT_HUDADD);
3607 writeU8(os, (u8)form->type);
3608 writeV2F1000(os, form->pos);
3609 os << serializeString(form->name);
3610 writeV2F1000(os, form->scale);
3611 os << serializeString(form->text);
3612 writeU32(os, form->number);
3613 writeU32(os, form->item);
3614 writeU32(os, form->dir);
3615 writeV2F1000(os, form->align);
3616 writeV2F1000(os, form->offset);
3619 std::string s = os.str();
3620 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3622 m_con.Send(peer_id, 0, data, true);
3625 void Server::SendHUDRemove(u16 peer_id, u32 id)
3627 std::ostringstream os(std::ios_base::binary);
3630 writeU16(os, TOCLIENT_HUDRM);
3634 std::string s = os.str();
3635 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3637 m_con.Send(peer_id, 0, data, true);
3640 void Server::SendHUDChange(u16 peer_id, u32 id, HudElementStat stat, void *value)
3642 std::ostringstream os(std::ios_base::binary);
3645 writeU16(os, TOCLIENT_HUDCHANGE);
3647 writeU8(os, (u8)stat);
3650 case HUD_STAT_SCALE:
3651 case HUD_STAT_ALIGN:
3652 case HUD_STAT_OFFSET:
3653 writeV2F1000(os, *(v2f *)value);
3657 os << serializeString(*(std::string *)value);
3659 case HUD_STAT_NUMBER:
3663 writeU32(os, *(u32 *)value);
3668 std::string s = os.str();
3669 SharedBuffer<u8> data((u8 *)s.c_str(), s.size());
3671 m_con.Send(peer_id, 0, data, true);
3674 void Server::SendHUDSetFlags(u16 peer_id, u32 flags, u32 mask)
3676 std::ostringstream os(std::ios_base::binary);
3679 writeU16(os, TOCLIENT_HUD_SET_FLAGS);
3680 writeU32(os, flags);
3684 std::string s = os.str();
3685 SharedBuffer<u8> data((u8 *)s.c_str(), s.size());
3687 m_con.Send(peer_id, 0, data, true);
3690 void Server::BroadcastChatMessage(const std::wstring &message)
3692 for(std::map<u16, RemoteClient*>::iterator
3693 i = m_clients.begin();
3694 i != m_clients.end(); ++i)
3696 // Get client and check that it is valid
3697 RemoteClient *client = i->second;
3698 assert(client->peer_id == i->first);
3699 if(client->serialization_version == SER_FMT_VER_INVALID)
3702 SendChatMessage(client->peer_id, message);
3706 void Server::SendPlayerHP(u16 peer_id)
3708 DSTACK(__FUNCTION_NAME);
3709 PlayerSAO *playersao = getPlayerSAO(peer_id);
3711 playersao->m_hp_not_sent = false;
3712 SendHP(m_con, peer_id, playersao->getHP());
3715 void Server::SendMovePlayer(u16 peer_id)
3717 DSTACK(__FUNCTION_NAME);
3718 Player *player = m_env->getPlayer(peer_id);
3721 std::ostringstream os(std::ios_base::binary);
3722 writeU16(os, TOCLIENT_MOVE_PLAYER);
3723 writeV3F1000(os, player->getPosition());
3724 writeF1000(os, player->getPitch());
3725 writeF1000(os, player->getYaw());
3728 v3f pos = player->getPosition();
3729 f32 pitch = player->getPitch();
3730 f32 yaw = player->getYaw();
3731 verbosestream<<"Server: Sending TOCLIENT_MOVE_PLAYER"
3732 <<" pos=("<<pos.X<<","<<pos.Y<<","<<pos.Z<<")"
3739 std::string s = os.str();
3740 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3742 m_con.Send(peer_id, 0, data, true);
3745 void Server::SendPlayerPrivileges(u16 peer_id)
3747 Player *player = m_env->getPlayer(peer_id);
3749 if(player->peer_id == PEER_ID_INEXISTENT)
3752 std::set<std::string> privs;
3753 m_script->getAuth(player->getName(), NULL, &privs);
3755 std::ostringstream os(std::ios_base::binary);
3756 writeU16(os, TOCLIENT_PRIVILEGES);
3757 writeU16(os, privs.size());
3758 for(std::set<std::string>::const_iterator i = privs.begin();
3759 i != privs.end(); i++){
3760 os<<serializeString(*i);
3764 std::string s = os.str();
3765 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3767 m_con.Send(peer_id, 0, data, true);
3770 void Server::SendPlayerInventoryFormspec(u16 peer_id)
3772 Player *player = m_env->getPlayer(peer_id);
3774 if(player->peer_id == PEER_ID_INEXISTENT)
3777 std::ostringstream os(std::ios_base::binary);
3778 writeU16(os, TOCLIENT_INVENTORY_FORMSPEC);
3779 os<<serializeLongString(player->inventory_formspec);
3782 std::string s = os.str();
3783 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3785 m_con.Send(peer_id, 0, data, true);
3788 s32 Server::playSound(const SimpleSoundSpec &spec,
3789 const ServerSoundParams ¶ms)
3791 // Find out initial position of sound
3792 bool pos_exists = false;
3793 v3f pos = params.getPos(m_env, &pos_exists);
3794 // If position is not found while it should be, cancel sound
3795 if(pos_exists != (params.type != ServerSoundParams::SSP_LOCAL))
3797 // Filter destination clients
3798 std::set<RemoteClient*> dst_clients;
3799 if(params.to_player != "")
3801 Player *player = m_env->getPlayer(params.to_player.c_str());
3803 infostream<<"Server::playSound: Player \""<<params.to_player
3804 <<"\" not found"<<std::endl;
3807 if(player->peer_id == PEER_ID_INEXISTENT){
3808 infostream<<"Server::playSound: Player \""<<params.to_player
3809 <<"\" not connected"<<std::endl;
3812 RemoteClient *client = getClient(player->peer_id);
3813 dst_clients.insert(client);
3817 for(std::map<u16, RemoteClient*>::iterator
3818 i = m_clients.begin(); i != m_clients.end(); ++i)
3820 RemoteClient *client = i->second;
3821 Player *player = m_env->getPlayer(client->peer_id);
3825 if(player->getPosition().getDistanceFrom(pos) >
3826 params.max_hear_distance)
3829 dst_clients.insert(client);
3832 if(dst_clients.size() == 0)
3835 s32 id = m_next_sound_id++;
3836 // The sound will exist as a reference in m_playing_sounds
3837 m_playing_sounds[id] = ServerPlayingSound();
3838 ServerPlayingSound &psound = m_playing_sounds[id];
3839 psound.params = params;
3840 for(std::set<RemoteClient*>::iterator i = dst_clients.begin();
3841 i != dst_clients.end(); i++)
3842 psound.clients.insert((*i)->peer_id);
3844 std::ostringstream os(std::ios_base::binary);
3845 writeU16(os, TOCLIENT_PLAY_SOUND);
3847 os<<serializeString(spec.name);
3848 writeF1000(os, spec.gain * params.gain);
3849 writeU8(os, params.type);
3850 writeV3F1000(os, pos);
3851 writeU16(os, params.object);
3852 writeU8(os, params.loop);
3854 std::string s = os.str();
3855 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3857 for(std::set<RemoteClient*>::iterator i = dst_clients.begin();
3858 i != dst_clients.end(); i++){
3860 m_con.Send((*i)->peer_id, 0, data, true);
3864 void Server::stopSound(s32 handle)
3866 // Get sound reference
3867 std::map<s32, ServerPlayingSound>::iterator i =
3868 m_playing_sounds.find(handle);
3869 if(i == m_playing_sounds.end())
3871 ServerPlayingSound &psound = i->second;
3873 std::ostringstream os(std::ios_base::binary);
3874 writeU16(os, TOCLIENT_STOP_SOUND);
3875 writeS32(os, handle);
3877 std::string s = os.str();
3878 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
3880 for(std::set<u16>::iterator i = psound.clients.begin();
3881 i != psound.clients.end(); i++){
3883 m_con.Send(*i, 0, data, true);
3885 // Remove sound reference
3886 m_playing_sounds.erase(i);
3889 void Server::sendRemoveNode(v3s16 p, u16 ignore_id,
3890 std::list<u16> *far_players, float far_d_nodes)
3892 float maxd = far_d_nodes*BS;
3893 v3f p_f = intToFloat(p, BS);
3897 SharedBuffer<u8> reply(replysize);
3898 writeU16(&reply[0], TOCLIENT_REMOVENODE);
3899 writeS16(&reply[2], p.X);
3900 writeS16(&reply[4], p.Y);
3901 writeS16(&reply[6], p.Z);
3903 for(std::map<u16, RemoteClient*>::iterator
3904 i = m_clients.begin();
3905 i != m_clients.end(); ++i)
3907 // Get client and check that it is valid
3908 RemoteClient *client = i->second;
3909 assert(client->peer_id == i->first);
3910 if(client->serialization_version == SER_FMT_VER_INVALID)
3913 // Don't send if it's the same one
3914 if(client->peer_id == ignore_id)
3920 Player *player = m_env->getPlayer(client->peer_id);
3923 // If player is far away, only set modified blocks not sent
3924 v3f player_pos = player->getPosition();
3925 if(player_pos.getDistanceFrom(p_f) > maxd)
3927 far_players->push_back(client->peer_id);
3934 m_con.Send(client->peer_id, 0, reply, true);
3938 void Server::sendAddNode(v3s16 p, MapNode n, u16 ignore_id,
3939 std::list<u16> *far_players, float far_d_nodes)
3941 float maxd = far_d_nodes*BS;
3942 v3f p_f = intToFloat(p, BS);
3944 for(std::map<u16, RemoteClient*>::iterator
3945 i = m_clients.begin();
3946 i != m_clients.end(); ++i)
3948 // Get client and check that it is valid
3949 RemoteClient *client = i->second;
3950 assert(client->peer_id == i->first);
3951 if(client->serialization_version == SER_FMT_VER_INVALID)
3954 // Don't send if it's the same one
3955 if(client->peer_id == ignore_id)
3961 Player *player = m_env->getPlayer(client->peer_id);
3964 // If player is far away, only set modified blocks not sent
3965 v3f player_pos = player->getPosition();
3966 if(player_pos.getDistanceFrom(p_f) > maxd)
3968 far_players->push_back(client->peer_id);
3975 u32 replysize = 8 + MapNode::serializedLength(client->serialization_version);
3976 SharedBuffer<u8> reply(replysize);
3977 writeU16(&reply[0], TOCLIENT_ADDNODE);
3978 writeS16(&reply[2], p.X);
3979 writeS16(&reply[4], p.Y);
3980 writeS16(&reply[6], p.Z);
3981 n.serialize(&reply[8], client->serialization_version);
3984 m_con.Send(client->peer_id, 0, reply, true);
3988 void Server::setBlockNotSent(v3s16 p)
3990 for(std::map<u16, RemoteClient*>::iterator
3991 i = m_clients.begin();
3992 i != m_clients.end(); ++i)
3994 RemoteClient *client = i->second;
3995 client->SetBlockNotSent(p);
3999 void Server::SendBlockNoLock(u16 peer_id, MapBlock *block, u8 ver)
4001 DSTACK(__FUNCTION_NAME);
4003 v3s16 p = block->getPos();
4007 bool completely_air = true;
4008 for(s16 z0=0; z0<MAP_BLOCKSIZE; z0++)
4009 for(s16 x0=0; x0<MAP_BLOCKSIZE; x0++)
4010 for(s16 y0=0; y0<MAP_BLOCKSIZE; y0++)
4012 if(block->getNodeNoEx(v3s16(x0,y0,z0)).d != CONTENT_AIR)
4014 completely_air = false;
4015 x0 = y0 = z0 = MAP_BLOCKSIZE; // Break out
4020 infostream<<"Server: Sending block ("<<p.X<<","<<p.Y<<","<<p.Z<<"): ";
4022 infostream<<"[completely air] ";
4023 infostream<<std::endl;
4027 Create a packet with the block in the right format
4030 std::ostringstream os(std::ios_base::binary);
4031 block->serialize(os, ver, false);
4032 std::string s = os.str();
4033 SharedBuffer<u8> blockdata((u8*)s.c_str(), s.size());
4035 u32 replysize = 8 + blockdata.getSize();
4036 SharedBuffer<u8> reply(replysize);
4037 writeU16(&reply[0], TOCLIENT_BLOCKDATA);
4038 writeS16(&reply[2], p.X);
4039 writeS16(&reply[4], p.Y);
4040 writeS16(&reply[6], p.Z);
4041 memcpy(&reply[8], *blockdata, blockdata.getSize());
4043 /*infostream<<"Server: Sending block ("<<p.X<<","<<p.Y<<","<<p.Z<<")"
4044 <<": \tpacket size: "<<replysize<<std::endl;*/
4049 m_con.Send(peer_id, 1, reply, true);
4052 void Server::SendBlocks(float dtime)
4054 DSTACK(__FUNCTION_NAME);
4056 JMutexAutoLock envlock(m_env_mutex);
4057 JMutexAutoLock conlock(m_con_mutex);
4059 ScopeProfiler sp(g_profiler, "Server: sel and send blocks to clients");
4061 std::vector<PrioritySortedBlockTransfer> queue;
4063 s32 total_sending = 0;
4066 ScopeProfiler sp(g_profiler, "Server: selecting blocks for sending");
4068 for(std::map<u16, RemoteClient*>::iterator
4069 i = m_clients.begin();
4070 i != m_clients.end(); ++i)
4072 RemoteClient *client = i->second;
4073 assert(client->peer_id == i->first);
4075 // If definitions and textures have not been sent, don't
4076 // send MapBlocks either
4077 if(!client->definitions_sent)
4080 total_sending += client->SendingCount();
4082 if(client->serialization_version == SER_FMT_VER_INVALID)
4085 client->GetNextBlocks(this, dtime, queue);
4090 // Lowest priority number comes first.
4091 // Lowest is most important.
4092 std::sort(queue.begin(), queue.end());
4094 for(u32 i=0; i<queue.size(); i++)
4096 //TODO: Calculate limit dynamically
4097 if(total_sending >= g_settings->getS32
4098 ("max_simultaneous_block_sends_server_total"))
4101 PrioritySortedBlockTransfer q = queue[i];
4103 MapBlock *block = NULL;
4106 block = m_env->getMap().getBlockNoCreate(q.pos);
4108 catch(InvalidPositionException &e)
4113 RemoteClient *client = getClient(q.peer_id);
4115 SendBlockNoLock(q.peer_id, block, client->serialization_version);
4117 client->SentBlock(q.pos);
4123 void Server::fillMediaCache()
4125 DSTACK(__FUNCTION_NAME);
4127 infostream<<"Server: Calculating media file checksums"<<std::endl;
4129 // Collect all media file paths
4130 std::list<std::string> paths;
4131 for(std::vector<ModSpec>::iterator i = m_mods.begin();
4132 i != m_mods.end(); i++){
4133 const ModSpec &mod = *i;
4134 paths.push_back(mod.path + DIR_DELIM + "textures");
4135 paths.push_back(mod.path + DIR_DELIM + "sounds");
4136 paths.push_back(mod.path + DIR_DELIM + "media");
4137 paths.push_back(mod.path + DIR_DELIM + "models");
4139 std::string path_all = "textures";
4140 paths.push_back(path_all + DIR_DELIM + "all");
4142 // Collect media file information from paths into cache
4143 for(std::list<std::string>::iterator i = paths.begin();
4144 i != paths.end(); i++)
4146 std::string mediapath = *i;
4147 std::vector<fs::DirListNode> dirlist = fs::GetDirListing(mediapath);
4148 for(u32 j=0; j<dirlist.size(); j++){
4149 if(dirlist[j].dir) // Ignode dirs
4151 std::string filename = dirlist[j].name;
4152 // If name contains illegal characters, ignore the file
4153 if(!string_allowed(filename, TEXTURENAME_ALLOWED_CHARS)){
4154 infostream<<"Server: ignoring illegal file name: \""
4155 <<filename<<"\""<<std::endl;
4158 // If name is not in a supported format, ignore it
4159 const char *supported_ext[] = {
4160 ".png", ".jpg", ".bmp", ".tga",
4161 ".pcx", ".ppm", ".psd", ".wal", ".rgb",
4163 ".x", ".b3d", ".md2", ".obj",
4166 if(removeStringEnd(filename, supported_ext) == ""){
4167 infostream<<"Server: ignoring unsupported file extension: \""
4168 <<filename<<"\""<<std::endl;
4171 // Ok, attempt to load the file and add to cache
4172 std::string filepath = mediapath + DIR_DELIM + filename;
4174 std::ifstream fis(filepath.c_str(), std::ios_base::binary);
4175 if(fis.good() == false){
4176 errorstream<<"Server::fillMediaCache(): Could not open \""
4177 <<filename<<"\" for reading"<<std::endl;
4180 std::ostringstream tmp_os(std::ios_base::binary);
4184 fis.read(buf, 1024);
4185 std::streamsize len = fis.gcount();
4186 tmp_os.write(buf, len);
4195 errorstream<<"Server::fillMediaCache(): Failed to read \""
4196 <<filename<<"\""<<std::endl;
4199 if(tmp_os.str().length() == 0){
4200 errorstream<<"Server::fillMediaCache(): Empty file \""
4201 <<filepath<<"\""<<std::endl;
4206 sha1.addBytes(tmp_os.str().c_str(), tmp_os.str().length());
4208 unsigned char *digest = sha1.getDigest();
4209 std::string sha1_base64 = base64_encode(digest, 20);
4210 std::string sha1_hex = hex_encode((char*)digest, 20);
4214 this->m_media[filename] = MediaInfo(filepath, sha1_base64);
4215 verbosestream<<"Server: "<<sha1_hex<<" is "<<filename<<std::endl;
4220 struct SendableMediaAnnouncement
4223 std::string sha1_digest;
4225 SendableMediaAnnouncement(const std::string name_="",
4226 const std::string sha1_digest_=""):
4228 sha1_digest(sha1_digest_)
4232 void Server::sendMediaAnnouncement(u16 peer_id)
4234 DSTACK(__FUNCTION_NAME);
4236 verbosestream<<"Server: Announcing files to id("<<peer_id<<")"
4239 std::list<SendableMediaAnnouncement> file_announcements;
4241 for(std::map<std::string, MediaInfo>::iterator i = m_media.begin();
4242 i != m_media.end(); i++){
4244 file_announcements.push_back(
4245 SendableMediaAnnouncement(i->first, i->second.sha1_digest));
4249 std::ostringstream os(std::ios_base::binary);
4257 u16 length of sha1_digest
4262 writeU16(os, TOCLIENT_ANNOUNCE_MEDIA);
4263 writeU16(os, file_announcements.size());
4265 for(std::list<SendableMediaAnnouncement>::iterator
4266 j = file_announcements.begin();
4267 j != file_announcements.end(); ++j){
4268 os<<serializeString(j->name);
4269 os<<serializeString(j->sha1_digest);
4271 os<<serializeString(g_settings->get("remote_media"));
4274 std::string s = os.str();
4275 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
4278 m_con.Send(peer_id, 0, data, true);
4281 struct SendableMedia
4287 SendableMedia(const std::string &name_="", const std::string path_="",
4288 const std::string &data_=""):
4295 void Server::sendRequestedMedia(u16 peer_id,
4296 const std::list<MediaRequest> &tosend)
4298 DSTACK(__FUNCTION_NAME);
4300 verbosestream<<"Server::sendRequestedMedia(): "
4301 <<"Sending files to client"<<std::endl;
4305 // Put 5kB in one bunch (this is not accurate)
4306 u32 bytes_per_bunch = 5000;
4308 std::vector< std::list<SendableMedia> > file_bunches;
4309 file_bunches.push_back(std::list<SendableMedia>());
4311 u32 file_size_bunch_total = 0;
4313 for(std::list<MediaRequest>::const_iterator i = tosend.begin();
4314 i != tosend.end(); ++i)
4316 if(m_media.find(i->name) == m_media.end()){
4317 errorstream<<"Server::sendRequestedMedia(): Client asked for "
4318 <<"unknown file \""<<(i->name)<<"\""<<std::endl;
4322 //TODO get path + name
4323 std::string tpath = m_media[(*i).name].path;
4326 std::ifstream fis(tpath.c_str(), std::ios_base::binary);
4327 if(fis.good() == false){
4328 errorstream<<"Server::sendRequestedMedia(): Could not open \""
4329 <<tpath<<"\" for reading"<<std::endl;
4332 std::ostringstream tmp_os(std::ios_base::binary);
4336 fis.read(buf, 1024);
4337 std::streamsize len = fis.gcount();
4338 tmp_os.write(buf, len);
4339 file_size_bunch_total += len;
4348 errorstream<<"Server::sendRequestedMedia(): Failed to read \""
4349 <<(*i).name<<"\""<<std::endl;
4352 /*infostream<<"Server::sendRequestedMedia(): Loaded \""
4353 <<tname<<"\""<<std::endl;*/
4355 file_bunches[file_bunches.size()-1].push_back(
4356 SendableMedia((*i).name, tpath, tmp_os.str()));
4358 // Start next bunch if got enough data
4359 if(file_size_bunch_total >= bytes_per_bunch){
4360 file_bunches.push_back(std::list<SendableMedia>());
4361 file_size_bunch_total = 0;
4366 /* Create and send packets */
4368 u32 num_bunches = file_bunches.size();
4369 for(u32 i=0; i<num_bunches; i++)
4371 std::ostringstream os(std::ios_base::binary);
4375 u16 total number of texture bunches
4376 u16 index of this bunch
4377 u32 number of files in this bunch
4386 writeU16(os, TOCLIENT_MEDIA);
4387 writeU16(os, num_bunches);
4389 writeU32(os, file_bunches[i].size());
4391 for(std::list<SendableMedia>::iterator
4392 j = file_bunches[i].begin();
4393 j != file_bunches[i].end(); ++j){
4394 os<<serializeString(j->name);
4395 os<<serializeLongString(j->data);
4399 std::string s = os.str();
4400 verbosestream<<"Server::sendRequestedMedia(): bunch "
4401 <<i<<"/"<<num_bunches
4402 <<" files="<<file_bunches[i].size()
4403 <<" size=" <<s.size()<<std::endl;
4404 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
4406 m_con.Send(peer_id, 0, data, true);
4410 void Server::sendDetachedInventory(const std::string &name, u16 peer_id)
4412 if(m_detached_inventories.count(name) == 0){
4413 errorstream<<__FUNCTION_NAME<<": \""<<name<<"\" not found"<<std::endl;
4416 Inventory *inv = m_detached_inventories[name];
4418 std::ostringstream os(std::ios_base::binary);
4419 writeU16(os, TOCLIENT_DETACHED_INVENTORY);
4420 os<<serializeString(name);
4424 std::string s = os.str();
4425 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
4427 m_con.Send(peer_id, 0, data, true);
4430 void Server::sendDetachedInventoryToAll(const std::string &name)
4432 DSTACK(__FUNCTION_NAME);
4434 for(std::map<u16, RemoteClient*>::iterator
4435 i = m_clients.begin();
4436 i != m_clients.end(); ++i){
4437 RemoteClient *client = i->second;
4438 sendDetachedInventory(name, client->peer_id);
4442 void Server::sendDetachedInventories(u16 peer_id)
4444 DSTACK(__FUNCTION_NAME);
4446 for(std::map<std::string, Inventory*>::iterator
4447 i = m_detached_inventories.begin();
4448 i != m_detached_inventories.end(); i++){
4449 const std::string &name = i->first;
4450 //Inventory *inv = i->second;
4451 sendDetachedInventory(name, peer_id);
4459 void Server::DiePlayer(u16 peer_id)
4461 DSTACK(__FUNCTION_NAME);
4463 PlayerSAO *playersao = getPlayerSAO(peer_id);
4466 infostream<<"Server::DiePlayer(): Player "
4467 <<playersao->getPlayer()->getName()
4468 <<" dies"<<std::endl;
4470 playersao->setHP(0);
4472 // Trigger scripted stuff
4473 m_script->on_dieplayer(playersao);
4475 SendPlayerHP(peer_id);
4476 SendDeathscreen(m_con, peer_id, false, v3f(0,0,0));
4479 void Server::RespawnPlayer(u16 peer_id)
4481 DSTACK(__FUNCTION_NAME);
4483 PlayerSAO *playersao = getPlayerSAO(peer_id);
4486 infostream<<"Server::RespawnPlayer(): Player "
4487 <<playersao->getPlayer()->getName()
4488 <<" respawns"<<std::endl;
4490 playersao->setHP(PLAYER_MAX_HP);
4492 bool repositioned = m_script->on_respawnplayer(playersao);
4494 v3f pos = findSpawnPos(m_env->getServerMap());
4495 playersao->setPos(pos);
4499 void Server::UpdateCrafting(u16 peer_id)
4501 DSTACK(__FUNCTION_NAME);
4503 Player* player = m_env->getPlayer(peer_id);
4506 // Get a preview for crafting
4508 getCraftingResult(&player->inventory, preview, false, this);
4510 // Put the new preview in
4511 InventoryList *plist = player->inventory.getList("craftpreview");
4513 assert(plist->getSize() >= 1);
4514 plist->changeItem(0, preview);
4517 RemoteClient* Server::getClient(u16 peer_id)
4519 DSTACK(__FUNCTION_NAME);
4520 //JMutexAutoLock lock(m_con_mutex);
4521 std::map<u16, RemoteClient*>::iterator n;
4522 n = m_clients.find(peer_id);
4523 // A client should exist for all peers
4524 assert(n != m_clients.end());
4528 std::wstring Server::getStatusString()
4530 std::wostringstream os(std::ios_base::binary);
4533 os<<L"version="<<narrow_to_wide(VERSION_STRING);
4535 os<<L", uptime="<<m_uptime.get();
4536 // Information about clients
4537 std::map<u16, RemoteClient*>::iterator i;
4540 for(i = m_clients.begin(), first = true;
4541 i != m_clients.end(); ++i)
4543 // Get client and check that it is valid
4544 RemoteClient *client = i->second;
4545 assert(client->peer_id == i->first);
4546 if(client->serialization_version == SER_FMT_VER_INVALID)
4549 Player *player = m_env->getPlayer(client->peer_id);
4550 // Get name of player
4551 std::wstring name = L"unknown";
4553 name = narrow_to_wide(player->getName());
4554 // Add name to information string
4562 if(((ServerMap*)(&m_env->getMap()))->isSavingEnabled() == false)
4563 os<<std::endl<<L"# Server: "<<" WARNING: Map saving is disabled.";
4564 if(g_settings->get("motd") != "")
4565 os<<std::endl<<L"# Server: "<<narrow_to_wide(g_settings->get("motd"));
4569 std::set<std::string> Server::getPlayerEffectivePrivs(const std::string &name)
4571 std::set<std::string> privs;
4572 m_script->getAuth(name, NULL, &privs);
4576 bool Server::checkPriv(const std::string &name, const std::string &priv)
4578 std::set<std::string> privs = getPlayerEffectivePrivs(name);
4579 return (privs.count(priv) != 0);
4582 void Server::reportPrivsModified(const std::string &name)
4585 for(std::map<u16, RemoteClient*>::iterator
4586 i = m_clients.begin();
4587 i != m_clients.end(); ++i){
4588 RemoteClient *client = i->second;
4589 Player *player = m_env->getPlayer(client->peer_id);
4590 reportPrivsModified(player->getName());
4593 Player *player = m_env->getPlayer(name.c_str());
4596 SendPlayerPrivileges(player->peer_id);
4597 PlayerSAO *sao = player->getPlayerSAO();
4600 sao->updatePrivileges(
4601 getPlayerEffectivePrivs(name),
4606 void Server::reportInventoryFormspecModified(const std::string &name)
4608 Player *player = m_env->getPlayer(name.c_str());
4611 SendPlayerInventoryFormspec(player->peer_id);
4614 // Saves g_settings to configpath given at initialization
4615 void Server::saveConfig()
4617 if(m_path_config != "")
4618 g_settings->updateConfigFile(m_path_config.c_str());
4621 void Server::notifyPlayer(const char *name, const std::wstring msg, const bool prepend = true)
4623 Player *player = m_env->getPlayer(name);
4627 SendChatMessage(player->peer_id, std::wstring(L"Server -!- ")+msg);
4629 SendChatMessage(player->peer_id, msg);
4632 bool Server::showFormspec(const char *playername, const std::string &formspec, const std::string &formname)
4634 Player *player = m_env->getPlayer(playername);
4638 infostream<<"showFormspec: couldn't find player:"<<playername<<std::endl;
4642 SendShowFormspecMessage(player->peer_id, formspec, formname);
4646 u32 Server::hudAdd(Player *player, HudElement *form) {
4650 u32 id = hud_get_free_id(player);
4651 if (id < player->hud.size())
4652 player->hud[id] = form;
4654 player->hud.push_back(form);
4656 SendHUDAdd(player->peer_id, id, form);
4660 bool Server::hudRemove(Player *player, u32 id) {
4661 if (!player || id >= player->hud.size() || !player->hud[id])
4664 delete player->hud[id];
4665 player->hud[id] = NULL;
4667 SendHUDRemove(player->peer_id, id);
4671 bool Server::hudChange(Player *player, u32 id, HudElementStat stat, void *data) {
4675 SendHUDChange(player->peer_id, id, stat, data);
4679 bool Server::hudSetFlags(Player *player, u32 flags, u32 mask) {
4683 SendHUDSetFlags(player->peer_id, flags, mask);
4687 void Server::notifyPlayers(const std::wstring msg)
4689 BroadcastChatMessage(msg);
4692 void Server::spawnParticle(const char *playername, v3f pos,
4693 v3f velocity, v3f acceleration,
4694 float expirationtime, float size, bool
4695 collisiondetection, std::string texture)
4697 Player *player = m_env->getPlayer(playername);
4700 SendSpawnParticle(player->peer_id, pos, velocity, acceleration,
4701 expirationtime, size, collisiondetection, texture);
4704 void Server::spawnParticleAll(v3f pos, v3f velocity, v3f acceleration,
4705 float expirationtime, float size,
4706 bool collisiondetection, std::string texture)
4708 SendSpawnParticleAll(pos, velocity, acceleration,
4709 expirationtime, size, collisiondetection, texture);
4712 u32 Server::addParticleSpawner(const char *playername,
4713 u16 amount, float spawntime,
4714 v3f minpos, v3f maxpos,
4715 v3f minvel, v3f maxvel,
4716 v3f minacc, v3f maxacc,
4717 float minexptime, float maxexptime,
4718 float minsize, float maxsize,
4719 bool collisiondetection, std::string texture)
4721 Player *player = m_env->getPlayer(playername);
4726 for(;;) // look for unused particlespawner id
4729 if (std::find(m_particlespawner_ids.begin(),
4730 m_particlespawner_ids.end(), id)
4731 == m_particlespawner_ids.end())
4733 m_particlespawner_ids.push_back(id);
4738 SendAddParticleSpawner(player->peer_id, amount, spawntime,
4739 minpos, maxpos, minvel, maxvel, minacc, maxacc,
4740 minexptime, maxexptime, minsize, maxsize,
4741 collisiondetection, texture, id);
4746 u32 Server::addParticleSpawnerAll(u16 amount, float spawntime,
4747 v3f minpos, v3f maxpos,
4748 v3f minvel, v3f maxvel,
4749 v3f minacc, v3f maxacc,
4750 float minexptime, float maxexptime,
4751 float minsize, float maxsize,
4752 bool collisiondetection, std::string texture)
4755 for(;;) // look for unused particlespawner id
4758 if (std::find(m_particlespawner_ids.begin(),
4759 m_particlespawner_ids.end(), id)
4760 == m_particlespawner_ids.end())
4762 m_particlespawner_ids.push_back(id);
4767 SendAddParticleSpawnerAll(amount, spawntime,
4768 minpos, maxpos, minvel, maxvel, minacc, maxacc,
4769 minexptime, maxexptime, minsize, maxsize,
4770 collisiondetection, texture, id);
4775 void Server::deleteParticleSpawner(const char *playername, u32 id)
4777 Player *player = m_env->getPlayer(playername);
4781 m_particlespawner_ids.erase(
4782 std::remove(m_particlespawner_ids.begin(),
4783 m_particlespawner_ids.end(), id),
4784 m_particlespawner_ids.end());
4785 SendDeleteParticleSpawner(player->peer_id, id);
4788 void Server::deleteParticleSpawnerAll(u32 id)
4790 m_particlespawner_ids.erase(
4791 std::remove(m_particlespawner_ids.begin(),
4792 m_particlespawner_ids.end(), id),
4793 m_particlespawner_ids.end());
4794 SendDeleteParticleSpawnerAll(id);
4797 void Server::queueBlockEmerge(v3s16 blockpos, bool allow_generate)
4799 m_emerge->enqueueBlockEmerge(PEER_ID_INEXISTENT, blockpos, allow_generate);
4802 Inventory* Server::createDetachedInventory(const std::string &name)
4804 if(m_detached_inventories.count(name) > 0){
4805 infostream<<"Server clearing detached inventory \""<<name<<"\""<<std::endl;
4806 delete m_detached_inventories[name];
4808 infostream<<"Server creating detached inventory \""<<name<<"\""<<std::endl;
4810 Inventory *inv = new Inventory(m_itemdef);
4812 m_detached_inventories[name] = inv;
4813 sendDetachedInventoryToAll(name);
4820 BoolScopeSet(bool *dst, bool val):
4823 m_orig_state = *m_dst;
4828 *m_dst = m_orig_state;
4835 // actions: time-reversed list
4836 // Return value: success/failure
4837 bool Server::rollbackRevertActions(const std::list<RollbackAction> &actions,
4838 std::list<std::string> *log)
4840 infostream<<"Server::rollbackRevertActions(len="<<actions.size()<<")"<<std::endl;
4841 ServerMap *map = (ServerMap*)(&m_env->getMap());
4842 // Disable rollback report sink while reverting
4843 BoolScopeSet rollback_scope_disable(&m_rollback_sink_enabled, false);
4845 // Fail if no actions to handle
4846 if(actions.empty()){
4847 log->push_back("Nothing to do.");
4854 for(std::list<RollbackAction>::const_iterator
4855 i = actions.begin();
4856 i != actions.end(); i++)
4858 const RollbackAction &action = *i;
4860 bool success = action.applyRevert(map, this, this);
4863 std::ostringstream os;
4864 os<<"Revert of step ("<<num_tried<<") "<<action.toString()<<" failed";
4865 infostream<<"Map::rollbackRevertActions(): "<<os.str()<<std::endl;
4867 log->push_back(os.str());
4869 std::ostringstream os;
4870 os<<"Successfully reverted step ("<<num_tried<<") "<<action.toString();
4871 infostream<<"Map::rollbackRevertActions(): "<<os.str()<<std::endl;
4873 log->push_back(os.str());
4877 infostream<<"Map::rollbackRevertActions(): "<<num_failed<<"/"<<num_tried
4878 <<" failed"<<std::endl;
4880 // Call it done if less than half failed
4881 return num_failed <= num_tried/2;
4884 // IGameDef interface
4886 IItemDefManager* Server::getItemDefManager()
4890 INodeDefManager* Server::getNodeDefManager()
4894 ICraftDefManager* Server::getCraftDefManager()
4898 ITextureSource* Server::getTextureSource()
4902 IShaderSource* Server::getShaderSource()
4906 u16 Server::allocateUnknownNodeId(const std::string &name)
4908 return m_nodedef->allocateDummy(name);
4910 ISoundManager* Server::getSoundManager()
4912 return &dummySoundManager;
4914 MtEventManager* Server::getEventManager()
4918 IRollbackReportSink* Server::getRollbackReportSink()
4920 if(!m_enable_rollback_recording)
4922 if(!m_rollback_sink_enabled)
4927 IWritableItemDefManager* Server::getWritableItemDefManager()
4931 IWritableNodeDefManager* Server::getWritableNodeDefManager()
4935 IWritableCraftDefManager* Server::getWritableCraftDefManager()
4940 const ModSpec* Server::getModSpec(const std::string &modname)
4942 for(std::vector<ModSpec>::iterator i = m_mods.begin();
4943 i != m_mods.end(); i++){
4944 const ModSpec &mod = *i;
4945 if(mod.name == modname)
4950 void Server::getModNames(std::list<std::string> &modlist)
4952 for(std::vector<ModSpec>::iterator i = m_mods.begin(); i != m_mods.end(); i++)
4954 modlist.push_back(i->name);
4957 std::string Server::getBuiltinLuaPath()
4959 return porting::path_share + DIR_DELIM + "builtin";
4962 v3f findSpawnPos(ServerMap &map)
4964 //return v3f(50,50,50)*BS;
4969 nodepos = v2s16(0,0);
4974 s16 water_level = map.m_mgparams->water_level;
4976 // Try to find a good place a few times
4977 for(s32 i=0; i<1000; i++)
4980 // We're going to try to throw the player to this position
4981 v2s16 nodepos2d = v2s16(
4982 -range + (myrand() % (range * 2)),
4983 -range + (myrand() % (range * 2)));
4985 // Get ground height at point
4986 s16 groundheight = map.findGroundLevel(nodepos2d);
4987 if (groundheight <= water_level) // Don't go underwater
4989 if (groundheight > water_level + 6) // Don't go to high places
4992 nodepos = v3s16(nodepos2d.X, groundheight, nodepos2d.Y);
4993 bool is_good = false;
4995 for (s32 i = 0; i < 10; i++) {
4996 v3s16 blockpos = getNodeBlockPos(nodepos);
4997 map.emergeBlock(blockpos, true);
4998 content_t c = map.getNodeNoEx(nodepos).getContent();
4999 if (c == CONTENT_AIR || c == CONTENT_IGNORE) {
5001 if (air_count >= 2){
5009 // Found a good place
5010 //infostream<<"Searched through "<<i<<" places."<<std::endl;
5016 return intToFloat(nodepos, BS);
5019 PlayerSAO* Server::emergePlayer(const char *name, u16 peer_id)
5021 RemotePlayer *player = NULL;
5022 bool newplayer = false;
5025 Try to get an existing player
5027 player = static_cast<RemotePlayer*>(m_env->getPlayer(name));
5029 // If player is already connected, cancel
5030 if(player != NULL && player->peer_id != 0)
5032 infostream<<"emergePlayer(): Player already connected"<<std::endl;
5037 If player with the wanted peer_id already exists, cancel.
5039 if(m_env->getPlayer(peer_id) != NULL)
5041 infostream<<"emergePlayer(): Player with wrong name but same"
5042 " peer_id already exists"<<std::endl;
5047 Create a new player if it doesn't exist yet
5052 player = new RemotePlayer(this);
5053 player->updateName(name);
5055 /* Set player position */
5056 infostream<<"Server: Finding spawn place for player \""
5057 <<name<<"\""<<std::endl;
5058 v3f pos = findSpawnPos(m_env->getServerMap());
5059 player->setPosition(pos);
5061 /* Add player to environment */
5062 m_env->addPlayer(player);
5066 Create a new player active object
5068 PlayerSAO *playersao = new PlayerSAO(m_env, player, peer_id,
5069 getPlayerEffectivePrivs(player->getName()),
5072 /* Clean up old HUD elements from previous sessions */
5073 player->hud.clear();
5075 /* Add object to environment */
5076 m_env->addActiveObject(playersao);
5080 m_script->on_newplayer(playersao);
5082 m_script->on_joinplayer(playersao);
5087 void Server::handlePeerChange(PeerChange &c)
5089 JMutexAutoLock envlock(m_env_mutex);
5090 JMutexAutoLock conlock(m_con_mutex);
5092 if(c.type == PEER_ADDED)
5099 std::map<u16, RemoteClient*>::iterator n;
5100 n = m_clients.find(c.peer_id);
5101 // The client shouldn't already exist
5102 assert(n == m_clients.end());
5105 RemoteClient *client = new RemoteClient();
5106 client->peer_id = c.peer_id;
5107 m_clients[client->peer_id] = client;
5110 else if(c.type == PEER_REMOVED)
5117 std::map<u16, RemoteClient*>::iterator n;
5118 n = m_clients.find(c.peer_id);
5119 // The client should exist
5120 assert(n != m_clients.end());
5123 Mark objects to be not known by the client
5125 RemoteClient *client = n->second;
5127 for(std::set<u16>::iterator
5128 i = client->m_known_objects.begin();
5129 i != client->m_known_objects.end(); ++i)
5133 ServerActiveObject* obj = m_env->getActiveObject(id);
5135 if(obj && obj->m_known_by_count > 0)
5136 obj->m_known_by_count--;
5140 Clear references to playing sounds
5142 for(std::map<s32, ServerPlayingSound>::iterator
5143 i = m_playing_sounds.begin();
5144 i != m_playing_sounds.end();)
5146 ServerPlayingSound &psound = i->second;
5147 psound.clients.erase(c.peer_id);
5148 if(psound.clients.size() == 0)
5149 m_playing_sounds.erase(i++);
5154 Player *player = m_env->getPlayer(c.peer_id);
5156 // Collect information about leaving in chat
5157 std::wstring message;
5161 std::wstring name = narrow_to_wide(player->getName());
5164 message += L" left the game.";
5166 message += L" (timed out)";
5170 /* Run scripts and remove from environment */
5174 PlayerSAO *playersao = player->getPlayerSAO();
5177 m_script->on_leaveplayer(playersao);
5179 playersao->disconnected();
5189 std::ostringstream os(std::ios_base::binary);
5190 for(std::map<u16, RemoteClient*>::iterator
5191 i = m_clients.begin();
5192 i != m_clients.end(); ++i)
5194 RemoteClient *client = i->second;
5195 assert(client->peer_id == i->first);
5196 if(client->serialization_version == SER_FMT_VER_INVALID)
5199 Player *player = m_env->getPlayer(client->peer_id);
5202 // Get name of player
5203 os<<player->getName()<<" ";
5206 actionstream<<player->getName()<<" "
5207 <<(c.timeout?"times out.":"leaves game.")
5208 <<" List of players: "
5209 <<os.str()<<std::endl;
5214 delete m_clients[c.peer_id];
5215 m_clients.erase(c.peer_id);
5217 // Send player info to all remaining clients
5218 //SendPlayerInfos();
5220 // Send leave chat message to all remaining clients
5221 if(message.length() != 0)
5222 BroadcastChatMessage(message);
5231 void Server::handlePeerChanges()
5233 while(m_peer_change_queue.size() > 0)
5235 PeerChange c = m_peer_change_queue.pop_front();
5237 verbosestream<<"Server: Handling peer change: "
5238 <<"id="<<c.peer_id<<", timeout="<<c.timeout
5241 handlePeerChange(c);
5245 void dedicated_server_loop(Server &server, bool &kill)
5247 DSTACK(__FUNCTION_NAME);
5249 verbosestream<<"dedicated_server_loop()"<<std::endl;
5251 IntervalLimiter m_profiler_interval;
5255 float steplen = g_settings->getFloat("dedicated_server_step");
5256 // This is kind of a hack but can be done like this
5257 // because server.step() is very light
5259 ScopeProfiler sp(g_profiler, "dedicated server sleep");
5260 sleep_ms((int)(steplen*1000.0));
5262 server.step(steplen);
5264 if(server.getShutdownRequested() || kill)
5266 infostream<<"Dedicated server quitting"<<std::endl;
5268 if(g_settings->getBool("server_announce") == true)
5269 ServerList::sendAnnounce("delete");
5277 float profiler_print_interval =
5278 g_settings->getFloat("profiler_print_interval");
5279 if(profiler_print_interval != 0)
5281 if(m_profiler_interval.step(steplen, profiler_print_interval))
5283 infostream<<"Profiler:"<<std::endl;
5284 g_profiler->print(infostream);
5285 g_profiler->clear();