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);
1941 infostream<<"Client: Ignoring unknown command "
1942 <<command<<std::endl;
1946 void Client::Send(u16 channelnum, SharedBuffer<u8> data, bool reliable)
1948 //JMutexAutoLock lock(m_con_mutex); //bulk comment-out
1949 m_con.Send(PEER_ID_SERVER, channelnum, data, reliable);
1952 void Client::interact(u8 action, const PointedThing& pointed)
1954 if(connectedAndInitialized() == false){
1955 infostream<<"Client::interact() "
1956 "cancelled (not connected)"
1961 std::ostringstream os(std::ios_base::binary);
1967 [5] u32 length of the next item
1968 [9] serialized PointedThing
1970 0: start digging (from undersurface) or use
1971 1: stop digging (all parameters ignored)
1972 2: digging completed
1973 3: place block or item (to abovesurface)
1976 writeU16(os, TOSERVER_INTERACT);
1977 writeU8(os, action);
1978 writeU16(os, getPlayerItem());
1979 std::ostringstream tmp_os(std::ios::binary);
1980 pointed.serialize(tmp_os);
1981 os<<serializeLongString(tmp_os.str());
1983 std::string s = os.str();
1984 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
1987 Send(0, data, true);
1990 void Client::sendNodemetaFields(v3s16 p, const std::string &formname,
1991 const std::map<std::string, std::string> &fields)
1993 std::ostringstream os(std::ios_base::binary);
1995 writeU16(os, TOSERVER_NODEMETA_FIELDS);
1997 os<<serializeString(formname);
1998 writeU16(os, fields.size());
1999 for(std::map<std::string, std::string>::const_iterator
2000 i = fields.begin(); i != fields.end(); i++){
2001 const std::string &name = i->first;
2002 const std::string &value = i->second;
2003 os<<serializeString(name);
2004 os<<serializeLongString(value);
2008 std::string s = os.str();
2009 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
2011 Send(0, data, true);
2014 void Client::sendInventoryFields(const std::string &formname,
2015 const std::map<std::string, std::string> &fields)
2017 std::ostringstream os(std::ios_base::binary);
2019 writeU16(os, TOSERVER_INVENTORY_FIELDS);
2020 os<<serializeString(formname);
2021 writeU16(os, fields.size());
2022 for(std::map<std::string, std::string>::const_iterator
2023 i = fields.begin(); i != fields.end(); i++){
2024 const std::string &name = i->first;
2025 const std::string &value = i->second;
2026 os<<serializeString(name);
2027 os<<serializeLongString(value);
2031 std::string s = os.str();
2032 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
2034 Send(0, data, true);
2037 void Client::sendInventoryAction(InventoryAction *a)
2039 std::ostringstream os(std::ios_base::binary);
2043 writeU16(buf, TOSERVER_INVENTORY_ACTION);
2044 os.write((char*)buf, 2);
2049 std::string s = os.str();
2050 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
2052 Send(0, data, true);
2055 void Client::sendChatMessage(const std::wstring &message)
2057 std::ostringstream os(std::ios_base::binary);
2061 writeU16(buf, TOSERVER_CHAT_MESSAGE);
2062 os.write((char*)buf, 2);
2065 writeU16(buf, message.size());
2066 os.write((char*)buf, 2);
2069 for(u32 i=0; i<message.size(); i++)
2073 os.write((char*)buf, 2);
2077 std::string s = os.str();
2078 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
2080 Send(0, data, true);
2083 void Client::sendChangePassword(const std::wstring oldpassword,
2084 const std::wstring newpassword)
2086 Player *player = m_env.getLocalPlayer();
2090 std::string playername = player->getName();
2091 std::string oldpwd = translatePassword(playername, oldpassword);
2092 std::string newpwd = translatePassword(playername, newpassword);
2094 std::ostringstream os(std::ios_base::binary);
2095 u8 buf[2+PASSWORD_SIZE*2];
2097 [0] u16 TOSERVER_PASSWORD
2098 [2] u8[28] old password
2099 [30] u8[28] new password
2102 writeU16(buf, TOSERVER_PASSWORD);
2103 for(u32 i=0;i<PASSWORD_SIZE-1;i++)
2105 buf[2+i] = i<oldpwd.length()?oldpwd[i]:0;
2106 buf[30+i] = i<newpwd.length()?newpwd[i]:0;
2108 buf[2+PASSWORD_SIZE-1] = 0;
2109 buf[30+PASSWORD_SIZE-1] = 0;
2110 os.write((char*)buf, 2+PASSWORD_SIZE*2);
2113 std::string s = os.str();
2114 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
2116 Send(0, data, true);
2120 void Client::sendDamage(u8 damage)
2122 DSTACK(__FUNCTION_NAME);
2123 std::ostringstream os(std::ios_base::binary);
2125 writeU16(os, TOSERVER_DAMAGE);
2126 writeU8(os, damage);
2129 std::string s = os.str();
2130 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
2132 Send(0, data, true);
2135 void Client::sendRespawn()
2137 DSTACK(__FUNCTION_NAME);
2138 std::ostringstream os(std::ios_base::binary);
2140 writeU16(os, TOSERVER_RESPAWN);
2143 std::string s = os.str();
2144 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
2146 Send(0, data, true);
2149 void Client::sendPlayerPos()
2151 //JMutexAutoLock envlock(m_env_mutex); //bulk comment-out
2153 LocalPlayer *myplayer = m_env.getLocalPlayer();
2154 if(myplayer == NULL)
2157 // Save bandwidth by only updating position when something changed
2158 if(myplayer->last_position == myplayer->getPosition() &&
2159 myplayer->last_speed == myplayer->getSpeed() &&
2160 myplayer->last_pitch == myplayer->getPitch() &&
2161 myplayer->last_yaw == myplayer->getYaw() &&
2162 myplayer->last_keyPressed == myplayer->keyPressed)
2165 myplayer->last_position = myplayer->getPosition();
2166 myplayer->last_speed = myplayer->getSpeed();
2167 myplayer->last_pitch = myplayer->getPitch();
2168 myplayer->last_yaw = myplayer->getYaw();
2169 myplayer->last_keyPressed = myplayer->keyPressed;
2173 //JMutexAutoLock lock(m_con_mutex); //bulk comment-out
2174 our_peer_id = m_con.GetPeerID();
2177 // Set peer id if not set already
2178 if(myplayer->peer_id == PEER_ID_INEXISTENT)
2179 myplayer->peer_id = our_peer_id;
2180 // Check that an existing peer_id is the same as the connection's
2181 assert(myplayer->peer_id == our_peer_id);
2183 v3f pf = myplayer->getPosition();
2184 v3s32 position(pf.X*100, pf.Y*100, pf.Z*100);
2185 v3f sf = myplayer->getSpeed();
2186 v3s32 speed(sf.X*100, sf.Y*100, sf.Z*100);
2187 s32 pitch = myplayer->getPitch() * 100;
2188 s32 yaw = myplayer->getYaw() * 100;
2189 u32 keyPressed=myplayer->keyPressed;
2193 [2] v3s32 position*100
2194 [2+12] v3s32 speed*100
2195 [2+12+12] s32 pitch*100
2196 [2+12+12+4] s32 yaw*100
2197 [2+12+12+4+4] u32 keyPressed
2199 SharedBuffer<u8> data(2+12+12+4+4+4);
2200 writeU16(&data[0], TOSERVER_PLAYERPOS);
2201 writeV3S32(&data[2], position);
2202 writeV3S32(&data[2+12], speed);
2203 writeS32(&data[2+12+12], pitch);
2204 writeS32(&data[2+12+12+4], yaw);
2205 writeU32(&data[2+12+12+4+4], keyPressed);
2206 // Send as unreliable
2207 Send(0, data, false);
2210 void Client::sendPlayerItem(u16 item)
2212 Player *myplayer = m_env.getLocalPlayer();
2213 if(myplayer == NULL)
2216 u16 our_peer_id = m_con.GetPeerID();
2218 // Set peer id if not set already
2219 if(myplayer->peer_id == PEER_ID_INEXISTENT)
2220 myplayer->peer_id = our_peer_id;
2221 // Check that an existing peer_id is the same as the connection's
2222 assert(myplayer->peer_id == our_peer_id);
2224 SharedBuffer<u8> data(2+2);
2225 writeU16(&data[0], TOSERVER_PLAYERITEM);
2226 writeU16(&data[2], item);
2229 Send(0, data, true);
2232 void Client::removeNode(v3s16 p)
2234 std::map<v3s16, MapBlock*> modified_blocks;
2238 //TimeTaker t("removeNodeAndUpdate", m_device);
2239 m_env.getMap().removeNodeAndUpdate(p, modified_blocks);
2241 catch(InvalidPositionException &e)
2245 // add urgent task to update the modified node
2246 addUpdateMeshTaskForNode(p, false, true);
2248 for(std::map<v3s16, MapBlock * >::iterator
2249 i = modified_blocks.begin();
2250 i != modified_blocks.end(); ++i)
2252 addUpdateMeshTaskWithEdge(i->first);
2256 void Client::addNode(v3s16 p, MapNode n)
2258 TimeTaker timer1("Client::addNode()");
2260 std::map<v3s16, MapBlock*> modified_blocks;
2264 //TimeTaker timer3("Client::addNode(): addNodeAndUpdate");
2265 m_env.getMap().addNodeAndUpdate(p, n, modified_blocks);
2267 catch(InvalidPositionException &e)
2270 for(std::map<v3s16, MapBlock * >::iterator
2271 i = modified_blocks.begin();
2272 i != modified_blocks.end(); ++i)
2274 addUpdateMeshTaskWithEdge(i->first);
2278 void Client::setPlayerControl(PlayerControl &control)
2280 //JMutexAutoLock envlock(m_env_mutex); //bulk comment-out
2281 LocalPlayer *player = m_env.getLocalPlayer();
2282 assert(player != NULL);
2283 player->control = control;
2286 void Client::selectPlayerItem(u16 item)
2288 //JMutexAutoLock envlock(m_env_mutex); //bulk comment-out
2289 m_playeritem = item;
2290 m_inventory_updated = true;
2291 sendPlayerItem(item);
2294 // Returns true if the inventory of the local player has been
2295 // updated from the server. If it is true, it is set to false.
2296 bool Client::getLocalInventoryUpdated()
2298 // m_inventory_updated is behind envlock
2299 //JMutexAutoLock envlock(m_env_mutex); //bulk comment-out
2300 bool updated = m_inventory_updated;
2301 m_inventory_updated = false;
2305 // Copies the inventory of the local player to parameter
2306 void Client::getLocalInventory(Inventory &dst)
2308 //JMutexAutoLock envlock(m_env_mutex); //bulk comment-out
2309 Player *player = m_env.getLocalPlayer();
2310 assert(player != NULL);
2311 dst = player->inventory;
2314 Inventory* Client::getInventory(const InventoryLocation &loc)
2317 case InventoryLocation::UNDEFINED:
2320 case InventoryLocation::CURRENT_PLAYER:
2322 Player *player = m_env.getLocalPlayer();
2323 assert(player != NULL);
2324 return &player->inventory;
2327 case InventoryLocation::PLAYER:
2329 Player *player = m_env.getPlayer(loc.name.c_str());
2332 return &player->inventory;
2335 case InventoryLocation::NODEMETA:
2337 NodeMetadata *meta = m_env.getMap().getNodeMetadata(loc.p);
2340 return meta->getInventory();
2343 case InventoryLocation::DETACHED:
2345 if(m_detached_inventories.count(loc.name) == 0)
2347 return m_detached_inventories[loc.name];
2355 void Client::inventoryAction(InventoryAction *a)
2358 Send it to the server
2360 sendInventoryAction(a);
2363 Predict some local inventory changes
2365 a->clientApply(this, this);
2368 ClientActiveObject * Client::getSelectedActiveObject(
2370 v3f from_pos_f_on_map,
2371 core::line3d<f32> shootline_on_map
2374 std::vector<DistanceSortedActiveObject> objects;
2376 m_env.getActiveObjects(from_pos_f_on_map, max_d, objects);
2378 //infostream<<"Collected "<<objects.size()<<" nearby objects"<<std::endl;
2381 // After this, the closest object is the first in the array.
2382 std::sort(objects.begin(), objects.end());
2384 for(u32 i=0; i<objects.size(); i++)
2386 ClientActiveObject *obj = objects[i].obj;
2388 core::aabbox3d<f32> *selection_box = obj->getSelectionBox();
2389 if(selection_box == NULL)
2392 v3f pos = obj->getPosition();
2394 core::aabbox3d<f32> offsetted_box(
2395 selection_box->MinEdge + pos,
2396 selection_box->MaxEdge + pos
2399 if(offsetted_box.intersectsWithLine(shootline_on_map))
2401 //infostream<<"Returning selected object"<<std::endl;
2406 //infostream<<"No object selected; returning NULL."<<std::endl;
2410 void Client::printDebugInfo(std::ostream &os)
2412 //JMutexAutoLock lock1(m_fetchblock_mutex);
2413 /*JMutexAutoLock lock2(m_incoming_queue_mutex);
2415 os<<"m_incoming_queue.getSize()="<<m_incoming_queue.getSize()
2416 //<<", m_fetchblock_history.size()="<<m_fetchblock_history.size()
2417 //<<", m_opt_not_found_history.size()="<<m_opt_not_found_history.size()
2421 std::list<std::wstring> Client::getConnectedPlayerNames()
2423 std::list<Player*> players = m_env.getPlayers(true);
2424 std::list<std::wstring> playerNames;
2425 for(std::list<Player*>::iterator
2426 i = players.begin();
2427 i != players.end(); ++i)
2429 Player *player = *i;
2430 playerNames.push_back(narrow_to_wide(player->getName()));
2435 float Client::getAnimationTime()
2437 return m_animation_time;
2440 int Client::getCrackLevel()
2442 return m_crack_level;
2445 void Client::setCrack(int level, v3s16 pos)
2447 int old_crack_level = m_crack_level;
2448 v3s16 old_crack_pos = m_crack_pos;
2450 m_crack_level = level;
2453 if(old_crack_level >= 0 && (level < 0 || pos != old_crack_pos))
2456 addUpdateMeshTaskForNode(old_crack_pos, false, true);
2458 if(level >= 0 && (old_crack_level < 0 || pos != old_crack_pos))
2461 addUpdateMeshTaskForNode(pos, false, true);
2467 Player *player = m_env.getLocalPlayer();
2468 assert(player != NULL);
2472 bool Client::getChatMessage(std::wstring &message)
2474 if(m_chat_queue.size() == 0)
2476 message = m_chat_queue.pop_front();
2480 void Client::typeChatMessage(const std::wstring &message)
2482 // Discard empty line
2487 sendChatMessage(message);
2490 if (message[0] == L'/')
2492 m_chat_queue.push_back(
2493 (std::wstring)L"issued command: "+message);
2497 LocalPlayer *player = m_env.getLocalPlayer();
2498 assert(player != NULL);
2499 std::wstring name = narrow_to_wide(player->getName());
2500 m_chat_queue.push_back(
2501 (std::wstring)L"<"+name+L"> "+message);
2505 void Client::addUpdateMeshTask(v3s16 p, bool ack_to_server, bool urgent)
2507 /*infostream<<"Client::addUpdateMeshTask(): "
2508 <<"("<<p.X<<","<<p.Y<<","<<p.Z<<")"
2509 <<" ack_to_server="<<ack_to_server
2510 <<" urgent="<<urgent
2513 MapBlock *b = m_env.getMap().getBlockNoCreateNoEx(p);
2518 Create a task to update the mesh of the block
2521 MeshMakeData *data = new MeshMakeData(this);
2524 //TimeTaker timer("data fill");
2526 // Debug: 1-6ms, avg=2ms
2528 data->setCrack(m_crack_level, m_crack_pos);
2529 data->setSmoothLighting(g_settings->getBool("smooth_lighting"));
2533 //while(m_mesh_update_thread.m_queue_in.size() > 0) sleep_ms(10);
2535 // Add task to queue
2536 m_mesh_update_thread.m_queue_in.addBlock(p, data, ack_to_server, urgent);
2538 /*infostream<<"Mesh update input queue size is "
2539 <<m_mesh_update_thread.m_queue_in.size()
2543 void Client::addUpdateMeshTaskWithEdge(v3s16 blockpos, bool ack_to_server, bool urgent)
2547 infostream<<"Client::addUpdateMeshTaskWithEdge(): "
2548 <<"("<<p.X<<","<<p.Y<<","<<p.Z<<")"
2553 v3s16 p = blockpos + v3s16(0,0,0);
2554 //MapBlock *b = m_env.getMap().getBlockNoCreate(p);
2555 addUpdateMeshTask(p, ack_to_server, urgent);
2557 catch(InvalidPositionException &e){}
2560 v3s16 p = blockpos + v3s16(-1,0,0);
2561 addUpdateMeshTask(p, false, urgent);
2563 catch(InvalidPositionException &e){}
2565 v3s16 p = blockpos + v3s16(0,-1,0);
2566 addUpdateMeshTask(p, false, urgent);
2568 catch(InvalidPositionException &e){}
2570 v3s16 p = blockpos + v3s16(0,0,-1);
2571 addUpdateMeshTask(p, false, urgent);
2573 catch(InvalidPositionException &e){}
2576 void Client::addUpdateMeshTaskForNode(v3s16 nodepos, bool ack_to_server, bool urgent)
2580 infostream<<"Client::addUpdateMeshTaskForNode(): "
2581 <<"("<<p.X<<","<<p.Y<<","<<p.Z<<")"
2585 v3s16 blockpos = getNodeBlockPos(nodepos);
2586 v3s16 blockpos_relative = blockpos * MAP_BLOCKSIZE;
2589 v3s16 p = blockpos + v3s16(0,0,0);
2590 addUpdateMeshTask(p, ack_to_server, urgent);
2592 catch(InvalidPositionException &e){}
2594 if(nodepos.X == blockpos_relative.X){
2596 v3s16 p = blockpos + v3s16(-1,0,0);
2597 addUpdateMeshTask(p, false, urgent);
2599 catch(InvalidPositionException &e){}
2601 if(nodepos.Y == blockpos_relative.Y){
2603 v3s16 p = blockpos + v3s16(0,-1,0);
2604 addUpdateMeshTask(p, false, urgent);
2606 catch(InvalidPositionException &e){}
2608 if(nodepos.Z == blockpos_relative.Z){
2610 v3s16 p = blockpos + v3s16(0,0,-1);
2611 addUpdateMeshTask(p, false, urgent);
2613 catch(InvalidPositionException &e){}
2617 ClientEvent Client::getClientEvent()
2619 if(m_client_event_queue.size() == 0)
2622 event.type = CE_NONE;
2625 return m_client_event_queue.pop_front();
2628 void Client::afterContentReceived()
2630 infostream<<"Client::afterContentReceived() started"<<std::endl;
2631 assert(m_itemdef_received);
2632 assert(m_nodedef_received);
2633 assert(texturesReceived());
2635 // remove the information about which checksum each texture
2637 m_media_name_sha1_map.clear();
2639 // Rebuild inherited images and recreate textures
2640 infostream<<"- Rebuilding images and textures"<<std::endl;
2641 m_tsrc->rebuildImagesAndTextures();
2643 // Update texture atlas
2644 infostream<<"- Updating texture atlas"<<std::endl;
2645 if(g_settings->getBool("enable_texture_atlas"))
2646 m_tsrc->buildMainAtlas(this);
2649 m_shsrc->rebuildShaders();
2651 // Update node aliases
2652 infostream<<"- Updating node aliases"<<std::endl;
2653 m_nodedef->updateAliases(m_itemdef);
2655 // Update node textures
2656 infostream<<"- Updating node textures"<<std::endl;
2657 m_nodedef->updateTextures(m_tsrc);
2659 // Preload item textures and meshes if configured to
2660 if(g_settings->getBool("preload_item_visuals"))
2662 verbosestream<<"Updating item textures and meshes"<<std::endl;
2663 std::set<std::string> names = m_itemdef->getAll();
2664 for(std::set<std::string>::const_iterator
2665 i = names.begin(); i != names.end(); ++i){
2666 // Asking for these caches the result
2667 m_itemdef->getInventoryTexture(*i, this);
2668 m_itemdef->getWieldMesh(*i, this);
2672 // Start mesh update thread after setting up content definitions
2673 infostream<<"- Starting mesh update thread"<<std::endl;
2674 m_mesh_update_thread.Start();
2676 infostream<<"Client::afterContentReceived() done"<<std::endl;
2679 float Client::getRTT(void)
2682 return m_con.GetPeerAvgRTT(PEER_ID_SERVER);
2683 } catch(con::PeerNotFoundException &e){
2688 // IGameDef interface
2690 IItemDefManager* Client::getItemDefManager()
2694 INodeDefManager* Client::getNodeDefManager()
2698 ICraftDefManager* Client::getCraftDefManager()
2701 //return m_craftdef;
2703 ITextureSource* Client::getTextureSource()
2707 IShaderSource* Client::getShaderSource()
2711 u16 Client::allocateUnknownNodeId(const std::string &name)
2713 errorstream<<"Client::allocateUnknownNodeId(): "
2714 <<"Client cannot allocate node IDs"<<std::endl;
2716 return CONTENT_IGNORE;
2718 ISoundManager* Client::getSoundManager()
2722 MtEventManager* Client::getEventManager()