3 Copyright (C) 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.
22 #include "clientserver.h"
23 #include "jmutexautolock.h"
27 #include "mapsector.h"
28 #include "mapblock_mesh.h"
33 #include "nodemetadata.h"
37 #include <IFileSystem.h>
40 #include "clientmap.h"
41 #include "filecache.h"
43 #include "util/string.h"
45 #include "IMeshCache.h"
46 #include "util/serialize.h"
50 #include <curl/curl.h>
53 static std::string getMediaCacheDir()
55 return porting::path_user + DIR_DELIM + "cache" + DIR_DELIM + "media";
62 QueuedMeshUpdate::QueuedMeshUpdate():
65 ack_block_to_server(false)
69 QueuedMeshUpdate::~QueuedMeshUpdate()
79 MeshUpdateQueue::MeshUpdateQueue()
84 MeshUpdateQueue::~MeshUpdateQueue()
86 JMutexAutoLock lock(m_mutex);
88 for(std::vector<QueuedMeshUpdate*>::iterator
90 i != m_queue.end(); i++)
92 QueuedMeshUpdate *q = *i;
98 peer_id=0 adds with nobody to send to
100 void MeshUpdateQueue::addBlock(v3s16 p, MeshMakeData *data, bool ack_block_to_server, bool urgent)
102 DSTACK(__FUNCTION_NAME);
106 JMutexAutoLock lock(m_mutex);
112 Find if block is already in queue.
113 If it is, update the data and quit.
115 for(std::vector<QueuedMeshUpdate*>::iterator
117 i != m_queue.end(); i++)
119 QueuedMeshUpdate *q = *i;
125 if(ack_block_to_server)
126 q->ack_block_to_server = true;
134 QueuedMeshUpdate *q = new QueuedMeshUpdate;
137 q->ack_block_to_server = ack_block_to_server;
138 m_queue.push_back(q);
141 // Returned pointer must be deleted
142 // Returns NULL if queue is empty
143 QueuedMeshUpdate * MeshUpdateQueue::pop()
145 JMutexAutoLock lock(m_mutex);
147 bool must_be_urgent = !m_urgents.empty();
148 for(std::vector<QueuedMeshUpdate*>::iterator
150 i != m_queue.end(); i++)
152 QueuedMeshUpdate *q = *i;
153 if(must_be_urgent && m_urgents.count(q->p) == 0)
156 m_urgents.erase(q->p);
166 void * MeshUpdateThread::Thread()
170 log_register_thread("MeshUpdateThread");
172 DSTACK(__FUNCTION_NAME);
174 BEGIN_DEBUG_EXCEPTION_HANDLER
178 /*// Wait for output queue to flush.
179 // Allow 2 in queue, this makes less frametime jitter.
180 // Umm actually, there is no much difference
181 if(m_queue_out.size() >= 2)
187 QueuedMeshUpdate *q = m_queue_in.pop();
194 ScopeProfiler sp(g_profiler, "Client: Mesh making");
196 MapBlockMesh *mesh_new = new MapBlockMesh(q->data);
197 if(mesh_new->getMesh()->getMeshBufferCount() == 0)
206 r.ack_block_to_server = q->ack_block_to_server;
208 /*infostream<<"MeshUpdateThread: Processed "
209 <<"("<<q->p.X<<","<<q->p.Y<<","<<q->p.Z<<")"
212 m_queue_out.push_back(r);
217 END_DEBUG_EXCEPTION_HANDLER(errorstream)
222 void * MediaFetchThread::Thread()
226 log_register_thread("MediaFetchThread");
228 DSTACK(__FUNCTION_NAME);
230 BEGIN_DEBUG_EXCEPTION_HANDLER
235 for (std::list<MediaRequest>::iterator i = m_file_requests.begin();
236 i != m_file_requests.end(); ++i) {
237 curl = curl_easy_init();
239 curl_easy_setopt(curl, CURLOPT_NOSIGNAL, 1);
240 curl_easy_setopt(curl, CURLOPT_URL, (m_remote_url + i->name).c_str());
241 curl_easy_setopt(curl, CURLOPT_FAILONERROR, true);
242 std::ostringstream stream;
243 curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, curl_write_data);
244 curl_easy_setopt(curl, CURLOPT_WRITEDATA, &stream);
245 res = curl_easy_perform(curl);
246 if (res == CURLE_OK) {
247 std::string data = stream.str();
248 m_file_data.push_back(make_pair(i->name, data));
250 m_failed.push_back(*i);
251 infostream << "cURL request failed for " << i->name << std::endl;
253 curl_easy_cleanup(curl);
257 END_DEBUG_EXCEPTION_HANDLER(errorstream)
263 IrrlichtDevice *device,
264 const char *playername,
265 std::string password,
266 MapDrawControl &control,
267 IWritableTextureSource *tsrc,
268 IWritableShaderSource *shsrc,
269 IWritableItemDefManager *itemdef,
270 IWritableNodeDefManager *nodedef,
271 ISoundManager *sound,
272 MtEventManager *event
280 m_mesh_update_thread(this),
282 new ClientMap(this, this, control,
283 device->getSceneManager()->getRootSceneNode(),
284 device->getSceneManager(), 666),
285 device->getSceneManager(),
288 m_con(PROTOCOL_ID, 512, CONNECTION_TIMEOUT, this),
290 m_server_ser_ver(SER_FMT_VER_INVALID),
292 m_inventory_updated(false),
293 m_inventory_from_server(NULL),
294 m_inventory_from_server_age(0.0),
299 m_password(password),
300 m_access_denied(false),
301 m_media_cache(getMediaCacheDir()),
302 m_media_receive_started(false),
304 m_media_received_count(0),
305 m_itemdef_received(false),
306 m_nodedef_received(false),
307 m_time_of_day_set(false),
308 m_last_time_of_day_f(-1),
309 m_time_of_day_update_timer(0),
310 m_recommended_send_interval(0.1),
311 m_removed_sounds_check_timer(0)
313 m_packetcounter_timer = 0.0;
314 //m_delete_unused_sectors_timer = 0.0;
315 m_connection_reinit_timer = 0.0;
316 m_avg_rtt_timer = 0.0;
317 m_playerpos_send_timer = 0.0;
318 m_ignore_damage_timer = 0.0;
320 // Build main texture atlas, now that the GameDef exists (that is, us)
321 if(g_settings->getBool("enable_texture_atlas"))
322 m_tsrc->buildMainAtlas(this);
324 infostream<<"Not building texture atlas."<<std::endl;
330 Player *player = new LocalPlayer(this);
332 player->updateName(playername);
334 m_env.addPlayer(player);
337 for (size_t i = 0; i < g_settings->getU16("media_fetch_threads"); ++i)
338 m_media_fetch_threads.push_back(new MediaFetchThread(this));
344 //JMutexAutoLock conlock(m_con_mutex); //bulk comment-out
348 m_mesh_update_thread.setRun(false);
349 while(m_mesh_update_thread.IsRunning())
352 delete m_inventory_from_server;
354 // Delete detached inventories
356 for(std::map<std::string, Inventory*>::iterator
357 i = m_detached_inventories.begin();
358 i != m_detached_inventories.end(); i++){
363 for (std::list<MediaFetchThread*>::iterator i = m_media_fetch_threads.begin();
364 i != m_media_fetch_threads.end(); ++i)
368 void Client::connect(Address address)
370 DSTACK(__FUNCTION_NAME);
371 //JMutexAutoLock lock(m_con_mutex); //bulk comment-out
372 m_con.SetTimeoutMs(0);
373 m_con.Connect(address);
376 bool Client::connectedAndInitialized()
378 //JMutexAutoLock lock(m_con_mutex); //bulk comment-out
380 if(m_con.Connected() == false)
383 if(m_server_ser_ver == SER_FMT_VER_INVALID)
389 void Client::step(float dtime)
391 DSTACK(__FUNCTION_NAME);
397 if(m_ignore_damage_timer > dtime)
398 m_ignore_damage_timer -= dtime;
400 m_ignore_damage_timer = 0.0;
402 m_animation_time += dtime;
403 if(m_animation_time > 60.0)
404 m_animation_time -= 60.0;
406 m_time_of_day_update_timer += dtime;
408 //infostream<<"Client steps "<<dtime<<std::endl;
411 //TimeTaker timer("ReceiveAll()", m_device);
417 //TimeTaker timer("m_con_mutex + m_con.RunTimeouts()", m_device);
419 //JMutexAutoLock lock(m_con_mutex); //bulk comment-out
420 m_con.RunTimeouts(dtime);
427 float &counter = m_packetcounter_timer;
433 infostream<<"Client packetcounter (20s):"<<std::endl;
434 m_packetcounter.print(infostream);
435 m_packetcounter.clear();
439 // Get connection status
440 bool connected = connectedAndInitialized();
445 Delete unused sectors
447 NOTE: This jams the game for a while because deleting sectors
451 float &counter = m_delete_unused_sectors_timer;
459 //JMutexAutoLock lock(m_env_mutex); //bulk comment-out
461 core::list<v3s16> deleted_blocks;
463 float delete_unused_sectors_timeout =
464 g_settings->getFloat("client_delete_unused_sectors_timeout");
466 // Delete sector blocks
467 /*u32 num = m_env.getMap().unloadUnusedData
468 (delete_unused_sectors_timeout,
469 true, &deleted_blocks);*/
471 // Delete whole sectors
472 m_env.getMap().unloadUnusedData
473 (delete_unused_sectors_timeout,
476 if(deleted_blocks.size() > 0)
478 /*infostream<<"Client: Deleted blocks of "<<num
479 <<" unused sectors"<<std::endl;*/
480 /*infostream<<"Client: Deleted "<<num
481 <<" unused sectors"<<std::endl;*/
487 // Env is locked so con can be locked.
488 //JMutexAutoLock lock(m_con_mutex); //bulk comment-out
490 core::list<v3s16>::Iterator i = deleted_blocks.begin();
491 core::list<v3s16> sendlist;
494 if(sendlist.size() == 255 || i == deleted_blocks.end())
496 if(sendlist.size() == 0)
505 u32 replysize = 2+1+6*sendlist.size();
506 SharedBuffer<u8> reply(replysize);
507 writeU16(&reply[0], TOSERVER_DELETEDBLOCKS);
508 reply[2] = sendlist.size();
510 for(core::list<v3s16>::Iterator
511 j = sendlist.begin();
512 j != sendlist.end(); j++)
514 writeV3S16(&reply[2+1+6*k], *j);
517 m_con.Send(PEER_ID_SERVER, 1, reply, true);
519 if(i == deleted_blocks.end())
525 sendlist.push_back(*i);
533 if(connected == false)
535 float &counter = m_connection_reinit_timer;
541 //JMutexAutoLock envlock(m_env_mutex); //bulk comment-out
543 Player *myplayer = m_env.getLocalPlayer();
544 assert(myplayer != NULL);
546 // Send TOSERVER_INIT
547 // [0] u16 TOSERVER_INIT
548 // [2] u8 SER_FMT_VER_HIGHEST
549 // [3] u8[20] player_name
550 // [23] u8[28] password (new in some version)
551 // [51] u16 minimum supported network protocol version (added sometime)
552 // [53] u16 maximum supported network protocol version (added later than the previous one)
553 SharedBuffer<u8> data(2+1+PLAYERNAME_SIZE+PASSWORD_SIZE+2+2);
554 writeU16(&data[0], TOSERVER_INIT);
555 writeU8(&data[2], SER_FMT_VER_HIGHEST);
557 memset((char*)&data[3], 0, PLAYERNAME_SIZE);
558 snprintf((char*)&data[3], PLAYERNAME_SIZE, "%s", myplayer->getName());
560 /*infostream<<"Client: sending initial password hash: \""<<m_password<<"\""
563 memset((char*)&data[23], 0, PASSWORD_SIZE);
564 snprintf((char*)&data[23], PASSWORD_SIZE, "%s", m_password.c_str());
566 writeU16(&data[51], CLIENT_PROTOCOL_VERSION_MIN);
567 writeU16(&data[53], CLIENT_PROTOCOL_VERSION_MAX);
569 // Send as unreliable
570 Send(0, data, false);
573 // Not connected, return
578 Do stuff if connected
582 Run Map's timers and unload unused data
584 const float map_timer_and_unload_dtime = 5.25;
585 if(m_map_timer_and_unload_interval.step(dtime, map_timer_and_unload_dtime))
587 ScopeProfiler sp(g_profiler, "Client: map timer and unload");
588 std::list<v3s16> deleted_blocks;
589 m_env.getMap().timerUpdate(map_timer_and_unload_dtime,
590 g_settings->getFloat("client_unload_unused_data_timeout"),
593 /*if(deleted_blocks.size() > 0)
594 infostream<<"Client: Unloaded "<<deleted_blocks.size()
595 <<" unused blocks"<<std::endl;*/
599 NOTE: This loop is intentionally iterated the way it is.
602 std::list<v3s16>::iterator i = deleted_blocks.begin();
603 std::list<v3s16> sendlist;
606 if(sendlist.size() == 255 || i == deleted_blocks.end())
608 if(sendlist.size() == 0)
617 u32 replysize = 2+1+6*sendlist.size();
618 SharedBuffer<u8> reply(replysize);
619 writeU16(&reply[0], TOSERVER_DELETEDBLOCKS);
620 reply[2] = sendlist.size();
622 for(std::list<v3s16>::iterator
623 j = sendlist.begin();
624 j != sendlist.end(); ++j)
626 writeV3S16(&reply[2+1+6*k], *j);
629 m_con.Send(PEER_ID_SERVER, 1, reply, true);
631 if(i == deleted_blocks.end())
637 sendlist.push_back(*i);
647 //JMutexAutoLock lock(m_env_mutex); //bulk comment-out
649 // Control local player (0ms)
650 LocalPlayer *player = m_env.getLocalPlayer();
651 assert(player != NULL);
652 player->applyControl(dtime);
654 //TimeTaker envtimer("env step", m_device);
663 ClientEnvEvent event = m_env.getClientEvent();
664 if(event.type == CEE_NONE)
668 else if(event.type == CEE_PLAYER_DAMAGE)
670 if(m_ignore_damage_timer <= 0)
672 u8 damage = event.player_damage.amount;
674 if(event.player_damage.send_to_server)
677 // Add to ClientEvent queue
679 event.type = CE_PLAYER_DAMAGE;
680 event.player_damage.amount = damage;
681 m_client_event_queue.push_back(event);
691 float &counter = m_avg_rtt_timer;
696 //JMutexAutoLock lock(m_con_mutex); //bulk comment-out
697 // connectedAndInitialized() is true, peer exists.
698 float avg_rtt = m_con.GetPeerAvgRTT(PEER_ID_SERVER);
699 infostream<<"Client: avg_rtt="<<avg_rtt<<std::endl;
704 Send player position to server
707 float &counter = m_playerpos_send_timer;
709 if(counter >= m_recommended_send_interval)
717 Replace updated meshes
720 //JMutexAutoLock lock(m_env_mutex); //bulk comment-out
722 //TimeTaker timer("** Processing mesh update result queue");
725 /*infostream<<"Mesh update result queue size is "
726 <<m_mesh_update_thread.m_queue_out.size()
729 int num_processed_meshes = 0;
730 while(!m_mesh_update_thread.m_queue_out.empty())
732 num_processed_meshes++;
733 MeshUpdateResult r = m_mesh_update_thread.m_queue_out.pop_front();
734 MapBlock *block = m_env.getMap().getBlockNoCreateNoEx(r.p);
737 //JMutexAutoLock lock(block->mesh_mutex);
739 // Delete the old mesh
740 if(block->mesh != NULL)
742 // TODO: Remove hardware buffers of meshbuffers of block->mesh
747 // Replace with the new mesh
748 block->mesh = r.mesh;
750 if(r.ack_block_to_server)
752 /*infostream<<"Client: ACK block ("<<r.p.X<<","<<r.p.Y
753 <<","<<r.p.Z<<")"<<std::endl;*/
764 u32 replysize = 2+1+6;
765 SharedBuffer<u8> reply(replysize);
766 writeU16(&reply[0], TOSERVER_GOTBLOCKS);
768 writeV3S16(&reply[3], r.p);
770 m_con.Send(PEER_ID_SERVER, 1, reply, true);
773 if(num_processed_meshes > 0)
774 g_profiler->graphAdd("num_processed_meshes", num_processed_meshes);
780 if (m_media_receive_started) {
781 bool all_stopped = true;
782 for (std::list<MediaFetchThread*>::iterator thread = m_media_fetch_threads.begin();
783 thread != m_media_fetch_threads.end(); ++thread) {
784 all_stopped &= !(*thread)->IsRunning();
785 while (!(*thread)->m_file_data.empty()) {
786 std::pair <std::string, std::string> out = (*thread)->m_file_data.pop_front();
787 ++m_media_received_count;
789 bool success = loadMedia(out.second, out.first);
791 verbosestream<<"Client: Loaded received media: "
792 <<"\""<<out.first<<"\". Caching."<<std::endl;
794 infostream<<"Client: Failed to load received media: "
795 <<"\""<<out.first<<"\". Not caching."<<std::endl;
799 bool did = fs::CreateAllDirs(getMediaCacheDir());
801 errorstream<<"Could not create media cache directory"
806 std::map<std::string, std::string>::iterator n;
807 n = m_media_name_sha1_map.find(out.first);
808 if(n == m_media_name_sha1_map.end())
809 errorstream<<"The server sent a file that has not "
810 <<"been announced."<<std::endl;
812 m_media_cache.update_sha1(out.second);
817 std::list<MediaRequest> fetch_failed;
818 for (std::list<MediaFetchThread*>::iterator thread = m_media_fetch_threads.begin();
819 thread != m_media_fetch_threads.end(); ++thread) {
820 for (std::list<MediaRequest>::iterator request = (*thread)->m_failed.begin();
821 request != (*thread)->m_failed.end(); ++request)
822 fetch_failed.push_back(*request);
823 (*thread)->m_failed.clear();
825 if (fetch_failed.size() > 0) {
826 infostream << "Failed to remote-fetch " << fetch_failed.size() << " files. "
827 << "Requesting them the usual way." << std::endl;
828 request_media(fetch_failed);
834 If the server didn't update the inventory in a while, revert
835 the local inventory (so the player notices the lag problem
836 and knows something is wrong).
838 if(m_inventory_from_server)
840 float interval = 10.0;
841 float count_before = floor(m_inventory_from_server_age / interval);
843 m_inventory_from_server_age += dtime;
845 float count_after = floor(m_inventory_from_server_age / interval);
847 if(count_after != count_before)
849 // Do this every <interval> seconds after TOCLIENT_INVENTORY
850 // Reset the locally changed inventory to the authoritative inventory
851 Player *player = m_env.getLocalPlayer();
852 player->inventory = *m_inventory_from_server;
853 m_inventory_updated = true;
858 Update positions of sounds attached to objects
861 for(std::map<int, u16>::iterator
862 i = m_sounds_to_objects.begin();
863 i != m_sounds_to_objects.end(); i++)
865 int client_id = i->first;
866 u16 object_id = i->second;
867 ClientActiveObject *cao = m_env.getActiveObject(object_id);
870 v3f pos = cao->getPosition();
871 m_sound->updateSoundPosition(client_id, pos);
876 Handle removed remotely initiated sounds
878 m_removed_sounds_check_timer += dtime;
879 if(m_removed_sounds_check_timer >= 2.32)
881 m_removed_sounds_check_timer = 0;
882 // Find removed sounds and clear references to them
883 std::set<s32> removed_server_ids;
884 for(std::map<s32, int>::iterator
885 i = m_sounds_server_to_client.begin();
886 i != m_sounds_server_to_client.end();)
888 s32 server_id = i->first;
889 int client_id = i->second;
891 if(!m_sound->soundExists(client_id)){
892 m_sounds_server_to_client.erase(server_id);
893 m_sounds_client_to_server.erase(client_id);
894 m_sounds_to_objects.erase(client_id);
895 removed_server_ids.insert(server_id);
899 if(removed_server_ids.size() != 0)
901 std::ostringstream os(std::ios_base::binary);
902 writeU16(os, TOSERVER_REMOVED_SOUNDS);
903 writeU16(os, removed_server_ids.size());
904 for(std::set<s32>::iterator i = removed_server_ids.begin();
905 i != removed_server_ids.end(); i++)
907 std::string s = os.str();
908 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
915 bool Client::loadMedia(const std::string &data, const std::string &filename)
917 // Silly irrlicht's const-incorrectness
918 Buffer<char> data_rw(data.c_str(), data.size());
922 const char *image_ext[] = {
923 ".png", ".jpg", ".bmp", ".tga",
924 ".pcx", ".ppm", ".psd", ".wal", ".rgb",
927 name = removeStringEnd(filename, image_ext);
930 verbosestream<<"Client: Attempting to load image "
931 <<"file \""<<filename<<"\""<<std::endl;
933 io::IFileSystem *irrfs = m_device->getFileSystem();
934 video::IVideoDriver *vdrv = m_device->getVideoDriver();
936 // Create an irrlicht memory file
937 io::IReadFile *rfile = irrfs->createMemoryReadFile(
938 *data_rw, data_rw.getSize(), "_tempreadfile");
941 video::IImage *img = vdrv->createImageFromFile(rfile);
943 errorstream<<"Client: Cannot create image from data of "
944 <<"file \""<<filename<<"\""<<std::endl;
949 m_tsrc->insertSourceImage(filename, img);
956 const char *sound_ext[] = {
957 ".0.ogg", ".1.ogg", ".2.ogg", ".3.ogg", ".4.ogg",
958 ".5.ogg", ".6.ogg", ".7.ogg", ".8.ogg", ".9.ogg",
961 name = removeStringEnd(filename, sound_ext);
964 verbosestream<<"Client: Attempting to load sound "
965 <<"file \""<<filename<<"\""<<std::endl;
966 m_sound->loadSoundData(name, data);
970 const char *model_ext[] = {
971 ".x", ".b3d", ".md2", ".obj",
974 name = removeStringEnd(filename, model_ext);
977 verbosestream<<"Client: Storing model into Irrlicht: "
978 <<"\""<<filename<<"\""<<std::endl;
980 io::IFileSystem *irrfs = m_device->getFileSystem();
981 io::IReadFile *rfile = irrfs->createMemoryReadFile(
982 *data_rw, data_rw.getSize(), filename.c_str());
985 scene::ISceneManager *smgr = m_device->getSceneManager();
986 scene::IAnimatedMesh *mesh = smgr->getMesh(rfile);
987 smgr->getMeshCache()->addMesh(filename.c_str(), mesh);
992 errorstream<<"Client: Don't know how to load file \""
993 <<filename<<"\""<<std::endl;
997 // Virtual methods from con::PeerHandler
998 void Client::peerAdded(con::Peer *peer)
1000 infostream<<"Client::peerAdded(): peer->id="
1001 <<peer->id<<std::endl;
1003 void Client::deletingPeer(con::Peer *peer, bool timeout)
1005 infostream<<"Client::deletingPeer(): "
1006 "Server Peer is getting deleted "
1007 <<"(timeout="<<timeout<<")"<<std::endl;
1012 u16 number of files requested
1018 void Client::request_media(const std::list<MediaRequest> &file_requests)
1020 std::ostringstream os(std::ios_base::binary);
1021 writeU16(os, TOSERVER_REQUEST_MEDIA);
1022 writeU16(os, file_requests.size());
1024 for(std::list<MediaRequest>::const_iterator i = file_requests.begin();
1025 i != file_requests.end(); ++i) {
1026 os<<serializeString(i->name);
1030 std::string s = os.str();
1031 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
1033 Send(0, data, true);
1034 infostream<<"Client: Sending media request list to server ("
1035 <<file_requests.size()<<" files)"<<std::endl;
1038 void Client::ReceiveAll()
1040 DSTACK(__FUNCTION_NAME);
1041 u32 start_ms = porting::getTimeMs();
1044 // Limit time even if there would be huge amounts of data to
1046 if(porting::getTimeMs() > start_ms + 100)
1051 g_profiler->graphAdd("client_received_packets", 1);
1053 catch(con::NoIncomingDataException &e)
1057 catch(con::InvalidIncomingDataException &e)
1059 infostream<<"Client::ReceiveAll(): "
1060 "InvalidIncomingDataException: what()="
1061 <<e.what()<<std::endl;
1066 void Client::Receive()
1068 DSTACK(__FUNCTION_NAME);
1069 SharedBuffer<u8> data;
1073 //TimeTaker t1("con mutex and receive", m_device);
1074 //JMutexAutoLock lock(m_con_mutex); //bulk comment-out
1075 datasize = m_con.Receive(sender_peer_id, data);
1077 //TimeTaker t1("ProcessData", m_device);
1078 ProcessData(*data, datasize, sender_peer_id);
1082 sender_peer_id given to this shall be quaranteed to be a valid peer
1084 void Client::ProcessData(u8 *data, u32 datasize, u16 sender_peer_id)
1086 DSTACK(__FUNCTION_NAME);
1088 // Ignore packets that don't even fit a command
1091 m_packetcounter.add(60000);
1095 ToClientCommand command = (ToClientCommand)readU16(&data[0]);
1097 //infostream<<"Client: received command="<<command<<std::endl;
1098 m_packetcounter.add((u16)command);
1101 If this check is removed, be sure to change the queue
1102 system to know the ids
1104 if(sender_peer_id != PEER_ID_SERVER)
1106 infostream<<"Client::ProcessData(): Discarding data not "
1107 "coming from server: peer_id="<<sender_peer_id
1112 u8 ser_version = m_server_ser_ver;
1114 //infostream<<"Client received command="<<(int)command<<std::endl;
1116 if(command == TOCLIENT_INIT)
1121 u8 deployed = data[2];
1123 infostream<<"Client: TOCLIENT_INIT received with "
1124 "deployed="<<((int)deployed&0xff)<<std::endl;
1126 if(deployed < SER_FMT_VER_LOWEST
1127 || deployed > SER_FMT_VER_HIGHEST)
1129 infostream<<"Client: TOCLIENT_INIT: Server sent "
1130 <<"unsupported ser_fmt_ver"<<std::endl;
1134 m_server_ser_ver = deployed;
1136 // Get player position
1137 v3s16 playerpos_s16(0, BS*2+BS*20, 0);
1138 if(datasize >= 2+1+6)
1139 playerpos_s16 = readV3S16(&data[2+1]);
1140 v3f playerpos_f = intToFloat(playerpos_s16, BS) - v3f(0, BS/2, 0);
1143 //JMutexAutoLock envlock(m_env_mutex); //bulk comment-out
1145 // Set player position
1146 Player *player = m_env.getLocalPlayer();
1147 assert(player != NULL);
1148 player->setPosition(playerpos_f);
1151 if(datasize >= 2+1+6+8)
1154 m_map_seed = readU64(&data[2+1+6]);
1155 infostream<<"Client: received map seed: "<<m_map_seed<<std::endl;
1158 if(datasize >= 2+1+6+8+4)
1161 m_recommended_send_interval = readF1000(&data[2+1+6+8]);
1162 infostream<<"Client: received recommended send interval "
1163 <<m_recommended_send_interval<<std::endl;
1168 SharedBuffer<u8> reply(replysize);
1169 writeU16(&reply[0], TOSERVER_INIT2);
1171 m_con.Send(PEER_ID_SERVER, 1, reply, true);
1176 if(command == TOCLIENT_ACCESS_DENIED)
1178 // The server didn't like our password. Note, this needs
1179 // to be processed even if the serialisation format has
1180 // not been agreed yet, the same as TOCLIENT_INIT.
1181 m_access_denied = true;
1182 m_access_denied_reason = L"Unknown";
1185 std::string datastring((char*)&data[2], datasize-2);
1186 std::istringstream is(datastring, std::ios_base::binary);
1187 m_access_denied_reason = deSerializeWideString(is);
1192 if(ser_version == SER_FMT_VER_INVALID)
1194 infostream<<"Client: Server serialization"
1195 " format invalid or not initialized."
1196 " Skipping incoming command="<<command<<std::endl;
1200 // Just here to avoid putting the two if's together when
1201 // making some copypasta
1204 if(command == TOCLIENT_REMOVENODE)
1209 p.X = readS16(&data[2]);
1210 p.Y = readS16(&data[4]);
1211 p.Z = readS16(&data[6]);
1213 //TimeTaker t1("TOCLIENT_REMOVENODE");
1217 else if(command == TOCLIENT_ADDNODE)
1219 if(datasize < 8 + MapNode::serializedLength(ser_version))
1223 p.X = readS16(&data[2]);
1224 p.Y = readS16(&data[4]);
1225 p.Z = readS16(&data[6]);
1227 //TimeTaker t1("TOCLIENT_ADDNODE");
1230 n.deSerialize(&data[8], ser_version);
1234 else if(command == TOCLIENT_BLOCKDATA)
1236 // Ignore too small packet
1241 p.X = readS16(&data[2]);
1242 p.Y = readS16(&data[4]);
1243 p.Z = readS16(&data[6]);
1245 /*infostream<<"Client: Thread: BLOCKDATA for ("
1246 <<p.X<<","<<p.Y<<","<<p.Z<<")"<<std::endl;*/
1247 /*infostream<<"Client: Thread: BLOCKDATA for ("
1248 <<p.X<<","<<p.Y<<","<<p.Z<<")"<<std::endl;*/
1250 std::string datastring((char*)&data[8], datasize-8);
1251 std::istringstream istr(datastring, std::ios_base::binary);
1256 v2s16 p2d(p.X, p.Z);
1257 sector = m_env.getMap().emergeSector(p2d);
1259 assert(sector->getPos() == p2d);
1261 //TimeTaker timer("MapBlock deSerialize");
1264 block = sector->getBlockNoCreateNoEx(p.Y);
1268 Update an existing block
1270 //infostream<<"Updating"<<std::endl;
1271 block->deSerialize(istr, ser_version, false);
1278 //infostream<<"Creating new"<<std::endl;
1279 block = new MapBlock(&m_env.getMap(), p, this);
1280 block->deSerialize(istr, ser_version, false);
1281 sector->insertBlock(block);
1295 u32 replysize = 2+1+6;
1296 SharedBuffer<u8> reply(replysize);
1297 writeU16(&reply[0], TOSERVER_GOTBLOCKS);
1299 writeV3S16(&reply[3], p);
1301 m_con.Send(PEER_ID_SERVER, 1, reply, true);
1305 Add it to mesh update queue and set it to be acknowledged after update.
1307 //infostream<<"Adding mesh update task for received block"<<std::endl;
1308 addUpdateMeshTaskWithEdge(p, true);
1310 else if(command == TOCLIENT_INVENTORY)
1315 //TimeTaker t1("Parsing TOCLIENT_INVENTORY", m_device);
1318 //TimeTaker t2("mutex locking", m_device);
1319 //JMutexAutoLock envlock(m_env_mutex); //bulk comment-out
1322 //TimeTaker t3("istringstream init", m_device);
1323 std::string datastring((char*)&data[2], datasize-2);
1324 std::istringstream is(datastring, std::ios_base::binary);
1327 //m_env.printPlayers(infostream);
1329 //TimeTaker t4("player get", m_device);
1330 Player *player = m_env.getLocalPlayer();
1331 assert(player != NULL);
1334 //TimeTaker t1("inventory.deSerialize()", m_device);
1335 player->inventory.deSerialize(is);
1338 m_inventory_updated = true;
1340 delete m_inventory_from_server;
1341 m_inventory_from_server = new Inventory(player->inventory);
1342 m_inventory_from_server_age = 0.0;
1344 //infostream<<"Client got player inventory:"<<std::endl;
1345 //player->inventory.print(infostream);
1348 else if(command == TOCLIENT_TIME_OF_DAY)
1353 u16 time_of_day = readU16(&data[2]);
1354 time_of_day = time_of_day % 24000;
1355 //infostream<<"Client: time_of_day="<<time_of_day<<std::endl;
1356 float time_speed = 0;
1357 if(datasize >= 2 + 2 + 4){
1358 time_speed = readF1000(&data[4]);
1360 // Old message; try to approximate speed of time by ourselves
1361 float time_of_day_f = (float)time_of_day / 24000.0;
1362 float tod_diff_f = 0;
1363 if(time_of_day_f < 0.2 && m_last_time_of_day_f > 0.8)
1364 tod_diff_f = time_of_day_f - m_last_time_of_day_f + 1.0;
1366 tod_diff_f = time_of_day_f - m_last_time_of_day_f;
1367 m_last_time_of_day_f = time_of_day_f;
1368 float time_diff = m_time_of_day_update_timer;
1369 m_time_of_day_update_timer = 0;
1370 if(m_time_of_day_set){
1371 time_speed = 3600.0*24.0 * tod_diff_f / time_diff;
1372 infostream<<"Client: Measured time_of_day speed (old format): "
1373 <<time_speed<<" tod_diff_f="<<tod_diff_f
1374 <<" time_diff="<<time_diff<<std::endl;
1378 // Update environment
1379 m_env.setTimeOfDay(time_of_day);
1380 m_env.setTimeOfDaySpeed(time_speed);
1381 m_time_of_day_set = true;
1383 u32 dr = m_env.getDayNightRatio();
1384 verbosestream<<"Client: time_of_day="<<time_of_day
1385 <<" time_speed="<<time_speed
1386 <<" dr="<<dr<<std::endl;
1388 else if(command == TOCLIENT_CHAT_MESSAGE)
1396 std::string datastring((char*)&data[2], datasize-2);
1397 std::istringstream is(datastring, std::ios_base::binary);
1400 is.read((char*)buf, 2);
1401 u16 len = readU16(buf);
1403 std::wstring message;
1404 for(u16 i=0; i<len; i++)
1406 is.read((char*)buf, 2);
1407 message += (wchar_t)readU16(buf);
1410 /*infostream<<"Client received chat message: "
1411 <<wide_to_narrow(message)<<std::endl;*/
1413 m_chat_queue.push_back(message);
1415 else if(command == TOCLIENT_ACTIVE_OBJECT_REMOVE_ADD)
1417 //if(g_settings->getBool("enable_experimental"))
1421 u16 count of removed objects
1422 for all removed objects {
1425 u16 count of added objects
1426 for all added objects {
1429 u32 initialization data length
1430 string initialization data
1435 // Get all data except the command number
1436 std::string datastring((char*)&data[2], datasize-2);
1437 // Throw them in an istringstream
1438 std::istringstream is(datastring, std::ios_base::binary);
1442 // Read removed objects
1444 u16 removed_count = readU16((u8*)buf);
1445 for(u16 i=0; i<removed_count; i++)
1448 u16 id = readU16((u8*)buf);
1451 //JMutexAutoLock envlock(m_env_mutex); //bulk comment-out
1452 m_env.removeActiveObject(id);
1456 // Read added objects
1458 u16 added_count = readU16((u8*)buf);
1459 for(u16 i=0; i<added_count; i++)
1462 u16 id = readU16((u8*)buf);
1464 u8 type = readU8((u8*)buf);
1465 std::string data = deSerializeLongString(is);
1468 //JMutexAutoLock envlock(m_env_mutex); //bulk comment-out
1469 m_env.addActiveObject(id, type, data);
1474 else if(command == TOCLIENT_ACTIVE_OBJECT_MESSAGES)
1476 //if(g_settings->getBool("enable_experimental"))
1488 // Get all data except the command number
1489 std::string datastring((char*)&data[2], datasize-2);
1490 // Throw them in an istringstream
1491 std::istringstream is(datastring, std::ios_base::binary);
1493 while(is.eof() == false)
1497 u16 id = readU16((u8*)buf);
1501 u16 message_size = readU16((u8*)buf);
1502 std::string message;
1503 message.reserve(message_size);
1504 for(u16 i=0; i<message_size; i++)
1507 message.append(buf, 1);
1509 // Pass on to the environment
1511 //JMutexAutoLock envlock(m_env_mutex); //bulk comment-out
1512 m_env.processActiveObjectMessage(id, message);
1517 else if(command == TOCLIENT_MOVEMENT)
1519 std::string datastring((char*)&data[2], datasize-2);
1520 std::istringstream is(datastring, std::ios_base::binary);
1521 Player *player = m_env.getLocalPlayer();
1522 assert(player != NULL);
1524 player->movement_acceleration_default = readF1000(is) * BS;
1525 player->movement_acceleration_air = readF1000(is) * BS;
1526 player->movement_acceleration_fast = readF1000(is) * BS;
1527 player->movement_speed_walk = readF1000(is) * BS;
1528 player->movement_speed_crouch = readF1000(is) * BS;
1529 player->movement_speed_fast = readF1000(is) * BS;
1530 player->movement_speed_climb = readF1000(is) * BS;
1531 player->movement_speed_jump = readF1000(is) * BS;
1532 player->movement_liquid_fluidity = readF1000(is) * BS;
1533 player->movement_liquid_fluidity_smooth = readF1000(is) * BS;
1534 player->movement_liquid_sink = readF1000(is) * BS;
1535 player->movement_gravity = readF1000(is) * BS;
1537 else if(command == TOCLIENT_HP)
1539 std::string datastring((char*)&data[2], datasize-2);
1540 std::istringstream is(datastring, std::ios_base::binary);
1541 Player *player = m_env.getLocalPlayer();
1542 assert(player != NULL);
1543 u8 oldhp = player->hp;
1549 // Add to ClientEvent queue
1551 event.type = CE_PLAYER_DAMAGE;
1552 event.player_damage.amount = oldhp - hp;
1553 m_client_event_queue.push_back(event);
1556 else if(command == TOCLIENT_MOVE_PLAYER)
1558 std::string datastring((char*)&data[2], datasize-2);
1559 std::istringstream is(datastring, std::ios_base::binary);
1560 Player *player = m_env.getLocalPlayer();
1561 assert(player != NULL);
1562 v3f pos = readV3F1000(is);
1563 f32 pitch = readF1000(is);
1564 f32 yaw = readF1000(is);
1565 player->setPosition(pos);
1566 /*player->setPitch(pitch);
1567 player->setYaw(yaw);*/
1569 infostream<<"Client got TOCLIENT_MOVE_PLAYER"
1570 <<" pos=("<<pos.X<<","<<pos.Y<<","<<pos.Z<<")"
1576 Add to ClientEvent queue.
1577 This has to be sent to the main program because otherwise
1578 it would just force the pitch and yaw values to whatever
1579 the camera points to.
1582 event.type = CE_PLAYER_FORCE_MOVE;
1583 event.player_force_move.pitch = pitch;
1584 event.player_force_move.yaw = yaw;
1585 m_client_event_queue.push_back(event);
1587 // Ignore damage for a few seconds, so that the player doesn't
1588 // get damage from falling on ground
1589 m_ignore_damage_timer = 3.0;
1591 else if(command == TOCLIENT_PLAYERITEM)
1593 infostream<<"Client: WARNING: Ignoring TOCLIENT_PLAYERITEM"<<std::endl;
1595 else if(command == TOCLIENT_DEATHSCREEN)
1597 std::string datastring((char*)&data[2], datasize-2);
1598 std::istringstream is(datastring, std::ios_base::binary);
1600 bool set_camera_point_target = readU8(is);
1601 v3f camera_point_target = readV3F1000(is);
1604 event.type = CE_DEATHSCREEN;
1605 event.deathscreen.set_camera_point_target = set_camera_point_target;
1606 event.deathscreen.camera_point_target_x = camera_point_target.X;
1607 event.deathscreen.camera_point_target_y = camera_point_target.Y;
1608 event.deathscreen.camera_point_target_z = camera_point_target.Z;
1609 m_client_event_queue.push_back(event);
1611 else if(command == TOCLIENT_ANNOUNCE_MEDIA)
1613 std::string datastring((char*)&data[2], datasize-2);
1614 std::istringstream is(datastring, std::ios_base::binary);
1616 // Mesh update thread must be stopped while
1617 // updating content definitions
1618 assert(!m_mesh_update_thread.IsRunning());
1620 int num_files = readU16(is);
1622 infostream<<"Client: Received media announcement: packet size: "
1623 <<datasize<<std::endl;
1625 std::list<MediaRequest> file_requests;
1627 for(int i=0; i<num_files; i++)
1629 //read file from cache
1630 std::string name = deSerializeString(is);
1631 std::string sha1_base64 = deSerializeString(is);
1633 // if name contains illegal characters, ignore the file
1634 if(!string_allowed(name, TEXTURENAME_ALLOWED_CHARS)){
1635 errorstream<<"Client: ignoring illegal file name "
1636 <<"sent by server: \""<<name<<"\""<<std::endl;
1640 std::string sha1_raw = base64_decode(sha1_base64);
1641 std::string sha1_hex = hex_encode(sha1_raw);
1642 std::ostringstream tmp_os(std::ios_base::binary);
1643 bool found_in_cache = m_media_cache.load_sha1(sha1_raw, tmp_os);
1644 m_media_name_sha1_map[name] = sha1_raw;
1646 // If found in cache, try to load it from there
1649 bool success = loadMedia(tmp_os.str(), name);
1651 verbosestream<<"Client: Loaded cached media: "
1652 <<sha1_hex<<" \""<<name<<"\""<<std::endl;
1655 infostream<<"Client: Failed to load cached media: "
1656 <<sha1_hex<<" \""<<name<<"\""<<std::endl;
1659 // Didn't load from cache; queue it to be requested
1660 verbosestream<<"Client: Adding file to request list: \""
1661 <<sha1_hex<<" \""<<name<<"\""<<std::endl;
1662 file_requests.push_back(MediaRequest(name));
1665 std::string remote_media = "";
1667 remote_media = deSerializeString(is);
1669 catch(SerializationError) {
1670 // not supported by server or turned off
1673 m_media_count = file_requests.size();
1674 m_media_receive_started = true;
1676 if (remote_media == "" || !USE_CURL) {
1677 request_media(file_requests);
1680 std::list<MediaFetchThread*>::iterator cur = m_media_fetch_threads.begin();
1681 for(std::list<MediaRequest>::iterator i = file_requests.begin();
1682 i != file_requests.end(); ++i) {
1683 (*cur)->m_file_requests.push_back(*i);
1685 if (cur == m_media_fetch_threads.end())
1686 cur = m_media_fetch_threads.begin();
1688 for (std::list<MediaFetchThread*>::iterator i = m_media_fetch_threads.begin();
1689 i != m_media_fetch_threads.end(); ++i) {
1690 (*i)->m_remote_url = remote_media;
1695 // notify server we received everything
1696 std::ostringstream os(std::ios_base::binary);
1697 writeU16(os, TOSERVER_RECEIVED_MEDIA);
1698 std::string s = os.str();
1699 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
1701 Send(0, data, true);
1704 event.type = CE_TEXTURES_UPDATED;
1705 m_client_event_queue.push_back(event);
1707 else if(command == TOCLIENT_MEDIA)
1709 if (m_media_count == 0)
1711 std::string datastring((char*)&data[2], datasize-2);
1712 std::istringstream is(datastring, std::ios_base::binary);
1714 // Mesh update thread must be stopped while
1715 // updating content definitions
1716 assert(!m_mesh_update_thread.IsRunning());
1720 u16 total number of file bunches
1721 u16 index of this bunch
1722 u32 number of files in this bunch
1730 int num_bunches = readU16(is);
1731 int bunch_i = readU16(is);
1732 int num_files = readU32(is);
1733 infostream<<"Client: Received files: bunch "<<bunch_i<<"/"
1734 <<num_bunches<<" files="<<num_files
1735 <<" size="<<datasize<<std::endl;
1736 for(int i=0; i<num_files; i++){
1737 m_media_received_count++;
1738 std::string name = deSerializeString(is);
1739 std::string data = deSerializeLongString(is);
1741 // if name contains illegal characters, ignore the file
1742 if(!string_allowed(name, TEXTURENAME_ALLOWED_CHARS)){
1743 errorstream<<"Client: ignoring illegal file name "
1744 <<"sent by server: \""<<name<<"\""<<std::endl;
1748 bool success = loadMedia(data, name);
1750 verbosestream<<"Client: Loaded received media: "
1751 <<"\""<<name<<"\". Caching."<<std::endl;
1753 infostream<<"Client: Failed to load received media: "
1754 <<"\""<<name<<"\". Not caching."<<std::endl;
1758 bool did = fs::CreateAllDirs(getMediaCacheDir());
1760 errorstream<<"Could not create media cache directory"
1765 std::map<std::string, std::string>::iterator n;
1766 n = m_media_name_sha1_map.find(name);
1767 if(n == m_media_name_sha1_map.end())
1768 errorstream<<"The server sent a file that has not "
1769 <<"been announced."<<std::endl;
1771 m_media_cache.update_sha1(data);
1776 event.type = CE_TEXTURES_UPDATED;
1777 m_client_event_queue.push_back(event);
1779 else if(command == TOCLIENT_TOOLDEF)
1781 infostream<<"Client: WARNING: Ignoring TOCLIENT_TOOLDEF"<<std::endl;
1783 else if(command == TOCLIENT_NODEDEF)
1785 infostream<<"Client: Received node definitions: packet size: "
1786 <<datasize<<std::endl;
1788 // Mesh update thread must be stopped while
1789 // updating content definitions
1790 assert(!m_mesh_update_thread.IsRunning());
1792 // Decompress node definitions
1793 std::string datastring((char*)&data[2], datasize-2);
1794 std::istringstream is(datastring, std::ios_base::binary);
1795 std::istringstream tmp_is(deSerializeLongString(is), std::ios::binary);
1796 std::ostringstream tmp_os;
1797 decompressZlib(tmp_is, tmp_os);
1799 // Deserialize node definitions
1800 std::istringstream tmp_is2(tmp_os.str());
1801 m_nodedef->deSerialize(tmp_is2);
1802 m_nodedef_received = true;
1804 else if(command == TOCLIENT_CRAFTITEMDEF)
1806 infostream<<"Client: WARNING: Ignoring TOCLIENT_CRAFTITEMDEF"<<std::endl;
1808 else if(command == TOCLIENT_ITEMDEF)
1810 infostream<<"Client: Received item definitions: packet size: "
1811 <<datasize<<std::endl;
1813 // Mesh update thread must be stopped while
1814 // updating content definitions
1815 assert(!m_mesh_update_thread.IsRunning());
1817 // Decompress item definitions
1818 std::string datastring((char*)&data[2], datasize-2);
1819 std::istringstream is(datastring, std::ios_base::binary);
1820 std::istringstream tmp_is(deSerializeLongString(is), std::ios::binary);
1821 std::ostringstream tmp_os;
1822 decompressZlib(tmp_is, tmp_os);
1824 // Deserialize node definitions
1825 std::istringstream tmp_is2(tmp_os.str());
1826 m_itemdef->deSerialize(tmp_is2);
1827 m_itemdef_received = true;
1829 else if(command == TOCLIENT_PLAY_SOUND)
1831 std::string datastring((char*)&data[2], datasize-2);
1832 std::istringstream is(datastring, std::ios_base::binary);
1834 s32 server_id = readS32(is);
1835 std::string name = deSerializeString(is);
1836 float gain = readF1000(is);
1837 int type = readU8(is); // 0=local, 1=positional, 2=object
1838 v3f pos = readV3F1000(is);
1839 u16 object_id = readU16(is);
1840 bool loop = readU8(is);
1845 client_id = m_sound->playSound(name, loop, gain);
1847 case 1: // positional
1848 client_id = m_sound->playSoundAt(name, loop, gain, pos);
1851 ClientActiveObject *cao = m_env.getActiveObject(object_id);
1853 pos = cao->getPosition();
1854 client_id = m_sound->playSoundAt(name, loop, gain, pos);
1855 // TODO: Set up sound to move with object
1860 if(client_id != -1){
1861 m_sounds_server_to_client[server_id] = client_id;
1862 m_sounds_client_to_server[client_id] = server_id;
1864 m_sounds_to_objects[client_id] = object_id;
1867 else if(command == TOCLIENT_STOP_SOUND)
1869 std::string datastring((char*)&data[2], datasize-2);
1870 std::istringstream is(datastring, std::ios_base::binary);
1872 s32 server_id = readS32(is);
1873 std::map<s32, int>::iterator i =
1874 m_sounds_server_to_client.find(server_id);
1875 if(i != m_sounds_server_to_client.end()){
1876 int client_id = i->second;
1877 m_sound->stopSound(client_id);
1880 else if(command == TOCLIENT_PRIVILEGES)
1882 std::string datastring((char*)&data[2], datasize-2);
1883 std::istringstream is(datastring, std::ios_base::binary);
1885 m_privileges.clear();
1886 infostream<<"Client: Privileges updated: ";
1887 u16 num_privileges = readU16(is);
1888 for(u16 i=0; i<num_privileges; i++){
1889 std::string priv = deSerializeString(is);
1890 m_privileges.insert(priv);
1891 infostream<<priv<<" ";
1893 infostream<<std::endl;
1895 else if(command == TOCLIENT_INVENTORY_FORMSPEC)
1897 std::string datastring((char*)&data[2], datasize-2);
1898 std::istringstream is(datastring, std::ios_base::binary);
1900 // Store formspec in LocalPlayer
1901 Player *player = m_env.getLocalPlayer();
1902 assert(player != NULL);
1903 player->inventory_formspec = deSerializeLongString(is);
1905 else if(command == TOCLIENT_DETACHED_INVENTORY)
1907 std::string datastring((char*)&data[2], datasize-2);
1908 std::istringstream is(datastring, std::ios_base::binary);
1910 std::string name = deSerializeString(is);
1912 infostream<<"Client: Detached inventory update: \""<<name<<"\""<<std::endl;
1914 Inventory *inv = NULL;
1915 if(m_detached_inventories.count(name) > 0)
1916 inv = m_detached_inventories[name];
1918 inv = new Inventory(m_itemdef);
1919 m_detached_inventories[name] = inv;
1921 inv->deSerialize(is);
1923 else if(command == TOCLIENT_SHOW_FORMSPEC)
1925 std::string datastring((char*)&data[2], datasize-2);
1926 std::istringstream is(datastring, std::ios_base::binary);
1928 std::string formspec = deSerializeLongString(is);
1929 std::string formname = deSerializeString(is);
1932 event.type = CE_SHOW_FORMSPEC;
1933 // pointer is required as event is a struct only!
1934 // adding a std:string to a struct isn't possible
1935 event.show_formspec.formspec = new std::string(formspec);
1936 event.show_formspec.formname = new std::string(formname);
1937 m_client_event_queue.push_back(event);
1939 else if(command == TOCLIENT_SPAWN_PARTICLE)
1941 std::string datastring((char*)&data[2], datasize-2);
1942 std::istringstream is(datastring, std::ios_base::binary);
1944 v3f pos = readV3F1000(is);
1945 v3f vel = readV3F1000(is);
1946 v3f acc = readV3F1000(is);
1947 float expirationtime = readF1000(is);
1948 float size = readF1000(is);
1949 bool collisiondetection = readU8(is);
1950 std::string texture = deSerializeLongString(is);
1953 event.type = CE_SPAWN_PARTICLE;
1954 event.spawn_particle.pos = new v3f (pos);
1955 event.spawn_particle.vel = new v3f (vel);
1956 event.spawn_particle.acc = new v3f (acc);
1958 event.spawn_particle.expirationtime = expirationtime;
1959 event.spawn_particle.size = size;
1960 event.add_particlespawner.collisiondetection =
1962 event.spawn_particle.texture = new std::string(texture);
1964 m_client_event_queue.push_back(event);
1966 else if(command == TOCLIENT_ADD_PARTICLESPAWNER)
1968 std::string datastring((char*)&data[2], datasize-2);
1969 std::istringstream is(datastring, std::ios_base::binary);
1971 u16 amount = readU16(is);
1972 float spawntime = readF1000(is);
1973 v3f minpos = readV3F1000(is);
1974 v3f maxpos = readV3F1000(is);
1975 v3f minvel = readV3F1000(is);
1976 v3f maxvel = readV3F1000(is);
1977 v3f minacc = readV3F1000(is);
1978 v3f maxacc = readV3F1000(is);
1979 float minexptime = readF1000(is);
1980 float maxexptime = readF1000(is);
1981 float minsize = readF1000(is);
1982 float maxsize = readF1000(is);
1983 bool collisiondetection = readU8(is);
1984 std::string texture = deSerializeLongString(is);
1985 u32 id = readU32(is);
1988 event.type = CE_ADD_PARTICLESPAWNER;
1989 event.add_particlespawner.amount = amount;
1990 event.add_particlespawner.spawntime = spawntime;
1992 event.add_particlespawner.minpos = new v3f (minpos);
1993 event.add_particlespawner.maxpos = new v3f (maxpos);
1994 event.add_particlespawner.minvel = new v3f (minvel);
1995 event.add_particlespawner.maxvel = new v3f (maxvel);
1996 event.add_particlespawner.minacc = new v3f (minacc);
1997 event.add_particlespawner.maxacc = new v3f (maxacc);
1999 event.add_particlespawner.minexptime = minexptime;
2000 event.add_particlespawner.maxexptime = maxexptime;
2001 event.add_particlespawner.minsize = minsize;
2002 event.add_particlespawner.maxsize = maxsize;
2003 event.add_particlespawner.collisiondetection = collisiondetection;
2004 event.add_particlespawner.texture = new std::string(texture);
2005 event.add_particlespawner.id = id;
2007 m_client_event_queue.push_back(event);
2009 else if(command == TOCLIENT_DELETE_PARTICLESPAWNER)
2011 std::string datastring((char*)&data[2], datasize-2);
2012 std::istringstream is(datastring, std::ios_base::binary);
2014 u32 id = readU16(is);
2017 event.type = CE_DELETE_PARTICLESPAWNER;
2018 event.delete_particlespawner.id = id;
2020 m_client_event_queue.push_back(event);
2024 infostream<<"Client: Ignoring unknown command "
2025 <<command<<std::endl;
2029 void Client::Send(u16 channelnum, SharedBuffer<u8> data, bool reliable)
2031 //JMutexAutoLock lock(m_con_mutex); //bulk comment-out
2032 m_con.Send(PEER_ID_SERVER, channelnum, data, reliable);
2035 void Client::interact(u8 action, const PointedThing& pointed)
2037 if(connectedAndInitialized() == false){
2038 infostream<<"Client::interact() "
2039 "cancelled (not connected)"
2044 std::ostringstream os(std::ios_base::binary);
2050 [5] u32 length of the next item
2051 [9] serialized PointedThing
2053 0: start digging (from undersurface) or use
2054 1: stop digging (all parameters ignored)
2055 2: digging completed
2056 3: place block or item (to abovesurface)
2059 writeU16(os, TOSERVER_INTERACT);
2060 writeU8(os, action);
2061 writeU16(os, getPlayerItem());
2062 std::ostringstream tmp_os(std::ios::binary);
2063 pointed.serialize(tmp_os);
2064 os<<serializeLongString(tmp_os.str());
2066 std::string s = os.str();
2067 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
2070 Send(0, data, true);
2073 void Client::sendNodemetaFields(v3s16 p, const std::string &formname,
2074 const std::map<std::string, std::string> &fields)
2076 std::ostringstream os(std::ios_base::binary);
2078 writeU16(os, TOSERVER_NODEMETA_FIELDS);
2080 os<<serializeString(formname);
2081 writeU16(os, fields.size());
2082 for(std::map<std::string, std::string>::const_iterator
2083 i = fields.begin(); i != fields.end(); i++){
2084 const std::string &name = i->first;
2085 const std::string &value = i->second;
2086 os<<serializeString(name);
2087 os<<serializeLongString(value);
2091 std::string s = os.str();
2092 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
2094 Send(0, data, true);
2097 void Client::sendInventoryFields(const std::string &formname,
2098 const std::map<std::string, std::string> &fields)
2100 std::ostringstream os(std::ios_base::binary);
2102 writeU16(os, TOSERVER_INVENTORY_FIELDS);
2103 os<<serializeString(formname);
2104 writeU16(os, fields.size());
2105 for(std::map<std::string, std::string>::const_iterator
2106 i = fields.begin(); i != fields.end(); i++){
2107 const std::string &name = i->first;
2108 const std::string &value = i->second;
2109 os<<serializeString(name);
2110 os<<serializeLongString(value);
2114 std::string s = os.str();
2115 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
2117 Send(0, data, true);
2120 void Client::sendInventoryAction(InventoryAction *a)
2122 std::ostringstream os(std::ios_base::binary);
2126 writeU16(buf, TOSERVER_INVENTORY_ACTION);
2127 os.write((char*)buf, 2);
2132 std::string s = os.str();
2133 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
2135 Send(0, data, true);
2138 void Client::sendChatMessage(const std::wstring &message)
2140 std::ostringstream os(std::ios_base::binary);
2144 writeU16(buf, TOSERVER_CHAT_MESSAGE);
2145 os.write((char*)buf, 2);
2148 writeU16(buf, message.size());
2149 os.write((char*)buf, 2);
2152 for(u32 i=0; i<message.size(); i++)
2156 os.write((char*)buf, 2);
2160 std::string s = os.str();
2161 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
2163 Send(0, data, true);
2166 void Client::sendChangePassword(const std::wstring oldpassword,
2167 const std::wstring newpassword)
2169 Player *player = m_env.getLocalPlayer();
2173 std::string playername = player->getName();
2174 std::string oldpwd = translatePassword(playername, oldpassword);
2175 std::string newpwd = translatePassword(playername, newpassword);
2177 std::ostringstream os(std::ios_base::binary);
2178 u8 buf[2+PASSWORD_SIZE*2];
2180 [0] u16 TOSERVER_PASSWORD
2181 [2] u8[28] old password
2182 [30] u8[28] new password
2185 writeU16(buf, TOSERVER_PASSWORD);
2186 for(u32 i=0;i<PASSWORD_SIZE-1;i++)
2188 buf[2+i] = i<oldpwd.length()?oldpwd[i]:0;
2189 buf[30+i] = i<newpwd.length()?newpwd[i]:0;
2191 buf[2+PASSWORD_SIZE-1] = 0;
2192 buf[30+PASSWORD_SIZE-1] = 0;
2193 os.write((char*)buf, 2+PASSWORD_SIZE*2);
2196 std::string s = os.str();
2197 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
2199 Send(0, data, true);
2203 void Client::sendDamage(u8 damage)
2205 DSTACK(__FUNCTION_NAME);
2206 std::ostringstream os(std::ios_base::binary);
2208 writeU16(os, TOSERVER_DAMAGE);
2209 writeU8(os, damage);
2212 std::string s = os.str();
2213 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
2215 Send(0, data, true);
2218 void Client::sendRespawn()
2220 DSTACK(__FUNCTION_NAME);
2221 std::ostringstream os(std::ios_base::binary);
2223 writeU16(os, TOSERVER_RESPAWN);
2226 std::string s = os.str();
2227 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
2229 Send(0, data, true);
2232 void Client::sendPlayerPos()
2234 //JMutexAutoLock envlock(m_env_mutex); //bulk comment-out
2236 LocalPlayer *myplayer = m_env.getLocalPlayer();
2237 if(myplayer == NULL)
2240 // Save bandwidth by only updating position when something changed
2241 if(myplayer->last_position == myplayer->getPosition() &&
2242 myplayer->last_speed == myplayer->getSpeed() &&
2243 myplayer->last_pitch == myplayer->getPitch() &&
2244 myplayer->last_yaw == myplayer->getYaw() &&
2245 myplayer->last_keyPressed == myplayer->keyPressed)
2248 myplayer->last_position = myplayer->getPosition();
2249 myplayer->last_speed = myplayer->getSpeed();
2250 myplayer->last_pitch = myplayer->getPitch();
2251 myplayer->last_yaw = myplayer->getYaw();
2252 myplayer->last_keyPressed = myplayer->keyPressed;
2256 //JMutexAutoLock lock(m_con_mutex); //bulk comment-out
2257 our_peer_id = m_con.GetPeerID();
2260 // Set peer id if not set already
2261 if(myplayer->peer_id == PEER_ID_INEXISTENT)
2262 myplayer->peer_id = our_peer_id;
2263 // Check that an existing peer_id is the same as the connection's
2264 assert(myplayer->peer_id == our_peer_id);
2266 v3f pf = myplayer->getPosition();
2267 v3s32 position(pf.X*100, pf.Y*100, pf.Z*100);
2268 v3f sf = myplayer->getSpeed();
2269 v3s32 speed(sf.X*100, sf.Y*100, sf.Z*100);
2270 s32 pitch = myplayer->getPitch() * 100;
2271 s32 yaw = myplayer->getYaw() * 100;
2272 u32 keyPressed=myplayer->keyPressed;
2276 [2] v3s32 position*100
2277 [2+12] v3s32 speed*100
2278 [2+12+12] s32 pitch*100
2279 [2+12+12+4] s32 yaw*100
2280 [2+12+12+4+4] u32 keyPressed
2282 SharedBuffer<u8> data(2+12+12+4+4+4);
2283 writeU16(&data[0], TOSERVER_PLAYERPOS);
2284 writeV3S32(&data[2], position);
2285 writeV3S32(&data[2+12], speed);
2286 writeS32(&data[2+12+12], pitch);
2287 writeS32(&data[2+12+12+4], yaw);
2288 writeU32(&data[2+12+12+4+4], keyPressed);
2289 // Send as unreliable
2290 Send(0, data, false);
2293 void Client::sendPlayerItem(u16 item)
2295 Player *myplayer = m_env.getLocalPlayer();
2296 if(myplayer == NULL)
2299 u16 our_peer_id = m_con.GetPeerID();
2301 // Set peer id if not set already
2302 if(myplayer->peer_id == PEER_ID_INEXISTENT)
2303 myplayer->peer_id = our_peer_id;
2304 // Check that an existing peer_id is the same as the connection's
2305 assert(myplayer->peer_id == our_peer_id);
2307 SharedBuffer<u8> data(2+2);
2308 writeU16(&data[0], TOSERVER_PLAYERITEM);
2309 writeU16(&data[2], item);
2312 Send(0, data, true);
2315 void Client::removeNode(v3s16 p)
2317 std::map<v3s16, MapBlock*> modified_blocks;
2321 //TimeTaker t("removeNodeAndUpdate", m_device);
2322 m_env.getMap().removeNodeAndUpdate(p, modified_blocks);
2324 catch(InvalidPositionException &e)
2328 // add urgent task to update the modified node
2329 addUpdateMeshTaskForNode(p, false, true);
2331 for(std::map<v3s16, MapBlock * >::iterator
2332 i = modified_blocks.begin();
2333 i != modified_blocks.end(); ++i)
2335 addUpdateMeshTaskWithEdge(i->first);
2339 void Client::addNode(v3s16 p, MapNode n)
2341 TimeTaker timer1("Client::addNode()");
2343 std::map<v3s16, MapBlock*> modified_blocks;
2347 //TimeTaker timer3("Client::addNode(): addNodeAndUpdate");
2348 m_env.getMap().addNodeAndUpdate(p, n, modified_blocks);
2350 catch(InvalidPositionException &e)
2353 for(std::map<v3s16, MapBlock * >::iterator
2354 i = modified_blocks.begin();
2355 i != modified_blocks.end(); ++i)
2357 addUpdateMeshTaskWithEdge(i->first);
2361 void Client::setPlayerControl(PlayerControl &control)
2363 //JMutexAutoLock envlock(m_env_mutex); //bulk comment-out
2364 LocalPlayer *player = m_env.getLocalPlayer();
2365 assert(player != NULL);
2366 player->control = control;
2369 void Client::selectPlayerItem(u16 item)
2371 //JMutexAutoLock envlock(m_env_mutex); //bulk comment-out
2372 m_playeritem = item;
2373 m_inventory_updated = true;
2374 sendPlayerItem(item);
2377 // Returns true if the inventory of the local player has been
2378 // updated from the server. If it is true, it is set to false.
2379 bool Client::getLocalInventoryUpdated()
2381 // m_inventory_updated is behind envlock
2382 //JMutexAutoLock envlock(m_env_mutex); //bulk comment-out
2383 bool updated = m_inventory_updated;
2384 m_inventory_updated = false;
2388 // Copies the inventory of the local player to parameter
2389 void Client::getLocalInventory(Inventory &dst)
2391 //JMutexAutoLock envlock(m_env_mutex); //bulk comment-out
2392 Player *player = m_env.getLocalPlayer();
2393 assert(player != NULL);
2394 dst = player->inventory;
2397 Inventory* Client::getInventory(const InventoryLocation &loc)
2400 case InventoryLocation::UNDEFINED:
2403 case InventoryLocation::CURRENT_PLAYER:
2405 Player *player = m_env.getLocalPlayer();
2406 assert(player != NULL);
2407 return &player->inventory;
2410 case InventoryLocation::PLAYER:
2412 Player *player = m_env.getPlayer(loc.name.c_str());
2415 return &player->inventory;
2418 case InventoryLocation::NODEMETA:
2420 NodeMetadata *meta = m_env.getMap().getNodeMetadata(loc.p);
2423 return meta->getInventory();
2426 case InventoryLocation::DETACHED:
2428 if(m_detached_inventories.count(loc.name) == 0)
2430 return m_detached_inventories[loc.name];
2438 void Client::inventoryAction(InventoryAction *a)
2441 Send it to the server
2443 sendInventoryAction(a);
2446 Predict some local inventory changes
2448 a->clientApply(this, this);
2451 ClientActiveObject * Client::getSelectedActiveObject(
2453 v3f from_pos_f_on_map,
2454 core::line3d<f32> shootline_on_map
2457 std::vector<DistanceSortedActiveObject> objects;
2459 m_env.getActiveObjects(from_pos_f_on_map, max_d, objects);
2461 //infostream<<"Collected "<<objects.size()<<" nearby objects"<<std::endl;
2464 // After this, the closest object is the first in the array.
2465 std::sort(objects.begin(), objects.end());
2467 for(u32 i=0; i<objects.size(); i++)
2469 ClientActiveObject *obj = objects[i].obj;
2471 core::aabbox3d<f32> *selection_box = obj->getSelectionBox();
2472 if(selection_box == NULL)
2475 v3f pos = obj->getPosition();
2477 core::aabbox3d<f32> offsetted_box(
2478 selection_box->MinEdge + pos,
2479 selection_box->MaxEdge + pos
2482 if(offsetted_box.intersectsWithLine(shootline_on_map))
2484 //infostream<<"Returning selected object"<<std::endl;
2489 //infostream<<"No object selected; returning NULL."<<std::endl;
2493 void Client::printDebugInfo(std::ostream &os)
2495 //JMutexAutoLock lock1(m_fetchblock_mutex);
2496 /*JMutexAutoLock lock2(m_incoming_queue_mutex);
2498 os<<"m_incoming_queue.getSize()="<<m_incoming_queue.getSize()
2499 //<<", m_fetchblock_history.size()="<<m_fetchblock_history.size()
2500 //<<", m_opt_not_found_history.size()="<<m_opt_not_found_history.size()
2504 std::list<std::wstring> Client::getConnectedPlayerNames()
2506 std::list<Player*> players = m_env.getPlayers(true);
2507 std::list<std::wstring> playerNames;
2508 for(std::list<Player*>::iterator
2509 i = players.begin();
2510 i != players.end(); ++i)
2512 Player *player = *i;
2513 playerNames.push_back(narrow_to_wide(player->getName()));
2518 float Client::getAnimationTime()
2520 return m_animation_time;
2523 int Client::getCrackLevel()
2525 return m_crack_level;
2528 void Client::setCrack(int level, v3s16 pos)
2530 int old_crack_level = m_crack_level;
2531 v3s16 old_crack_pos = m_crack_pos;
2533 m_crack_level = level;
2536 if(old_crack_level >= 0 && (level < 0 || pos != old_crack_pos))
2539 addUpdateMeshTaskForNode(old_crack_pos, false, true);
2541 if(level >= 0 && (old_crack_level < 0 || pos != old_crack_pos))
2544 addUpdateMeshTaskForNode(pos, false, true);
2550 Player *player = m_env.getLocalPlayer();
2551 assert(player != NULL);
2555 bool Client::getChatMessage(std::wstring &message)
2557 if(m_chat_queue.size() == 0)
2559 message = m_chat_queue.pop_front();
2563 void Client::typeChatMessage(const std::wstring &message)
2565 // Discard empty line
2570 sendChatMessage(message);
2573 if (message[0] == L'/')
2575 m_chat_queue.push_back(
2576 (std::wstring)L"issued command: "+message);
2580 LocalPlayer *player = m_env.getLocalPlayer();
2581 assert(player != NULL);
2582 std::wstring name = narrow_to_wide(player->getName());
2583 m_chat_queue.push_back(
2584 (std::wstring)L"<"+name+L"> "+message);
2588 void Client::addUpdateMeshTask(v3s16 p, bool ack_to_server, bool urgent)
2590 /*infostream<<"Client::addUpdateMeshTask(): "
2591 <<"("<<p.X<<","<<p.Y<<","<<p.Z<<")"
2592 <<" ack_to_server="<<ack_to_server
2593 <<" urgent="<<urgent
2596 MapBlock *b = m_env.getMap().getBlockNoCreateNoEx(p);
2601 Create a task to update the mesh of the block
2604 MeshMakeData *data = new MeshMakeData(this);
2607 //TimeTaker timer("data fill");
2609 // Debug: 1-6ms, avg=2ms
2611 data->setCrack(m_crack_level, m_crack_pos);
2612 data->setSmoothLighting(g_settings->getBool("smooth_lighting"));
2616 //while(m_mesh_update_thread.m_queue_in.size() > 0) sleep_ms(10);
2618 // Add task to queue
2619 m_mesh_update_thread.m_queue_in.addBlock(p, data, ack_to_server, urgent);
2621 /*infostream<<"Mesh update input queue size is "
2622 <<m_mesh_update_thread.m_queue_in.size()
2626 void Client::addUpdateMeshTaskWithEdge(v3s16 blockpos, bool ack_to_server, bool urgent)
2630 infostream<<"Client::addUpdateMeshTaskWithEdge(): "
2631 <<"("<<p.X<<","<<p.Y<<","<<p.Z<<")"
2636 v3s16 p = blockpos + v3s16(0,0,0);
2637 //MapBlock *b = m_env.getMap().getBlockNoCreate(p);
2638 addUpdateMeshTask(p, ack_to_server, urgent);
2640 catch(InvalidPositionException &e){}
2643 v3s16 p = blockpos + v3s16(-1,0,0);
2644 addUpdateMeshTask(p, false, urgent);
2646 catch(InvalidPositionException &e){}
2648 v3s16 p = blockpos + v3s16(0,-1,0);
2649 addUpdateMeshTask(p, false, urgent);
2651 catch(InvalidPositionException &e){}
2653 v3s16 p = blockpos + v3s16(0,0,-1);
2654 addUpdateMeshTask(p, false, urgent);
2656 catch(InvalidPositionException &e){}
2659 void Client::addUpdateMeshTaskForNode(v3s16 nodepos, bool ack_to_server, bool urgent)
2663 infostream<<"Client::addUpdateMeshTaskForNode(): "
2664 <<"("<<p.X<<","<<p.Y<<","<<p.Z<<")"
2668 v3s16 blockpos = getNodeBlockPos(nodepos);
2669 v3s16 blockpos_relative = blockpos * MAP_BLOCKSIZE;
2672 v3s16 p = blockpos + v3s16(0,0,0);
2673 addUpdateMeshTask(p, ack_to_server, urgent);
2675 catch(InvalidPositionException &e){}
2677 if(nodepos.X == blockpos_relative.X){
2679 v3s16 p = blockpos + v3s16(-1,0,0);
2680 addUpdateMeshTask(p, false, urgent);
2682 catch(InvalidPositionException &e){}
2684 if(nodepos.Y == blockpos_relative.Y){
2686 v3s16 p = blockpos + v3s16(0,-1,0);
2687 addUpdateMeshTask(p, false, urgent);
2689 catch(InvalidPositionException &e){}
2691 if(nodepos.Z == blockpos_relative.Z){
2693 v3s16 p = blockpos + v3s16(0,0,-1);
2694 addUpdateMeshTask(p, false, urgent);
2696 catch(InvalidPositionException &e){}
2700 ClientEvent Client::getClientEvent()
2702 if(m_client_event_queue.size() == 0)
2705 event.type = CE_NONE;
2708 return m_client_event_queue.pop_front();
2711 void Client::afterContentReceived()
2713 infostream<<"Client::afterContentReceived() started"<<std::endl;
2714 assert(m_itemdef_received);
2715 assert(m_nodedef_received);
2716 assert(texturesReceived());
2718 // remove the information about which checksum each texture
2720 m_media_name_sha1_map.clear();
2722 // Rebuild inherited images and recreate textures
2723 infostream<<"- Rebuilding images and textures"<<std::endl;
2724 m_tsrc->rebuildImagesAndTextures();
2726 // Update texture atlas
2727 infostream<<"- Updating texture atlas"<<std::endl;
2728 if(g_settings->getBool("enable_texture_atlas"))
2729 m_tsrc->buildMainAtlas(this);
2732 m_shsrc->rebuildShaders();
2734 // Update node aliases
2735 infostream<<"- Updating node aliases"<<std::endl;
2736 m_nodedef->updateAliases(m_itemdef);
2738 // Update node textures
2739 infostream<<"- Updating node textures"<<std::endl;
2740 m_nodedef->updateTextures(m_tsrc);
2742 // Preload item textures and meshes if configured to
2743 if(g_settings->getBool("preload_item_visuals"))
2745 verbosestream<<"Updating item textures and meshes"<<std::endl;
2746 std::set<std::string> names = m_itemdef->getAll();
2747 for(std::set<std::string>::const_iterator
2748 i = names.begin(); i != names.end(); ++i){
2749 // Asking for these caches the result
2750 m_itemdef->getInventoryTexture(*i, this);
2751 m_itemdef->getWieldMesh(*i, this);
2755 // Start mesh update thread after setting up content definitions
2756 infostream<<"- Starting mesh update thread"<<std::endl;
2757 m_mesh_update_thread.Start();
2759 infostream<<"Client::afterContentReceived() done"<<std::endl;
2762 float Client::getRTT(void)
2765 return m_con.GetPeerAvgRTT(PEER_ID_SERVER);
2766 } catch(con::PeerNotFoundException &e){
2771 // IGameDef interface
2773 IItemDefManager* Client::getItemDefManager()
2777 INodeDefManager* Client::getNodeDefManager()
2781 ICraftDefManager* Client::getCraftDefManager()
2784 //return m_craftdef;
2786 ITextureSource* Client::getTextureSource()
2790 IShaderSource* Client::getShaderSource()
2794 u16 Client::allocateUnknownNodeId(const std::string &name)
2796 errorstream<<"Client::allocateUnknownNodeId(): "
2797 <<"Client cannot allocate node IDs"<<std::endl;
2799 return CONTENT_IGNORE;
2801 ISoundManager* Client::getSoundManager()
2805 MtEventManager* Client::getEventManager()