3 Copyright (C) 2010 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"
36 #include <IFileSystem.h>
39 #include "clientmap.h"
40 #include "filecache.h"
42 #include "util/string.h"
44 #include "IMeshCache.h"
46 static std::string getMediaCacheDir()
48 return porting::path_user + DIR_DELIM + "cache" + DIR_DELIM + "media";
55 MediaRequest(const std::string &name_=""):
64 QueuedMeshUpdate::QueuedMeshUpdate():
67 ack_block_to_server(false)
71 QueuedMeshUpdate::~QueuedMeshUpdate()
81 MeshUpdateQueue::MeshUpdateQueue()
86 MeshUpdateQueue::~MeshUpdateQueue()
88 JMutexAutoLock lock(m_mutex);
90 for(std::vector<QueuedMeshUpdate*>::iterator
92 i != m_queue.end(); i++)
94 QueuedMeshUpdate *q = *i;
100 peer_id=0 adds with nobody to send to
102 void MeshUpdateQueue::addBlock(v3s16 p, MeshMakeData *data, bool ack_block_to_server, bool urgent)
104 DSTACK(__FUNCTION_NAME);
108 JMutexAutoLock lock(m_mutex);
114 Find if block is already in queue.
115 If it is, update the data and quit.
117 for(std::vector<QueuedMeshUpdate*>::iterator
119 i != m_queue.end(); i++)
121 QueuedMeshUpdate *q = *i;
127 if(ack_block_to_server)
128 q->ack_block_to_server = true;
136 QueuedMeshUpdate *q = new QueuedMeshUpdate;
139 q->ack_block_to_server = ack_block_to_server;
140 m_queue.push_back(q);
143 // Returned pointer must be deleted
144 // Returns NULL if queue is empty
145 QueuedMeshUpdate * MeshUpdateQueue::pop()
147 JMutexAutoLock lock(m_mutex);
149 bool must_be_urgent = !m_urgents.empty();
150 for(std::vector<QueuedMeshUpdate*>::iterator
152 i != m_queue.end(); i++)
154 QueuedMeshUpdate *q = *i;
155 if(must_be_urgent && m_urgents.count(q->p) == 0)
158 m_urgents.erase(q->p);
168 void * MeshUpdateThread::Thread()
172 log_register_thread("MeshUpdateThread");
174 DSTACK(__FUNCTION_NAME);
176 BEGIN_DEBUG_EXCEPTION_HANDLER
180 /*// Wait for output queue to flush.
181 // Allow 2 in queue, this makes less frametime jitter.
182 // Umm actually, there is no much difference
183 if(m_queue_out.size() >= 2)
189 QueuedMeshUpdate *q = m_queue_in.pop();
196 ScopeProfiler sp(g_profiler, "Client: Mesh making");
198 MapBlockMesh *mesh_new = new MapBlockMesh(q->data);
199 if(mesh_new->getMesh()->getMeshBufferCount() == 0)
208 r.ack_block_to_server = q->ack_block_to_server;
210 /*infostream<<"MeshUpdateThread: Processed "
211 <<"("<<q->p.X<<","<<q->p.Y<<","<<q->p.Z<<")"
214 m_queue_out.push_back(r);
219 END_DEBUG_EXCEPTION_HANDLER(errorstream)
225 IrrlichtDevice *device,
226 const char *playername,
227 std::string password,
228 MapDrawControl &control,
229 IWritableTextureSource *tsrc,
230 IWritableItemDefManager *itemdef,
231 IWritableNodeDefManager *nodedef,
232 ISoundManager *sound,
233 MtEventManager *event
240 m_mesh_update_thread(this),
242 new ClientMap(this, this, control,
243 device->getSceneManager()->getRootSceneNode(),
244 device->getSceneManager(), 666),
245 device->getSceneManager(),
248 m_con(PROTOCOL_ID, 512, CONNECTION_TIMEOUT, this),
250 m_server_ser_ver(SER_FMT_VER_INVALID),
252 m_inventory_updated(false),
253 m_inventory_from_server(NULL),
254 m_inventory_from_server_age(0.0),
259 m_password(password),
260 m_access_denied(false),
261 m_media_cache(getMediaCacheDir()),
262 m_media_receive_progress(0),
263 m_media_received(false),
264 m_itemdef_received(false),
265 m_nodedef_received(false),
266 m_time_of_day_set(false),
267 m_last_time_of_day_f(-1),
268 m_time_of_day_update_timer(0),
269 m_removed_sounds_check_timer(0)
271 m_packetcounter_timer = 0.0;
272 //m_delete_unused_sectors_timer = 0.0;
273 m_connection_reinit_timer = 0.0;
274 m_avg_rtt_timer = 0.0;
275 m_playerpos_send_timer = 0.0;
276 m_ignore_damage_timer = 0.0;
278 // Build main texture atlas, now that the GameDef exists (that is, us)
279 if(g_settings->getBool("enable_texture_atlas"))
280 m_tsrc->buildMainAtlas(this);
282 infostream<<"Not building texture atlas."<<std::endl;
288 Player *player = new LocalPlayer(this);
290 player->updateName(playername);
292 m_env.addPlayer(player);
299 //JMutexAutoLock conlock(m_con_mutex); //bulk comment-out
303 m_mesh_update_thread.setRun(false);
304 while(m_mesh_update_thread.IsRunning())
307 delete m_inventory_from_server;
309 // Delete detached inventories
311 for(std::map<std::string, Inventory*>::iterator
312 i = m_detached_inventories.begin();
313 i != m_detached_inventories.end(); i++){
319 void Client::connect(Address address)
321 DSTACK(__FUNCTION_NAME);
322 //JMutexAutoLock lock(m_con_mutex); //bulk comment-out
323 m_con.SetTimeoutMs(0);
324 m_con.Connect(address);
327 bool Client::connectedAndInitialized()
329 //JMutexAutoLock lock(m_con_mutex); //bulk comment-out
331 if(m_con.Connected() == false)
334 if(m_server_ser_ver == SER_FMT_VER_INVALID)
340 void Client::step(float dtime)
342 DSTACK(__FUNCTION_NAME);
348 if(m_ignore_damage_timer > dtime)
349 m_ignore_damage_timer -= dtime;
351 m_ignore_damage_timer = 0.0;
353 m_animation_time += dtime;
354 if(m_animation_time > 60.0)
355 m_animation_time -= 60.0;
357 m_time_of_day_update_timer += dtime;
359 //infostream<<"Client steps "<<dtime<<std::endl;
362 //TimeTaker timer("ReceiveAll()", m_device);
368 //TimeTaker timer("m_con_mutex + m_con.RunTimeouts()", m_device);
370 //JMutexAutoLock lock(m_con_mutex); //bulk comment-out
371 m_con.RunTimeouts(dtime);
378 float &counter = m_packetcounter_timer;
384 infostream<<"Client packetcounter (20s):"<<std::endl;
385 m_packetcounter.print(infostream);
386 m_packetcounter.clear();
390 // Get connection status
391 bool connected = connectedAndInitialized();
396 Delete unused sectors
398 NOTE: This jams the game for a while because deleting sectors
402 float &counter = m_delete_unused_sectors_timer;
410 //JMutexAutoLock lock(m_env_mutex); //bulk comment-out
412 core::list<v3s16> deleted_blocks;
414 float delete_unused_sectors_timeout =
415 g_settings->getFloat("client_delete_unused_sectors_timeout");
417 // Delete sector blocks
418 /*u32 num = m_env.getMap().unloadUnusedData
419 (delete_unused_sectors_timeout,
420 true, &deleted_blocks);*/
422 // Delete whole sectors
423 m_env.getMap().unloadUnusedData
424 (delete_unused_sectors_timeout,
427 if(deleted_blocks.size() > 0)
429 /*infostream<<"Client: Deleted blocks of "<<num
430 <<" unused sectors"<<std::endl;*/
431 /*infostream<<"Client: Deleted "<<num
432 <<" unused sectors"<<std::endl;*/
438 // Env is locked so con can be locked.
439 //JMutexAutoLock lock(m_con_mutex); //bulk comment-out
441 core::list<v3s16>::Iterator i = deleted_blocks.begin();
442 core::list<v3s16> sendlist;
445 if(sendlist.size() == 255 || i == deleted_blocks.end())
447 if(sendlist.size() == 0)
456 u32 replysize = 2+1+6*sendlist.size();
457 SharedBuffer<u8> reply(replysize);
458 writeU16(&reply[0], TOSERVER_DELETEDBLOCKS);
459 reply[2] = sendlist.size();
461 for(core::list<v3s16>::Iterator
462 j = sendlist.begin();
463 j != sendlist.end(); j++)
465 writeV3S16(&reply[2+1+6*k], *j);
468 m_con.Send(PEER_ID_SERVER, 1, reply, true);
470 if(i == deleted_blocks.end())
476 sendlist.push_back(*i);
484 if(connected == false)
486 float &counter = m_connection_reinit_timer;
492 //JMutexAutoLock envlock(m_env_mutex); //bulk comment-out
494 Player *myplayer = m_env.getLocalPlayer();
495 assert(myplayer != NULL);
497 // Send TOSERVER_INIT
498 // [0] u16 TOSERVER_INIT
499 // [2] u8 SER_FMT_VER_HIGHEST
500 // [3] u8[20] player_name
501 // [23] u8[28] password (new in some version)
502 // [51] u16 client network protocol version (new in some version)
503 SharedBuffer<u8> data(2+1+PLAYERNAME_SIZE+PASSWORD_SIZE+2);
504 writeU16(&data[0], TOSERVER_INIT);
505 writeU8(&data[2], SER_FMT_VER_HIGHEST);
507 memset((char*)&data[3], 0, PLAYERNAME_SIZE);
508 snprintf((char*)&data[3], PLAYERNAME_SIZE, "%s", myplayer->getName());
510 /*infostream<<"Client: sending initial password hash: \""<<m_password<<"\""
513 memset((char*)&data[23], 0, PASSWORD_SIZE);
514 snprintf((char*)&data[23], PASSWORD_SIZE, "%s", m_password.c_str());
516 // This should be incremented in each version
517 writeU16(&data[51], PROTOCOL_VERSION);
519 // Send as unreliable
520 Send(0, data, false);
523 // Not connected, return
528 Do stuff if connected
532 Run Map's timers and unload unused data
534 const float map_timer_and_unload_dtime = 5.25;
535 if(m_map_timer_and_unload_interval.step(dtime, map_timer_and_unload_dtime))
537 ScopeProfiler sp(g_profiler, "Client: map timer and unload");
538 core::list<v3s16> deleted_blocks;
539 m_env.getMap().timerUpdate(map_timer_and_unload_dtime,
540 g_settings->getFloat("client_unload_unused_data_timeout"),
543 /*if(deleted_blocks.size() > 0)
544 infostream<<"Client: Unloaded "<<deleted_blocks.size()
545 <<" unused blocks"<<std::endl;*/
549 NOTE: This loop is intentionally iterated the way it is.
552 core::list<v3s16>::Iterator i = deleted_blocks.begin();
553 core::list<v3s16> sendlist;
556 if(sendlist.size() == 255 || i == deleted_blocks.end())
558 if(sendlist.size() == 0)
567 u32 replysize = 2+1+6*sendlist.size();
568 SharedBuffer<u8> reply(replysize);
569 writeU16(&reply[0], TOSERVER_DELETEDBLOCKS);
570 reply[2] = sendlist.size();
572 for(core::list<v3s16>::Iterator
573 j = sendlist.begin();
574 j != sendlist.end(); j++)
576 writeV3S16(&reply[2+1+6*k], *j);
579 m_con.Send(PEER_ID_SERVER, 1, reply, true);
581 if(i == deleted_blocks.end())
587 sendlist.push_back(*i);
597 //JMutexAutoLock lock(m_env_mutex); //bulk comment-out
599 // Control local player (0ms)
600 LocalPlayer *player = m_env.getLocalPlayer();
601 assert(player != NULL);
602 player->applyControl(dtime);
604 //TimeTaker envtimer("env step", m_device);
613 ClientEnvEvent event = m_env.getClientEvent();
614 if(event.type == CEE_NONE)
618 else if(event.type == CEE_PLAYER_DAMAGE)
620 if(m_ignore_damage_timer <= 0)
622 u8 damage = event.player_damage.amount;
624 if(event.player_damage.send_to_server)
627 // Add to ClientEvent queue
629 event.type = CE_PLAYER_DAMAGE;
630 event.player_damage.amount = damage;
631 m_client_event_queue.push_back(event);
641 float &counter = m_avg_rtt_timer;
646 //JMutexAutoLock lock(m_con_mutex); //bulk comment-out
647 // connectedAndInitialized() is true, peer exists.
648 float avg_rtt = m_con.GetPeerAvgRTT(PEER_ID_SERVER);
649 infostream<<"Client: avg_rtt="<<avg_rtt<<std::endl;
654 Send player position to server
657 float &counter = m_playerpos_send_timer;
667 Replace updated meshes
670 //JMutexAutoLock lock(m_env_mutex); //bulk comment-out
672 //TimeTaker timer("** Processing mesh update result queue");
675 /*infostream<<"Mesh update result queue size is "
676 <<m_mesh_update_thread.m_queue_out.size()
679 int num_processed_meshes = 0;
680 while(m_mesh_update_thread.m_queue_out.size() > 0)
682 num_processed_meshes++;
683 MeshUpdateResult r = m_mesh_update_thread.m_queue_out.pop_front();
684 MapBlock *block = m_env.getMap().getBlockNoCreateNoEx(r.p);
687 //JMutexAutoLock lock(block->mesh_mutex);
689 // Delete the old mesh
690 if(block->mesh != NULL)
692 // TODO: Remove hardware buffers of meshbuffers of block->mesh
697 // Replace with the new mesh
698 block->mesh = r.mesh;
700 if(r.ack_block_to_server)
702 /*infostream<<"Client: ACK block ("<<r.p.X<<","<<r.p.Y
703 <<","<<r.p.Z<<")"<<std::endl;*/
714 u32 replysize = 2+1+6;
715 SharedBuffer<u8> reply(replysize);
716 writeU16(&reply[0], TOSERVER_GOTBLOCKS);
718 writeV3S16(&reply[3], r.p);
720 m_con.Send(PEER_ID_SERVER, 1, reply, true);
723 if(num_processed_meshes > 0)
724 g_profiler->graphAdd("num_processed_meshes", num_processed_meshes);
728 If the server didn't update the inventory in a while, revert
729 the local inventory (so the player notices the lag problem
730 and knows something is wrong).
732 if(m_inventory_from_server)
734 float interval = 10.0;
735 float count_before = floor(m_inventory_from_server_age / interval);
737 m_inventory_from_server_age += dtime;
739 float count_after = floor(m_inventory_from_server_age / interval);
741 if(count_after != count_before)
743 // Do this every <interval> seconds after TOCLIENT_INVENTORY
744 // Reset the locally changed inventory to the authoritative inventory
745 Player *player = m_env.getLocalPlayer();
746 player->inventory = *m_inventory_from_server;
747 m_inventory_updated = true;
752 Update positions of sounds attached to objects
755 for(std::map<int, u16>::iterator
756 i = m_sounds_to_objects.begin();
757 i != m_sounds_to_objects.end(); i++)
759 int client_id = i->first;
760 u16 object_id = i->second;
761 ClientActiveObject *cao = m_env.getActiveObject(object_id);
764 v3f pos = cao->getPosition();
765 m_sound->updateSoundPosition(client_id, pos);
770 Handle removed remotely initiated sounds
772 m_removed_sounds_check_timer += dtime;
773 if(m_removed_sounds_check_timer >= 2.32)
775 m_removed_sounds_check_timer = 0;
776 // Find removed sounds and clear references to them
777 std::set<s32> removed_server_ids;
778 for(std::map<s32, int>::iterator
779 i = m_sounds_server_to_client.begin();
780 i != m_sounds_server_to_client.end();)
782 s32 server_id = i->first;
783 int client_id = i->second;
785 if(!m_sound->soundExists(client_id)){
786 m_sounds_server_to_client.erase(server_id);
787 m_sounds_client_to_server.erase(client_id);
788 m_sounds_to_objects.erase(client_id);
789 removed_server_ids.insert(server_id);
793 if(removed_server_ids.size() != 0)
795 std::ostringstream os(std::ios_base::binary);
796 writeU16(os, TOSERVER_REMOVED_SOUNDS);
797 writeU16(os, removed_server_ids.size());
798 for(std::set<s32>::iterator i = removed_server_ids.begin();
799 i != removed_server_ids.end(); i++)
801 std::string s = os.str();
802 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
809 bool Client::loadMedia(const std::string &data, const std::string &filename)
811 // Silly irrlicht's const-incorrectness
812 Buffer<char> data_rw(data.c_str(), data.size());
816 const char *image_ext[] = {
817 ".png", ".jpg", ".bmp", ".tga",
818 ".pcx", ".ppm", ".psd", ".wal", ".rgb",
821 name = removeStringEnd(filename, image_ext);
824 verbosestream<<"Client: Attempting to load image "
825 <<"file \""<<filename<<"\""<<std::endl;
827 io::IFileSystem *irrfs = m_device->getFileSystem();
828 video::IVideoDriver *vdrv = m_device->getVideoDriver();
830 // Create an irrlicht memory file
831 io::IReadFile *rfile = irrfs->createMemoryReadFile(
832 *data_rw, data_rw.getSize(), "_tempreadfile");
835 video::IImage *img = vdrv->createImageFromFile(rfile);
837 errorstream<<"Client: Cannot create image from data of "
838 <<"file \""<<filename<<"\""<<std::endl;
843 m_tsrc->insertSourceImage(filename, img);
850 const char *sound_ext[] = {
851 ".0.ogg", ".1.ogg", ".2.ogg", ".3.ogg", ".4.ogg",
852 ".5.ogg", ".6.ogg", ".7.ogg", ".8.ogg", ".9.ogg",
855 name = removeStringEnd(filename, sound_ext);
858 verbosestream<<"Client: Attempting to load sound "
859 <<"file \""<<filename<<"\""<<std::endl;
860 m_sound->loadSoundData(name, data);
864 const char *model_ext[] = {
865 ".x", ".b3d", ".md2", ".obj",
868 name = removeStringEnd(filename, model_ext);
871 verbosestream<<"Client: Storing model into Irrlicht: "
872 <<"\""<<filename<<"\""<<std::endl;
874 io::IFileSystem *irrfs = m_device->getFileSystem();
875 io::IReadFile *rfile = irrfs->createMemoryReadFile(
876 *data_rw, data_rw.getSize(), filename.c_str());
879 scene::ISceneManager *smgr = m_device->getSceneManager();
880 scene::IAnimatedMesh *mesh = smgr->getMesh(rfile);
881 smgr->getMeshCache()->addMesh(filename.c_str(), mesh);
886 errorstream<<"Client: Don't know how to load file \""
887 <<filename<<"\""<<std::endl;
891 // Virtual methods from con::PeerHandler
892 void Client::peerAdded(con::Peer *peer)
894 infostream<<"Client::peerAdded(): peer->id="
895 <<peer->id<<std::endl;
897 void Client::deletingPeer(con::Peer *peer, bool timeout)
899 infostream<<"Client::deletingPeer(): "
900 "Server Peer is getting deleted "
901 <<"(timeout="<<timeout<<")"<<std::endl;
904 void Client::ReceiveAll()
906 DSTACK(__FUNCTION_NAME);
907 u32 start_ms = porting::getTimeMs();
910 // Limit time even if there would be huge amounts of data to
912 if(porting::getTimeMs() > start_ms + 100)
917 g_profiler->graphAdd("client_received_packets", 1);
919 catch(con::NoIncomingDataException &e)
923 catch(con::InvalidIncomingDataException &e)
925 infostream<<"Client::ReceiveAll(): "
926 "InvalidIncomingDataException: what()="
927 <<e.what()<<std::endl;
932 void Client::Receive()
934 DSTACK(__FUNCTION_NAME);
935 SharedBuffer<u8> data;
939 //TimeTaker t1("con mutex and receive", m_device);
940 //JMutexAutoLock lock(m_con_mutex); //bulk comment-out
941 datasize = m_con.Receive(sender_peer_id, data);
943 //TimeTaker t1("ProcessData", m_device);
944 ProcessData(*data, datasize, sender_peer_id);
948 sender_peer_id given to this shall be quaranteed to be a valid peer
950 void Client::ProcessData(u8 *data, u32 datasize, u16 sender_peer_id)
952 DSTACK(__FUNCTION_NAME);
954 // Ignore packets that don't even fit a command
957 m_packetcounter.add(60000);
961 ToClientCommand command = (ToClientCommand)readU16(&data[0]);
963 //infostream<<"Client: received command="<<command<<std::endl;
964 m_packetcounter.add((u16)command);
967 If this check is removed, be sure to change the queue
968 system to know the ids
970 if(sender_peer_id != PEER_ID_SERVER)
972 infostream<<"Client::ProcessData(): Discarding data not "
973 "coming from server: peer_id="<<sender_peer_id
978 u8 ser_version = m_server_ser_ver;
980 //infostream<<"Client received command="<<(int)command<<std::endl;
982 if(command == TOCLIENT_INIT)
987 u8 deployed = data[2];
989 infostream<<"Client: TOCLIENT_INIT received with "
990 "deployed="<<((int)deployed&0xff)<<std::endl;
992 if(deployed < SER_FMT_VER_LOWEST
993 || deployed > SER_FMT_VER_HIGHEST)
995 infostream<<"Client: TOCLIENT_INIT: Server sent "
996 <<"unsupported ser_fmt_ver"<<std::endl;
1000 m_server_ser_ver = deployed;
1002 // Get player position
1003 v3s16 playerpos_s16(0, BS*2+BS*20, 0);
1004 if(datasize >= 2+1+6)
1005 playerpos_s16 = readV3S16(&data[2+1]);
1006 v3f playerpos_f = intToFloat(playerpos_s16, BS) - v3f(0, BS/2, 0);
1009 //JMutexAutoLock envlock(m_env_mutex); //bulk comment-out
1011 // Set player position
1012 Player *player = m_env.getLocalPlayer();
1013 assert(player != NULL);
1014 player->setPosition(playerpos_f);
1017 if(datasize >= 2+1+6+8)
1020 m_map_seed = readU64(&data[2+1+6]);
1021 infostream<<"Client: received map seed: "<<m_map_seed<<std::endl;
1026 SharedBuffer<u8> reply(replysize);
1027 writeU16(&reply[0], TOSERVER_INIT2);
1029 m_con.Send(PEER_ID_SERVER, 1, reply, true);
1034 if(command == TOCLIENT_ACCESS_DENIED)
1036 // The server didn't like our password. Note, this needs
1037 // to be processed even if the serialisation format has
1038 // not been agreed yet, the same as TOCLIENT_INIT.
1039 m_access_denied = true;
1040 m_access_denied_reason = L"Unknown";
1043 std::string datastring((char*)&data[2], datasize-2);
1044 std::istringstream is(datastring, std::ios_base::binary);
1045 m_access_denied_reason = deSerializeWideString(is);
1050 if(ser_version == SER_FMT_VER_INVALID)
1052 infostream<<"Client: Server serialization"
1053 " format invalid or not initialized."
1054 " Skipping incoming command="<<command<<std::endl;
1058 // Just here to avoid putting the two if's together when
1059 // making some copypasta
1062 if(command == TOCLIENT_REMOVENODE)
1067 p.X = readS16(&data[2]);
1068 p.Y = readS16(&data[4]);
1069 p.Z = readS16(&data[6]);
1071 //TimeTaker t1("TOCLIENT_REMOVENODE");
1075 else if(command == TOCLIENT_ADDNODE)
1077 if(datasize < 8 + MapNode::serializedLength(ser_version))
1081 p.X = readS16(&data[2]);
1082 p.Y = readS16(&data[4]);
1083 p.Z = readS16(&data[6]);
1085 //TimeTaker t1("TOCLIENT_ADDNODE");
1088 n.deSerialize(&data[8], ser_version);
1092 else if(command == TOCLIENT_BLOCKDATA)
1094 // Ignore too small packet
1099 p.X = readS16(&data[2]);
1100 p.Y = readS16(&data[4]);
1101 p.Z = readS16(&data[6]);
1103 /*infostream<<"Client: Thread: BLOCKDATA for ("
1104 <<p.X<<","<<p.Y<<","<<p.Z<<")"<<std::endl;*/
1105 /*infostream<<"Client: Thread: BLOCKDATA for ("
1106 <<p.X<<","<<p.Y<<","<<p.Z<<")"<<std::endl;*/
1108 std::string datastring((char*)&data[8], datasize-8);
1109 std::istringstream istr(datastring, std::ios_base::binary);
1114 v2s16 p2d(p.X, p.Z);
1115 sector = m_env.getMap().emergeSector(p2d);
1117 assert(sector->getPos() == p2d);
1119 //TimeTaker timer("MapBlock deSerialize");
1122 block = sector->getBlockNoCreateNoEx(p.Y);
1126 Update an existing block
1128 //infostream<<"Updating"<<std::endl;
1129 block->deSerialize(istr, ser_version, false);
1136 //infostream<<"Creating new"<<std::endl;
1137 block = new MapBlock(&m_env.getMap(), p, this);
1138 block->deSerialize(istr, ser_version, false);
1139 sector->insertBlock(block);
1153 u32 replysize = 2+1+6;
1154 SharedBuffer<u8> reply(replysize);
1155 writeU16(&reply[0], TOSERVER_GOTBLOCKS);
1157 writeV3S16(&reply[3], p);
1159 m_con.Send(PEER_ID_SERVER, 1, reply, true);
1163 Add it to mesh update queue and set it to be acknowledged after update.
1165 //infostream<<"Adding mesh update task for received block"<<std::endl;
1166 addUpdateMeshTaskWithEdge(p, true);
1168 else if(command == TOCLIENT_INVENTORY)
1173 //TimeTaker t1("Parsing TOCLIENT_INVENTORY", m_device);
1176 //TimeTaker t2("mutex locking", m_device);
1177 //JMutexAutoLock envlock(m_env_mutex); //bulk comment-out
1180 //TimeTaker t3("istringstream init", m_device);
1181 std::string datastring((char*)&data[2], datasize-2);
1182 std::istringstream is(datastring, std::ios_base::binary);
1185 //m_env.printPlayers(infostream);
1187 //TimeTaker t4("player get", m_device);
1188 Player *player = m_env.getLocalPlayer();
1189 assert(player != NULL);
1192 //TimeTaker t1("inventory.deSerialize()", m_device);
1193 player->inventory.deSerialize(is);
1196 m_inventory_updated = true;
1198 delete m_inventory_from_server;
1199 m_inventory_from_server = new Inventory(player->inventory);
1200 m_inventory_from_server_age = 0.0;
1202 //infostream<<"Client got player inventory:"<<std::endl;
1203 //player->inventory.print(infostream);
1206 else if(command == TOCLIENT_TIME_OF_DAY)
1211 u16 time_of_day = readU16(&data[2]);
1212 time_of_day = time_of_day % 24000;
1213 //infostream<<"Client: time_of_day="<<time_of_day<<std::endl;
1214 float time_speed = 0;
1215 if(datasize >= 2 + 2 + 4){
1216 time_speed = readF1000(&data[4]);
1218 // Old message; try to approximate speed of time by ourselves
1219 float time_of_day_f = (float)time_of_day / 24000.0;
1220 float tod_diff_f = 0;
1221 if(time_of_day_f < 0.2 && m_last_time_of_day_f > 0.8)
1222 tod_diff_f = time_of_day_f - m_last_time_of_day_f + 1.0;
1224 tod_diff_f = time_of_day_f - m_last_time_of_day_f;
1225 m_last_time_of_day_f = time_of_day_f;
1226 float time_diff = m_time_of_day_update_timer;
1227 m_time_of_day_update_timer = 0;
1228 if(m_time_of_day_set){
1229 time_speed = 3600.0*24.0 * tod_diff_f / time_diff;
1230 infostream<<"Client: Measured time_of_day speed (old format): "
1231 <<time_speed<<" tod_diff_f="<<tod_diff_f
1232 <<" time_diff="<<time_diff<<std::endl;
1236 // Update environment
1237 m_env.setTimeOfDay(time_of_day);
1238 m_env.setTimeOfDaySpeed(time_speed);
1239 m_time_of_day_set = true;
1241 u32 dr = m_env.getDayNightRatio();
1242 verbosestream<<"Client: time_of_day="<<time_of_day
1243 <<" time_speed="<<time_speed
1244 <<" dr="<<dr<<std::endl;
1246 else if(command == TOCLIENT_CHAT_MESSAGE)
1254 std::string datastring((char*)&data[2], datasize-2);
1255 std::istringstream is(datastring, std::ios_base::binary);
1258 is.read((char*)buf, 2);
1259 u16 len = readU16(buf);
1261 std::wstring message;
1262 for(u16 i=0; i<len; i++)
1264 is.read((char*)buf, 2);
1265 message += (wchar_t)readU16(buf);
1268 /*infostream<<"Client received chat message: "
1269 <<wide_to_narrow(message)<<std::endl;*/
1271 m_chat_queue.push_back(message);
1273 else if(command == TOCLIENT_ACTIVE_OBJECT_REMOVE_ADD)
1275 //if(g_settings->getBool("enable_experimental"))
1279 u16 count of removed objects
1280 for all removed objects {
1283 u16 count of added objects
1284 for all added objects {
1287 u32 initialization data length
1288 string initialization data
1293 // Get all data except the command number
1294 std::string datastring((char*)&data[2], datasize-2);
1295 // Throw them in an istringstream
1296 std::istringstream is(datastring, std::ios_base::binary);
1300 // Read removed objects
1302 u16 removed_count = readU16((u8*)buf);
1303 for(u16 i=0; i<removed_count; i++)
1306 u16 id = readU16((u8*)buf);
1309 //JMutexAutoLock envlock(m_env_mutex); //bulk comment-out
1310 m_env.removeActiveObject(id);
1314 // Read added objects
1316 u16 added_count = readU16((u8*)buf);
1317 for(u16 i=0; i<added_count; i++)
1320 u16 id = readU16((u8*)buf);
1322 u8 type = readU8((u8*)buf);
1323 std::string data = deSerializeLongString(is);
1326 //JMutexAutoLock envlock(m_env_mutex); //bulk comment-out
1327 m_env.addActiveObject(id, type, data);
1332 else if(command == TOCLIENT_ACTIVE_OBJECT_MESSAGES)
1334 //if(g_settings->getBool("enable_experimental"))
1346 // Get all data except the command number
1347 std::string datastring((char*)&data[2], datasize-2);
1348 // Throw them in an istringstream
1349 std::istringstream is(datastring, std::ios_base::binary);
1351 while(is.eof() == false)
1355 u16 id = readU16((u8*)buf);
1359 u16 message_size = readU16((u8*)buf);
1360 std::string message;
1361 message.reserve(message_size);
1362 for(u16 i=0; i<message_size; i++)
1365 message.append(buf, 1);
1367 // Pass on to the environment
1369 //JMutexAutoLock envlock(m_env_mutex); //bulk comment-out
1370 m_env.processActiveObjectMessage(id, message);
1375 else if(command == TOCLIENT_HP)
1377 std::string datastring((char*)&data[2], datasize-2);
1378 std::istringstream is(datastring, std::ios_base::binary);
1379 Player *player = m_env.getLocalPlayer();
1380 assert(player != NULL);
1381 u8 oldhp = player->hp;
1387 // Add to ClientEvent queue
1389 event.type = CE_PLAYER_DAMAGE;
1390 event.player_damage.amount = oldhp - hp;
1391 m_client_event_queue.push_back(event);
1394 else if(command == TOCLIENT_MOVE_PLAYER)
1396 std::string datastring((char*)&data[2], datasize-2);
1397 std::istringstream is(datastring, std::ios_base::binary);
1398 Player *player = m_env.getLocalPlayer();
1399 assert(player != NULL);
1400 v3f pos = readV3F1000(is);
1401 f32 pitch = readF1000(is);
1402 f32 yaw = readF1000(is);
1403 player->setPosition(pos);
1404 /*player->setPitch(pitch);
1405 player->setYaw(yaw);*/
1407 infostream<<"Client got TOCLIENT_MOVE_PLAYER"
1408 <<" pos=("<<pos.X<<","<<pos.Y<<","<<pos.Z<<")"
1414 Add to ClientEvent queue.
1415 This has to be sent to the main program because otherwise
1416 it would just force the pitch and yaw values to whatever
1417 the camera points to.
1420 event.type = CE_PLAYER_FORCE_MOVE;
1421 event.player_force_move.pitch = pitch;
1422 event.player_force_move.yaw = yaw;
1423 m_client_event_queue.push_back(event);
1425 // Ignore damage for a few seconds, so that the player doesn't
1426 // get damage from falling on ground
1427 m_ignore_damage_timer = 3.0;
1429 else if(command == TOCLIENT_PLAYERITEM)
1431 infostream<<"Client: WARNING: Ignoring TOCLIENT_PLAYERITEM"<<std::endl;
1433 else if(command == TOCLIENT_DEATHSCREEN)
1435 std::string datastring((char*)&data[2], datasize-2);
1436 std::istringstream is(datastring, std::ios_base::binary);
1438 bool set_camera_point_target = readU8(is);
1439 v3f camera_point_target = readV3F1000(is);
1442 event.type = CE_DEATHSCREEN;
1443 event.deathscreen.set_camera_point_target = set_camera_point_target;
1444 event.deathscreen.camera_point_target_x = camera_point_target.X;
1445 event.deathscreen.camera_point_target_y = camera_point_target.Y;
1446 event.deathscreen.camera_point_target_z = camera_point_target.Z;
1447 m_client_event_queue.push_back(event);
1449 else if(command == TOCLIENT_ANNOUNCE_MEDIA)
1451 std::string datastring((char*)&data[2], datasize-2);
1452 std::istringstream is(datastring, std::ios_base::binary);
1454 // Mesh update thread must be stopped while
1455 // updating content definitions
1456 assert(!m_mesh_update_thread.IsRunning());
1458 int num_files = readU16(is);
1460 verbosestream<<"Client received TOCLIENT_ANNOUNCE_MEDIA ("
1461 <<num_files<<" files)"<<std::endl;
1463 core::list<MediaRequest> file_requests;
1465 for(int i=0; i<num_files; i++)
1467 //read file from cache
1468 std::string name = deSerializeString(is);
1469 std::string sha1_base64 = deSerializeString(is);
1471 // if name contains illegal characters, ignore the file
1472 if(!string_allowed(name, TEXTURENAME_ALLOWED_CHARS)){
1473 errorstream<<"Client: ignoring illegal file name "
1474 <<"sent by server: \""<<name<<"\""<<std::endl;
1478 std::string sha1_raw = base64_decode(sha1_base64);
1479 std::string sha1_hex = hex_encode(sha1_raw);
1480 std::ostringstream tmp_os(std::ios_base::binary);
1481 bool found_in_cache = m_media_cache.load_sha1(sha1_raw, tmp_os);
1482 m_media_name_sha1_map.set(name, sha1_raw);
1484 // If found in cache, try to load it from there
1487 bool success = loadMedia(tmp_os.str(), name);
1489 verbosestream<<"Client: Loaded cached media: "
1490 <<sha1_hex<<" \""<<name<<"\""<<std::endl;
1493 infostream<<"Client: Failed to load cached media: "
1494 <<sha1_hex<<" \""<<name<<"\""<<std::endl;
1497 // Didn't load from cache; queue it to be requested
1498 verbosestream<<"Client: Adding file to request list: \""
1499 <<sha1_hex<<" \""<<name<<"\""<<std::endl;
1500 file_requests.push_back(MediaRequest(name));
1504 event.type = CE_TEXTURES_UPDATED;
1505 m_client_event_queue.push_back(event);
1509 u16 number of files requested
1515 std::ostringstream os(std::ios_base::binary);
1516 writeU16(os, TOSERVER_REQUEST_MEDIA);
1517 writeU16(os, file_requests.size());
1519 for(core::list<MediaRequest>::Iterator i = file_requests.begin();
1520 i != file_requests.end(); i++) {
1521 os<<serializeString(i->name);
1525 std::string s = os.str();
1526 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
1528 Send(0, data, true);
1529 infostream<<"Client: Sending media request list to server ("
1530 <<file_requests.size()<<" files)"<<std::endl;
1532 else if(command == TOCLIENT_MEDIA)
1534 std::string datastring((char*)&data[2], datasize-2);
1535 std::istringstream is(datastring, std::ios_base::binary);
1537 // Mesh update thread must be stopped while
1538 // updating content definitions
1539 assert(!m_mesh_update_thread.IsRunning());
1543 u16 total number of file bunches
1544 u16 index of this bunch
1545 u32 number of files in this bunch
1553 int num_bunches = readU16(is);
1554 int bunch_i = readU16(is);
1555 if(num_bunches >= 2)
1556 m_media_receive_progress = (float)bunch_i / (float)(num_bunches - 1);
1558 m_media_receive_progress = 1.0;
1559 if(bunch_i == num_bunches - 1)
1560 m_media_received = true;
1561 int num_files = readU32(is);
1562 infostream<<"Client: Received files: bunch "<<bunch_i<<"/"
1563 <<num_bunches<<" files="<<num_files
1564 <<" size="<<datasize<<std::endl;
1565 for(int i=0; i<num_files; i++){
1566 std::string name = deSerializeString(is);
1567 std::string data = deSerializeLongString(is);
1569 // if name contains illegal characters, ignore the file
1570 if(!string_allowed(name, TEXTURENAME_ALLOWED_CHARS)){
1571 errorstream<<"Client: ignoring illegal file name "
1572 <<"sent by server: \""<<name<<"\""<<std::endl;
1576 bool success = loadMedia(data, name);
1578 verbosestream<<"Client: Loaded received media: "
1579 <<"\""<<name<<"\". Caching."<<std::endl;
1581 infostream<<"Client: Failed to load received media: "
1582 <<"\""<<name<<"\". Not caching."<<std::endl;
1586 bool did = fs::CreateAllDirs(getMediaCacheDir());
1588 errorstream<<"Could not create media cache directory"
1593 core::map<std::string, std::string>::Node *n;
1594 n = m_media_name_sha1_map.find(name);
1596 errorstream<<"The server sent a file that has not "
1597 <<"been announced."<<std::endl;
1599 m_media_cache.update_sha1(data);
1604 event.type = CE_TEXTURES_UPDATED;
1605 m_client_event_queue.push_back(event);
1607 else if(command == TOCLIENT_TOOLDEF)
1609 infostream<<"Client: WARNING: Ignoring TOCLIENT_TOOLDEF"<<std::endl;
1611 else if(command == TOCLIENT_NODEDEF)
1613 infostream<<"Client: Received node definitions: packet size: "
1614 <<datasize<<std::endl;
1616 // Mesh update thread must be stopped while
1617 // updating content definitions
1618 assert(!m_mesh_update_thread.IsRunning());
1620 // Decompress node definitions
1621 std::string datastring((char*)&data[2], datasize-2);
1622 std::istringstream is(datastring, std::ios_base::binary);
1623 std::istringstream tmp_is(deSerializeLongString(is), std::ios::binary);
1624 std::ostringstream tmp_os;
1625 decompressZlib(tmp_is, tmp_os);
1627 // Deserialize node definitions
1628 std::istringstream tmp_is2(tmp_os.str());
1629 m_nodedef->deSerialize(tmp_is2);
1630 m_nodedef_received = true;
1632 else if(command == TOCLIENT_CRAFTITEMDEF)
1634 infostream<<"Client: WARNING: Ignoring TOCLIENT_CRAFTITEMDEF"<<std::endl;
1636 else if(command == TOCLIENT_ITEMDEF)
1638 infostream<<"Client: Received item definitions: packet size: "
1639 <<datasize<<std::endl;
1641 // Mesh update thread must be stopped while
1642 // updating content definitions
1643 assert(!m_mesh_update_thread.IsRunning());
1645 // Decompress item definitions
1646 std::string datastring((char*)&data[2], datasize-2);
1647 std::istringstream is(datastring, std::ios_base::binary);
1648 std::istringstream tmp_is(deSerializeLongString(is), std::ios::binary);
1649 std::ostringstream tmp_os;
1650 decompressZlib(tmp_is, tmp_os);
1652 // Deserialize node definitions
1653 std::istringstream tmp_is2(tmp_os.str());
1654 m_itemdef->deSerialize(tmp_is2);
1655 m_itemdef_received = true;
1657 else if(command == TOCLIENT_PLAY_SOUND)
1659 std::string datastring((char*)&data[2], datasize-2);
1660 std::istringstream is(datastring, std::ios_base::binary);
1662 s32 server_id = readS32(is);
1663 std::string name = deSerializeString(is);
1664 float gain = readF1000(is);
1665 int type = readU8(is); // 0=local, 1=positional, 2=object
1666 v3f pos = readV3F1000(is);
1667 u16 object_id = readU16(is);
1668 bool loop = readU8(is);
1673 client_id = m_sound->playSound(name, loop, gain);
1675 case 1: // positional
1676 client_id = m_sound->playSoundAt(name, loop, gain, pos);
1679 ClientActiveObject *cao = m_env.getActiveObject(object_id);
1681 pos = cao->getPosition();
1682 client_id = m_sound->playSoundAt(name, loop, gain, pos);
1683 // TODO: Set up sound to move with object
1688 if(client_id != -1){
1689 m_sounds_server_to_client[server_id] = client_id;
1690 m_sounds_client_to_server[client_id] = server_id;
1692 m_sounds_to_objects[client_id] = object_id;
1695 else if(command == TOCLIENT_STOP_SOUND)
1697 std::string datastring((char*)&data[2], datasize-2);
1698 std::istringstream is(datastring, std::ios_base::binary);
1700 s32 server_id = readS32(is);
1701 std::map<s32, int>::iterator i =
1702 m_sounds_server_to_client.find(server_id);
1703 if(i != m_sounds_server_to_client.end()){
1704 int client_id = i->second;
1705 m_sound->stopSound(client_id);
1708 else if(command == TOCLIENT_PRIVILEGES)
1710 std::string datastring((char*)&data[2], datasize-2);
1711 std::istringstream is(datastring, std::ios_base::binary);
1713 m_privileges.clear();
1714 infostream<<"Client: Privileges updated: ";
1715 u16 num_privileges = readU16(is);
1716 for(u16 i=0; i<num_privileges; i++){
1717 std::string priv = deSerializeString(is);
1718 m_privileges.insert(priv);
1719 infostream<<priv<<" ";
1721 infostream<<std::endl;
1723 else if(command == TOCLIENT_INVENTORY_FORMSPEC)
1725 std::string datastring((char*)&data[2], datasize-2);
1726 std::istringstream is(datastring, std::ios_base::binary);
1728 // Store formspec in LocalPlayer
1729 Player *player = m_env.getLocalPlayer();
1730 assert(player != NULL);
1731 player->inventory_formspec = deSerializeLongString(is);
1733 else if(command == TOCLIENT_DETACHED_INVENTORY)
1735 std::string datastring((char*)&data[2], datasize-2);
1736 std::istringstream is(datastring, std::ios_base::binary);
1738 std::string name = deSerializeString(is);
1740 infostream<<"Client: Detached inventory update: \""<<name<<"\""<<std::endl;
1742 Inventory *inv = NULL;
1743 if(m_detached_inventories.count(name) > 0)
1744 inv = m_detached_inventories[name];
1746 inv = new Inventory(m_itemdef);
1747 m_detached_inventories[name] = inv;
1749 inv->deSerialize(is);
1753 infostream<<"Client: Ignoring unknown command "
1754 <<command<<std::endl;
1758 void Client::Send(u16 channelnum, SharedBuffer<u8> data, bool reliable)
1760 //JMutexAutoLock lock(m_con_mutex); //bulk comment-out
1761 m_con.Send(PEER_ID_SERVER, channelnum, data, reliable);
1764 void Client::interact(u8 action, const PointedThing& pointed)
1766 if(connectedAndInitialized() == false){
1767 infostream<<"Client::interact() "
1768 "cancelled (not connected)"
1773 std::ostringstream os(std::ios_base::binary);
1779 [5] u32 length of the next item
1780 [9] serialized PointedThing
1782 0: start digging (from undersurface) or use
1783 1: stop digging (all parameters ignored)
1784 2: digging completed
1785 3: place block or item (to abovesurface)
1788 writeU16(os, TOSERVER_INTERACT);
1789 writeU8(os, action);
1790 writeU16(os, getPlayerItem());
1791 std::ostringstream tmp_os(std::ios::binary);
1792 pointed.serialize(tmp_os);
1793 os<<serializeLongString(tmp_os.str());
1795 std::string s = os.str();
1796 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
1799 Send(0, data, true);
1802 void Client::sendNodemetaFields(v3s16 p, const std::string &formname,
1803 const std::map<std::string, std::string> &fields)
1805 std::ostringstream os(std::ios_base::binary);
1807 writeU16(os, TOSERVER_NODEMETA_FIELDS);
1809 os<<serializeString(formname);
1810 writeU16(os, fields.size());
1811 for(std::map<std::string, std::string>::const_iterator
1812 i = fields.begin(); i != fields.end(); i++){
1813 const std::string &name = i->first;
1814 const std::string &value = i->second;
1815 os<<serializeString(name);
1816 os<<serializeLongString(value);
1820 std::string s = os.str();
1821 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
1823 Send(0, data, true);
1826 void Client::sendInventoryFields(const std::string &formname,
1827 const std::map<std::string, std::string> &fields)
1829 std::ostringstream os(std::ios_base::binary);
1831 writeU16(os, TOSERVER_INVENTORY_FIELDS);
1832 os<<serializeString(formname);
1833 writeU16(os, fields.size());
1834 for(std::map<std::string, std::string>::const_iterator
1835 i = fields.begin(); i != fields.end(); i++){
1836 const std::string &name = i->first;
1837 const std::string &value = i->second;
1838 os<<serializeString(name);
1839 os<<serializeLongString(value);
1843 std::string s = os.str();
1844 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
1846 Send(0, data, true);
1849 void Client::sendInventoryAction(InventoryAction *a)
1851 std::ostringstream os(std::ios_base::binary);
1855 writeU16(buf, TOSERVER_INVENTORY_ACTION);
1856 os.write((char*)buf, 2);
1861 std::string s = os.str();
1862 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
1864 Send(0, data, true);
1867 void Client::sendChatMessage(const std::wstring &message)
1869 std::ostringstream os(std::ios_base::binary);
1873 writeU16(buf, TOSERVER_CHAT_MESSAGE);
1874 os.write((char*)buf, 2);
1877 writeU16(buf, message.size());
1878 os.write((char*)buf, 2);
1881 for(u32 i=0; i<message.size(); i++)
1885 os.write((char*)buf, 2);
1889 std::string s = os.str();
1890 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
1892 Send(0, data, true);
1895 void Client::sendChangePassword(const std::wstring oldpassword,
1896 const std::wstring newpassword)
1898 Player *player = m_env.getLocalPlayer();
1902 std::string playername = player->getName();
1903 std::string oldpwd = translatePassword(playername, oldpassword);
1904 std::string newpwd = translatePassword(playername, newpassword);
1906 std::ostringstream os(std::ios_base::binary);
1907 u8 buf[2+PASSWORD_SIZE*2];
1909 [0] u16 TOSERVER_PASSWORD
1910 [2] u8[28] old password
1911 [30] u8[28] new password
1914 writeU16(buf, TOSERVER_PASSWORD);
1915 for(u32 i=0;i<PASSWORD_SIZE-1;i++)
1917 buf[2+i] = i<oldpwd.length()?oldpwd[i]:0;
1918 buf[30+i] = i<newpwd.length()?newpwd[i]:0;
1920 buf[2+PASSWORD_SIZE-1] = 0;
1921 buf[30+PASSWORD_SIZE-1] = 0;
1922 os.write((char*)buf, 2+PASSWORD_SIZE*2);
1925 std::string s = os.str();
1926 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
1928 Send(0, data, true);
1932 void Client::sendDamage(u8 damage)
1934 DSTACK(__FUNCTION_NAME);
1935 std::ostringstream os(std::ios_base::binary);
1937 writeU16(os, TOSERVER_DAMAGE);
1938 writeU8(os, damage);
1941 std::string s = os.str();
1942 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
1944 Send(0, data, true);
1947 void Client::sendRespawn()
1949 DSTACK(__FUNCTION_NAME);
1950 std::ostringstream os(std::ios_base::binary);
1952 writeU16(os, TOSERVER_RESPAWN);
1955 std::string s = os.str();
1956 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
1958 Send(0, data, true);
1961 void Client::sendPlayerPos()
1963 //JMutexAutoLock envlock(m_env_mutex); //bulk comment-out
1965 Player *myplayer = m_env.getLocalPlayer();
1966 if(myplayer == NULL)
1971 //JMutexAutoLock lock(m_con_mutex); //bulk comment-out
1972 our_peer_id = m_con.GetPeerID();
1975 // Set peer id if not set already
1976 if(myplayer->peer_id == PEER_ID_INEXISTENT)
1977 myplayer->peer_id = our_peer_id;
1978 // Check that an existing peer_id is the same as the connection's
1979 assert(myplayer->peer_id == our_peer_id);
1981 v3f pf = myplayer->getPosition();
1982 v3s32 position(pf.X*100, pf.Y*100, pf.Z*100);
1983 v3f sf = myplayer->getSpeed();
1984 v3s32 speed(sf.X*100, sf.Y*100, sf.Z*100);
1985 s32 pitch = myplayer->getPitch() * 100;
1986 s32 yaw = myplayer->getYaw() * 100;
1991 [2] v3s32 position*100
1992 [2+12] v3s32 speed*100
1993 [2+12+12] s32 pitch*100
1994 [2+12+12+4] s32 yaw*100
1997 SharedBuffer<u8> data(2+12+12+4+4);
1998 writeU16(&data[0], TOSERVER_PLAYERPOS);
1999 writeV3S32(&data[2], position);
2000 writeV3S32(&data[2+12], speed);
2001 writeS32(&data[2+12+12], pitch);
2002 writeS32(&data[2+12+12+4], yaw);
2004 // Send as unreliable
2005 Send(0, data, false);
2008 void Client::sendPlayerItem(u16 item)
2010 Player *myplayer = m_env.getLocalPlayer();
2011 if(myplayer == NULL)
2014 u16 our_peer_id = m_con.GetPeerID();
2016 // Set peer id if not set already
2017 if(myplayer->peer_id == PEER_ID_INEXISTENT)
2018 myplayer->peer_id = our_peer_id;
2019 // Check that an existing peer_id is the same as the connection's
2020 assert(myplayer->peer_id == our_peer_id);
2022 SharedBuffer<u8> data(2+2);
2023 writeU16(&data[0], TOSERVER_PLAYERITEM);
2024 writeU16(&data[2], item);
2027 Send(0, data, true);
2030 void Client::removeNode(v3s16 p)
2032 core::map<v3s16, MapBlock*> modified_blocks;
2036 //TimeTaker t("removeNodeAndUpdate", m_device);
2037 m_env.getMap().removeNodeAndUpdate(p, modified_blocks);
2039 catch(InvalidPositionException &e)
2043 // add urgent task to update the modified node
2044 addUpdateMeshTaskForNode(p, false, true);
2046 for(core::map<v3s16, MapBlock * >::Iterator
2047 i = modified_blocks.getIterator();
2048 i.atEnd() == false; i++)
2050 v3s16 p = i.getNode()->getKey();
2051 addUpdateMeshTaskWithEdge(p);
2055 void Client::addNode(v3s16 p, MapNode n)
2057 TimeTaker timer1("Client::addNode()");
2059 core::map<v3s16, MapBlock*> modified_blocks;
2063 //TimeTaker timer3("Client::addNode(): addNodeAndUpdate");
2064 m_env.getMap().addNodeAndUpdate(p, n, modified_blocks);
2066 catch(InvalidPositionException &e)
2069 for(core::map<v3s16, MapBlock * >::Iterator
2070 i = modified_blocks.getIterator();
2071 i.atEnd() == false; i++)
2073 v3s16 p = i.getNode()->getKey();
2074 addUpdateMeshTaskWithEdge(p);
2078 void Client::setPlayerControl(PlayerControl &control)
2080 //JMutexAutoLock envlock(m_env_mutex); //bulk comment-out
2081 LocalPlayer *player = m_env.getLocalPlayer();
2082 assert(player != NULL);
2083 player->control = control;
2086 void Client::selectPlayerItem(u16 item)
2088 //JMutexAutoLock envlock(m_env_mutex); //bulk comment-out
2089 m_playeritem = item;
2090 m_inventory_updated = true;
2091 sendPlayerItem(item);
2094 // Returns true if the inventory of the local player has been
2095 // updated from the server. If it is true, it is set to false.
2096 bool Client::getLocalInventoryUpdated()
2098 // m_inventory_updated is behind envlock
2099 //JMutexAutoLock envlock(m_env_mutex); //bulk comment-out
2100 bool updated = m_inventory_updated;
2101 m_inventory_updated = false;
2105 // Copies the inventory of the local player to parameter
2106 void Client::getLocalInventory(Inventory &dst)
2108 //JMutexAutoLock envlock(m_env_mutex); //bulk comment-out
2109 Player *player = m_env.getLocalPlayer();
2110 assert(player != NULL);
2111 dst = player->inventory;
2114 Inventory* Client::getInventory(const InventoryLocation &loc)
2117 case InventoryLocation::UNDEFINED:
2120 case InventoryLocation::CURRENT_PLAYER:
2122 Player *player = m_env.getLocalPlayer();
2123 assert(player != NULL);
2124 return &player->inventory;
2127 case InventoryLocation::PLAYER:
2129 Player *player = m_env.getPlayer(loc.name.c_str());
2132 return &player->inventory;
2135 case InventoryLocation::NODEMETA:
2137 NodeMetadata *meta = m_env.getMap().getNodeMetadata(loc.p);
2140 return meta->getInventory();
2143 case InventoryLocation::DETACHED:
2145 if(m_detached_inventories.count(loc.name) == 0)
2147 return m_detached_inventories[loc.name];
2155 void Client::inventoryAction(InventoryAction *a)
2158 Send it to the server
2160 sendInventoryAction(a);
2163 Predict some local inventory changes
2165 a->clientApply(this, this);
2168 ClientActiveObject * Client::getSelectedActiveObject(
2170 v3f from_pos_f_on_map,
2171 core::line3d<f32> shootline_on_map
2174 core::array<DistanceSortedActiveObject> objects;
2176 m_env.getActiveObjects(from_pos_f_on_map, max_d, objects);
2178 //infostream<<"Collected "<<objects.size()<<" nearby objects"<<std::endl;
2181 // After this, the closest object is the first in the array.
2184 for(u32 i=0; i<objects.size(); i++)
2186 ClientActiveObject *obj = objects[i].obj;
2188 core::aabbox3d<f32> *selection_box = obj->getSelectionBox();
2189 if(selection_box == NULL)
2192 v3f pos = obj->getPosition();
2194 core::aabbox3d<f32> offsetted_box(
2195 selection_box->MinEdge + pos,
2196 selection_box->MaxEdge + pos
2199 if(offsetted_box.intersectsWithLine(shootline_on_map))
2201 //infostream<<"Returning selected object"<<std::endl;
2206 //infostream<<"No object selected; returning NULL."<<std::endl;
2210 void Client::printDebugInfo(std::ostream &os)
2212 //JMutexAutoLock lock1(m_fetchblock_mutex);
2213 /*JMutexAutoLock lock2(m_incoming_queue_mutex);
2215 os<<"m_incoming_queue.getSize()="<<m_incoming_queue.getSize()
2216 //<<", m_fetchblock_history.size()="<<m_fetchblock_history.size()
2217 //<<", m_opt_not_found_history.size()="<<m_opt_not_found_history.size()
2221 core::list<std::wstring> Client::getConnectedPlayerNames()
2223 core::list<Player*> players = m_env.getPlayers(true);
2224 core::list<std::wstring> playerNames;
2225 for(core::list<Player*>::Iterator
2226 i = players.begin();
2227 i != players.end(); i++)
2229 Player *player = *i;
2230 playerNames.push_back(narrow_to_wide(player->getName()));
2235 float Client::getAnimationTime()
2237 return m_animation_time;
2240 int Client::getCrackLevel()
2242 return m_crack_level;
2245 void Client::setCrack(int level, v3s16 pos)
2247 int old_crack_level = m_crack_level;
2248 v3s16 old_crack_pos = m_crack_pos;
2250 m_crack_level = level;
2253 if(old_crack_level >= 0 && (level < 0 || pos != old_crack_pos))
2256 addUpdateMeshTaskForNode(old_crack_pos, false, true);
2258 if(level >= 0 && (old_crack_level < 0 || pos != old_crack_pos))
2261 addUpdateMeshTaskForNode(pos, false, true);
2267 Player *player = m_env.getLocalPlayer();
2268 assert(player != NULL);
2272 bool Client::getChatMessage(std::wstring &message)
2274 if(m_chat_queue.size() == 0)
2276 message = m_chat_queue.pop_front();
2280 void Client::typeChatMessage(const std::wstring &message)
2282 // Discard empty line
2287 sendChatMessage(message);
2290 if (message[0] == L'/')
2292 m_chat_queue.push_back(
2293 (std::wstring)L"issued command: "+message);
2297 LocalPlayer *player = m_env.getLocalPlayer();
2298 assert(player != NULL);
2299 std::wstring name = narrow_to_wide(player->getName());
2300 m_chat_queue.push_back(
2301 (std::wstring)L"<"+name+L"> "+message);
2305 void Client::addUpdateMeshTask(v3s16 p, bool ack_to_server, bool urgent)
2307 /*infostream<<"Client::addUpdateMeshTask(): "
2308 <<"("<<p.X<<","<<p.Y<<","<<p.Z<<")"
2309 <<" ack_to_server="<<ack_to_server
2310 <<" urgent="<<urgent
2313 MapBlock *b = m_env.getMap().getBlockNoCreateNoEx(p);
2318 Create a task to update the mesh of the block
2321 MeshMakeData *data = new MeshMakeData(this);
2324 //TimeTaker timer("data fill");
2326 // Debug: 1-6ms, avg=2ms
2328 data->setCrack(m_crack_level, m_crack_pos);
2329 data->setSmoothLighting(g_settings->getBool("smooth_lighting"));
2333 //while(m_mesh_update_thread.m_queue_in.size() > 0) sleep_ms(10);
2335 // Add task to queue
2336 m_mesh_update_thread.m_queue_in.addBlock(p, data, ack_to_server, urgent);
2338 /*infostream<<"Mesh update input queue size is "
2339 <<m_mesh_update_thread.m_queue_in.size()
2343 void Client::addUpdateMeshTaskWithEdge(v3s16 blockpos, bool ack_to_server, bool urgent)
2347 infostream<<"Client::addUpdateMeshTaskWithEdge(): "
2348 <<"("<<p.X<<","<<p.Y<<","<<p.Z<<")"
2353 v3s16 p = blockpos + v3s16(0,0,0);
2354 //MapBlock *b = m_env.getMap().getBlockNoCreate(p);
2355 addUpdateMeshTask(p, ack_to_server, urgent);
2357 catch(InvalidPositionException &e){}
2360 v3s16 p = blockpos + v3s16(-1,0,0);
2361 addUpdateMeshTask(p, false, urgent);
2363 catch(InvalidPositionException &e){}
2365 v3s16 p = blockpos + v3s16(0,-1,0);
2366 addUpdateMeshTask(p, false, urgent);
2368 catch(InvalidPositionException &e){}
2370 v3s16 p = blockpos + v3s16(0,0,-1);
2371 addUpdateMeshTask(p, false, urgent);
2373 catch(InvalidPositionException &e){}
2376 void Client::addUpdateMeshTaskForNode(v3s16 nodepos, bool ack_to_server, bool urgent)
2380 infostream<<"Client::addUpdateMeshTaskForNode(): "
2381 <<"("<<p.X<<","<<p.Y<<","<<p.Z<<")"
2385 v3s16 blockpos = getNodeBlockPos(nodepos);
2386 v3s16 blockpos_relative = blockpos * MAP_BLOCKSIZE;
2389 v3s16 p = blockpos + v3s16(0,0,0);
2390 addUpdateMeshTask(p, ack_to_server, urgent);
2392 catch(InvalidPositionException &e){}
2394 if(nodepos.X == blockpos_relative.X){
2396 v3s16 p = blockpos + v3s16(-1,0,0);
2397 addUpdateMeshTask(p, false, urgent);
2399 catch(InvalidPositionException &e){}
2401 if(nodepos.Y == blockpos_relative.Y){
2403 v3s16 p = blockpos + v3s16(0,-1,0);
2404 addUpdateMeshTask(p, false, urgent);
2406 catch(InvalidPositionException &e){}
2408 if(nodepos.Z == blockpos_relative.Z){
2410 v3s16 p = blockpos + v3s16(0,0,-1);
2411 addUpdateMeshTask(p, false, urgent);
2413 catch(InvalidPositionException &e){}
2417 ClientEvent Client::getClientEvent()
2419 if(m_client_event_queue.size() == 0)
2422 event.type = CE_NONE;
2425 return m_client_event_queue.pop_front();
2428 void Client::afterContentReceived()
2430 verbosestream<<"Client::afterContentReceived() started"<<std::endl;
2431 assert(m_itemdef_received);
2432 assert(m_nodedef_received);
2433 assert(m_media_received);
2435 // remove the information about which checksum each texture
2437 m_media_name_sha1_map.clear();
2439 // Rebuild inherited images and recreate textures
2440 verbosestream<<"Rebuilding images and textures"<<std::endl;
2441 m_tsrc->rebuildImagesAndTextures();
2443 // Update texture atlas
2444 verbosestream<<"Updating texture atlas"<<std::endl;
2445 if(g_settings->getBool("enable_texture_atlas"))
2446 m_tsrc->buildMainAtlas(this);
2448 // Update node aliases
2449 verbosestream<<"Updating node aliases"<<std::endl;
2450 m_nodedef->updateAliases(m_itemdef);
2452 // Update node textures
2453 verbosestream<<"Updating node textures"<<std::endl;
2454 m_nodedef->updateTextures(m_tsrc);
2456 // Update item textures and meshes
2457 verbosestream<<"Updating item textures and meshes"<<std::endl;
2458 m_itemdef->updateTexturesAndMeshes(this);
2460 // Start mesh update thread after setting up content definitions
2461 verbosestream<<"Starting mesh update thread"<<std::endl;
2462 m_mesh_update_thread.Start();
2464 verbosestream<<"Client::afterContentReceived() done"<<std::endl;
2467 float Client::getRTT(void)
2470 return m_con.GetPeerAvgRTT(PEER_ID_SERVER);
2471 } catch(con::PeerNotFoundException &e){
2476 // IGameDef interface
2478 IItemDefManager* Client::getItemDefManager()
2482 INodeDefManager* Client::getNodeDefManager()
2486 ICraftDefManager* Client::getCraftDefManager()
2489 //return m_craftdef;
2491 ITextureSource* Client::getTextureSource()
2495 u16 Client::allocateUnknownNodeId(const std::string &name)
2497 errorstream<<"Client::allocateUnknownNodeId(): "
2498 <<"Client cannot allocate node IDs"<<std::endl;
2500 return CONTENT_IGNORE;
2502 ISoundManager* Client::getSoundManager()
2506 MtEventManager* Client::getEventManager()