]> git.lizzy.rs Git - minetest.git/blob - src/client.cpp
Remove an unused function and include from client.cpp
[minetest.git] / src / client.cpp
1 /*
2 Minetest
3 Copyright (C) 2013 celeron55, Perttu Ahola <celeron55@gmail.com>
4
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.
9
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.
14
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.
18 */
19
20 #include "client.h"
21 #include <iostream>
22 #include <algorithm>
23 #include "clientserver.h"
24 #include "jthread/jmutexautolock.h"
25 #include "main.h"
26 #include <sstream>
27 #include "filesys.h"
28 #include "porting.h"
29 #include "mapsector.h"
30 #include "mapblock_mesh.h"
31 #include "mapblock.h"
32 #include "settings.h"
33 #include "profiler.h"
34 #include "gettext.h"
35 #include "log.h"
36 #include "nodemetadata.h"
37 #include "nodedef.h"
38 #include "itemdef.h"
39 #include "shader.h"
40 #include <IFileSystem.h>
41 #include "base64.h"
42 #include "clientmap.h"
43 #include "clientmedia.h"
44 #include "sound.h"
45 #include "util/string.h"
46 #include "IMeshCache.h"
47 #include "serialization.h"
48 #include "util/serialize.h"
49 #include "config.h"
50 #include "util/directiontables.h"
51 #include "util/pointedthing.h"
52 #include "version.h"
53
54 /*
55         QueuedMeshUpdate
56 */
57
58 QueuedMeshUpdate::QueuedMeshUpdate():
59         p(-1337,-1337,-1337),
60         data(NULL),
61         ack_block_to_server(false)
62 {
63 }
64
65 QueuedMeshUpdate::~QueuedMeshUpdate()
66 {
67         if(data)
68                 delete data;
69 }
70
71 /*
72         MeshUpdateQueue
73 */
74         
75 MeshUpdateQueue::MeshUpdateQueue()
76 {
77 }
78
79 MeshUpdateQueue::~MeshUpdateQueue()
80 {
81         JMutexAutoLock lock(m_mutex);
82
83         for(std::vector<QueuedMeshUpdate*>::iterator
84                         i = m_queue.begin();
85                         i != m_queue.end(); i++)
86         {
87                 QueuedMeshUpdate *q = *i;
88                 delete q;
89         }
90 }
91
92 /*
93         peer_id=0 adds with nobody to send to
94 */
95 void MeshUpdateQueue::addBlock(v3s16 p, MeshMakeData *data, bool ack_block_to_server, bool urgent)
96 {
97         DSTACK(__FUNCTION_NAME);
98
99         assert(data);
100
101         JMutexAutoLock lock(m_mutex);
102
103         if(urgent)
104                 m_urgents.insert(p);
105
106         /*
107                 Find if block is already in queue.
108                 If it is, update the data and quit.
109         */
110         for(std::vector<QueuedMeshUpdate*>::iterator
111                         i = m_queue.begin();
112                         i != m_queue.end(); i++)
113         {
114                 QueuedMeshUpdate *q = *i;
115                 if(q->p == p)
116                 {
117                         if(q->data)
118                                 delete q->data;
119                         q->data = data;
120                         if(ack_block_to_server)
121                                 q->ack_block_to_server = true;
122                         return;
123                 }
124         }
125         
126         /*
127                 Add the block
128         */
129         QueuedMeshUpdate *q = new QueuedMeshUpdate;
130         q->p = p;
131         q->data = data;
132         q->ack_block_to_server = ack_block_to_server;
133         m_queue.push_back(q);
134 }
135
136 // Returned pointer must be deleted
137 // Returns NULL if queue is empty
138 QueuedMeshUpdate * MeshUpdateQueue::pop()
139 {
140         JMutexAutoLock lock(m_mutex);
141
142         bool must_be_urgent = !m_urgents.empty();
143         for(std::vector<QueuedMeshUpdate*>::iterator
144                         i = m_queue.begin();
145                         i != m_queue.end(); i++)
146         {
147                 QueuedMeshUpdate *q = *i;
148                 if(must_be_urgent && m_urgents.count(q->p) == 0)
149                         continue;
150                 m_queue.erase(i);
151                 m_urgents.erase(q->p);
152                 return q;
153         }
154         return NULL;
155 }
156
157 /*
158         MeshUpdateThread
159 */
160
161 void * MeshUpdateThread::Thread()
162 {
163         ThreadStarted();
164
165         log_register_thread("MeshUpdateThread");
166
167         DSTACK(__FUNCTION_NAME);
168         
169         BEGIN_DEBUG_EXCEPTION_HANDLER
170
171         while(!StopRequested())
172         {
173                 /*// Wait for output queue to flush.
174                 // Allow 2 in queue, this makes less frametime jitter.
175                 // Umm actually, there is no much difference
176                 if(m_queue_out.size() >= 2)
177                 {
178                         sleep_ms(3);
179                         continue;
180                 }*/
181
182                 QueuedMeshUpdate *q = m_queue_in.pop();
183                 if(q == NULL)
184                 {
185                         sleep_ms(3);
186                         continue;
187                 }
188
189                 ScopeProfiler sp(g_profiler, "Client: Mesh making");
190
191                 MapBlockMesh *mesh_new = new MapBlockMesh(q->data);
192                 if(mesh_new->getMesh()->getMeshBufferCount() == 0)
193                 {
194                         delete mesh_new;
195                         mesh_new = NULL;
196                 }
197
198                 MeshUpdateResult r;
199                 r.p = q->p;
200                 r.mesh = mesh_new;
201                 r.ack_block_to_server = q->ack_block_to_server;
202
203                 /*infostream<<"MeshUpdateThread: Processed "
204                                 <<"("<<q->p.X<<","<<q->p.Y<<","<<q->p.Z<<")"
205                                 <<std::endl;*/
206
207                 m_queue_out.push_back(r);
208
209                 delete q;
210         }
211
212         END_DEBUG_EXCEPTION_HANDLER(errorstream)
213
214         return NULL;
215 }
216
217 /*
218         Client
219 */
220
221 Client::Client(
222                 IrrlichtDevice *device,
223                 const char *playername,
224                 std::string password,
225                 MapDrawControl &control,
226                 IWritableTextureSource *tsrc,
227                 IWritableShaderSource *shsrc,
228                 IWritableItemDefManager *itemdef,
229                 IWritableNodeDefManager *nodedef,
230                 ISoundManager *sound,
231                 MtEventManager *event,
232                 bool ipv6
233 ):
234         m_tsrc(tsrc),
235         m_shsrc(shsrc),
236         m_itemdef(itemdef),
237         m_nodedef(nodedef),
238         m_sound(sound),
239         m_event(event),
240         m_mesh_update_thread(this),
241         m_env(
242                 new ClientMap(this, this, control,
243                         device->getSceneManager()->getRootSceneNode(),
244                         device->getSceneManager(), 666),
245                 device->getSceneManager(),
246                 tsrc, this, device
247         ),
248         m_con(PROTOCOL_ID, 512, CONNECTION_TIMEOUT, ipv6, this),
249         m_device(device),
250         m_server_ser_ver(SER_FMT_VER_INVALID),
251         m_playeritem(0),
252         m_inventory_updated(false),
253         m_inventory_from_server(NULL),
254         m_inventory_from_server_age(0.0),
255         m_animation_time(0),
256         m_crack_level(-1),
257         m_crack_pos(0,0,0),
258         m_map_seed(0),
259         m_password(password),
260         m_access_denied(false),
261         m_itemdef_received(false),
262         m_nodedef_received(false),
263         m_media_downloader(new ClientMediaDownloader()),
264         m_time_of_day_set(false),
265         m_last_time_of_day_f(-1),
266         m_time_of_day_update_timer(0),
267         m_recommended_send_interval(0.1),
268         m_removed_sounds_check_timer(0)
269 {
270         m_packetcounter_timer = 0.0;
271         //m_delete_unused_sectors_timer = 0.0;
272         m_connection_reinit_timer = 0.0;
273         m_avg_rtt_timer = 0.0;
274         m_playerpos_send_timer = 0.0;
275         m_ignore_damage_timer = 0.0;
276
277         /*
278                 Add local player
279         */
280         {
281                 Player *player = new LocalPlayer(this);
282
283                 player->updateName(playername);
284
285                 m_env.addPlayer(player);
286         }
287 }
288
289 Client::~Client()
290 {
291         {
292                 //JMutexAutoLock conlock(m_con_mutex); //bulk comment-out
293                 m_con.Disconnect();
294         }
295
296         m_mesh_update_thread.Stop();
297         m_mesh_update_thread.Wait();
298         while(!m_mesh_update_thread.m_queue_out.empty()) {
299                 MeshUpdateResult r = m_mesh_update_thread.m_queue_out.pop_front();
300                 delete r.mesh;
301         }
302
303
304         delete m_inventory_from_server;
305
306         // Delete detached inventories
307         {
308                 for(std::map<std::string, Inventory*>::iterator
309                                 i = m_detached_inventories.begin();
310                                 i != m_detached_inventories.end(); i++){
311                         delete i->second;
312                 }
313         }
314
315         // cleanup 3d model meshes on client shutdown
316         while (m_device->getSceneManager()->getMeshCache()->getMeshCount() != 0) {
317                 scene::IAnimatedMesh * mesh =
318                         m_device->getSceneManager()->getMeshCache()->getMeshByIndex(0);
319
320                 if (mesh != NULL)
321                         m_device->getSceneManager()->getMeshCache()->removeMesh(mesh);
322         }
323 }
324
325 void Client::connect(Address address)
326 {
327         DSTACK(__FUNCTION_NAME);
328         //JMutexAutoLock lock(m_con_mutex); //bulk comment-out
329         m_con.SetTimeoutMs(0);
330         m_con.Connect(address);
331 }
332
333 bool Client::connectedAndInitialized()
334 {
335         //JMutexAutoLock lock(m_con_mutex); //bulk comment-out
336
337         if(m_con.Connected() == false)
338                 return false;
339         
340         if(m_server_ser_ver == SER_FMT_VER_INVALID)
341                 return false;
342         
343         return true;
344 }
345
346 void Client::step(float dtime)
347 {
348         DSTACK(__FUNCTION_NAME);
349         
350         // Limit a bit
351         if(dtime > 2.0)
352                 dtime = 2.0;
353         
354         if(m_ignore_damage_timer > dtime)
355                 m_ignore_damage_timer -= dtime;
356         else
357                 m_ignore_damage_timer = 0.0;
358         
359         m_animation_time += dtime;
360         if(m_animation_time > 60.0)
361                 m_animation_time -= 60.0;
362
363         m_time_of_day_update_timer += dtime;
364         
365         //infostream<<"Client steps "<<dtime<<std::endl;
366
367         {
368                 //TimeTaker timer("ReceiveAll()", m_device);
369                 // 0ms
370                 ReceiveAll();
371         }
372         
373         {
374                 //TimeTaker timer("m_con_mutex + m_con.RunTimeouts()", m_device);
375                 // 0ms
376                 //JMutexAutoLock lock(m_con_mutex); //bulk comment-out
377                 m_con.RunTimeouts(dtime);
378         }
379
380         /*
381                 Packet counter
382         */
383         {
384                 float &counter = m_packetcounter_timer;
385                 counter -= dtime;
386                 if(counter <= 0.0)
387                 {
388                         counter = 20.0;
389                         
390                         infostream<<"Client packetcounter (20s):"<<std::endl;
391                         m_packetcounter.print(infostream);
392                         m_packetcounter.clear();
393                 }
394         }
395         
396         // Get connection status
397         bool connected = connectedAndInitialized();
398
399 #if 0
400         {
401                 /*
402                         Delete unused sectors
403
404                         NOTE: This jams the game for a while because deleting sectors
405                               clear caches
406                 */
407                 
408                 float &counter = m_delete_unused_sectors_timer;
409                 counter -= dtime;
410                 if(counter <= 0.0)
411                 {
412                         // 3 minute interval
413                         //counter = 180.0;
414                         counter = 60.0;
415
416                         //JMutexAutoLock lock(m_env_mutex); //bulk comment-out
417
418                         core::list<v3s16> deleted_blocks;
419
420                         float delete_unused_sectors_timeout =
421                                 g_settings->getFloat("client_delete_unused_sectors_timeout");
422         
423                         // Delete sector blocks
424                         /*u32 num = m_env.getMap().unloadUnusedData
425                                         (delete_unused_sectors_timeout,
426                                         true, &deleted_blocks);*/
427                         
428                         // Delete whole sectors
429                         m_env.getMap().unloadUnusedData
430                                         (delete_unused_sectors_timeout,
431                                         &deleted_blocks);
432
433                         if(deleted_blocks.size() > 0)
434                         {
435                                 /*infostream<<"Client: Deleted blocks of "<<num
436                                                 <<" unused sectors"<<std::endl;*/
437                                 /*infostream<<"Client: Deleted "<<num
438                                                 <<" unused sectors"<<std::endl;*/
439                                 
440                                 /*
441                                         Send info to server
442                                 */
443
444                                 // Env is locked so con can be locked.
445                                 //JMutexAutoLock lock(m_con_mutex); //bulk comment-out
446                                 
447                                 core::list<v3s16>::Iterator i = deleted_blocks.begin();
448                                 core::list<v3s16> sendlist;
449                                 for(;;)
450                                 {
451                                         if(sendlist.size() == 255 || i == deleted_blocks.end())
452                                         {
453                                                 if(sendlist.size() == 0)
454                                                         break;
455                                                 /*
456                                                         [0] u16 command
457                                                         [2] u8 count
458                                                         [3] v3s16 pos_0
459                                                         [3+6] v3s16 pos_1
460                                                         ...
461                                                 */
462                                                 u32 replysize = 2+1+6*sendlist.size();
463                                                 SharedBuffer<u8> reply(replysize);
464                                                 writeU16(&reply[0], TOSERVER_DELETEDBLOCKS);
465                                                 reply[2] = sendlist.size();
466                                                 u32 k = 0;
467                                                 for(core::list<v3s16>::Iterator
468                                                                 j = sendlist.begin();
469                                                                 j != sendlist.end(); j++)
470                                                 {
471                                                         writeV3S16(&reply[2+1+6*k], *j);
472                                                         k++;
473                                                 }
474                                                 m_con.Send(PEER_ID_SERVER, 1, reply, true);
475
476                                                 if(i == deleted_blocks.end())
477                                                         break;
478
479                                                 sendlist.clear();
480                                         }
481
482                                         sendlist.push_back(*i);
483                                         i++;
484                                 }
485                         }
486                 }
487         }
488 #endif
489
490         if(connected == false)
491         {
492                 float &counter = m_connection_reinit_timer;
493                 counter -= dtime;
494                 if(counter <= 0.0)
495                 {
496                         counter = 2.0;
497
498                         //JMutexAutoLock envlock(m_env_mutex); //bulk comment-out
499                         
500                         Player *myplayer = m_env.getLocalPlayer();
501                         assert(myplayer != NULL);
502         
503                         // Send TOSERVER_INIT
504                         // [0] u16 TOSERVER_INIT
505                         // [2] u8 SER_FMT_VER_HIGHEST_READ
506                         // [3] u8[20] player_name
507                         // [23] u8[28] password (new in some version)
508                         // [51] u16 minimum supported network protocol version (added sometime)
509                         // [53] u16 maximum supported network protocol version (added later than the previous one)
510                         SharedBuffer<u8> data(2+1+PLAYERNAME_SIZE+PASSWORD_SIZE+2+2);
511                         writeU16(&data[0], TOSERVER_INIT);
512                         writeU8(&data[2], SER_FMT_VER_HIGHEST_READ);
513
514                         memset((char*)&data[3], 0, PLAYERNAME_SIZE);
515                         snprintf((char*)&data[3], PLAYERNAME_SIZE, "%s", myplayer->getName());
516
517                         /*infostream<<"Client: sending initial password hash: \""<<m_password<<"\""
518                                         <<std::endl;*/
519
520                         memset((char*)&data[23], 0, PASSWORD_SIZE);
521                         snprintf((char*)&data[23], PASSWORD_SIZE, "%s", m_password.c_str());
522                         
523                         writeU16(&data[51], CLIENT_PROTOCOL_VERSION_MIN);
524                         writeU16(&data[53], CLIENT_PROTOCOL_VERSION_MAX);
525
526                         // Send as unreliable
527                         Send(0, data, false);
528                 }
529
530                 // Not connected, return
531                 return;
532         }
533
534         /*
535                 Do stuff if connected
536         */
537         
538         /*
539                 Run Map's timers and unload unused data
540         */
541         const float map_timer_and_unload_dtime = 5.25;
542         if(m_map_timer_and_unload_interval.step(dtime, map_timer_and_unload_dtime))
543         {
544                 ScopeProfiler sp(g_profiler, "Client: map timer and unload");
545                 std::list<v3s16> deleted_blocks;
546                 m_env.getMap().timerUpdate(map_timer_and_unload_dtime,
547                                 g_settings->getFloat("client_unload_unused_data_timeout"),
548                                 &deleted_blocks);
549                                 
550                 /*if(deleted_blocks.size() > 0)
551                         infostream<<"Client: Unloaded "<<deleted_blocks.size()
552                                         <<" unused blocks"<<std::endl;*/
553                         
554                 /*
555                         Send info to server
556                         NOTE: This loop is intentionally iterated the way it is.
557                 */
558
559                 std::list<v3s16>::iterator i = deleted_blocks.begin();
560                 std::list<v3s16> sendlist;
561                 for(;;)
562                 {
563                         if(sendlist.size() == 255 || i == deleted_blocks.end())
564                         {
565                                 if(sendlist.size() == 0)
566                                         break;
567                                 /*
568                                         [0] u16 command
569                                         [2] u8 count
570                                         [3] v3s16 pos_0
571                                         [3+6] v3s16 pos_1
572                                         ...
573                                 */
574                                 u32 replysize = 2+1+6*sendlist.size();
575                                 SharedBuffer<u8> reply(replysize);
576                                 writeU16(&reply[0], TOSERVER_DELETEDBLOCKS);
577                                 reply[2] = sendlist.size();
578                                 u32 k = 0;
579                                 for(std::list<v3s16>::iterator
580                                                 j = sendlist.begin();
581                                                 j != sendlist.end(); ++j)
582                                 {
583                                         writeV3S16(&reply[2+1+6*k], *j);
584                                         k++;
585                                 }
586                                 m_con.Send(PEER_ID_SERVER, 1, reply, true);
587
588                                 if(i == deleted_blocks.end())
589                                         break;
590
591                                 sendlist.clear();
592                         }
593
594                         sendlist.push_back(*i);
595                         ++i;
596                 }
597         }
598
599         /*
600                 Handle environment
601         */
602         {
603                 // 0ms
604                 //JMutexAutoLock lock(m_env_mutex); //bulk comment-out
605
606                 // Control local player (0ms)
607                 LocalPlayer *player = m_env.getLocalPlayer();
608                 assert(player != NULL);
609                 player->applyControl(dtime);
610
611                 //TimeTaker envtimer("env step", m_device);
612                 // Step environment
613                 m_env.step(dtime);
614                 
615                 /*
616                         Get events
617                 */
618                 for(;;)
619                 {
620                         ClientEnvEvent event = m_env.getClientEvent();
621                         if(event.type == CEE_NONE)
622                         {
623                                 break;
624                         }
625                         else if(event.type == CEE_PLAYER_DAMAGE)
626                         {
627                                 if(m_ignore_damage_timer <= 0)
628                                 {
629                                         u8 damage = event.player_damage.amount;
630                                         
631                                         if(event.player_damage.send_to_server)
632                                                 sendDamage(damage);
633
634                                         // Add to ClientEvent queue
635                                         ClientEvent event;
636                                         event.type = CE_PLAYER_DAMAGE;
637                                         event.player_damage.amount = damage;
638                                         m_client_event_queue.push_back(event);
639                                 }
640                         }
641                         else if(event.type == CEE_PLAYER_BREATH)
642                         {
643                                         u16 breath = event.player_breath.amount;
644                                         sendBreath(breath);
645                         }
646                 }
647         }
648
649         /*
650                 Print some info
651         */
652         {
653                 float &counter = m_avg_rtt_timer;
654                 counter += dtime;
655                 if(counter >= 10)
656                 {
657                         counter = 0.0;
658                         //JMutexAutoLock lock(m_con_mutex); //bulk comment-out
659                         // connectedAndInitialized() is true, peer exists.
660                         float avg_rtt = m_con.GetPeerAvgRTT(PEER_ID_SERVER);
661                         infostream<<"Client: avg_rtt="<<avg_rtt<<std::endl;
662                 }
663         }
664
665         /*
666                 Send player position to server
667         */
668         {
669                 float &counter = m_playerpos_send_timer;
670                 counter += dtime;
671                 if(counter >= m_recommended_send_interval)
672                 {
673                         counter = 0.0;
674                         sendPlayerPos();
675                 }
676         }
677
678         /*
679                 Replace updated meshes
680         */
681         {
682                 //JMutexAutoLock lock(m_env_mutex); //bulk comment-out
683
684                 //TimeTaker timer("** Processing mesh update result queue");
685                 // 0ms
686                 
687                 /*infostream<<"Mesh update result queue size is "
688                                 <<m_mesh_update_thread.m_queue_out.size()
689                                 <<std::endl;*/
690                 
691                 int num_processed_meshes = 0;
692                 while(!m_mesh_update_thread.m_queue_out.empty())
693                 {
694                         num_processed_meshes++;
695                         MeshUpdateResult r = m_mesh_update_thread.m_queue_out.pop_front();
696                         MapBlock *block = m_env.getMap().getBlockNoCreateNoEx(r.p);
697                         if(block)
698                         {
699                                 //JMutexAutoLock lock(block->mesh_mutex);
700
701                                 // Delete the old mesh
702                                 if(block->mesh != NULL)
703                                 {
704                                         // TODO: Remove hardware buffers of meshbuffers of block->mesh
705                                         delete block->mesh;
706                                         block->mesh = NULL;
707                                 }
708
709                                 // Replace with the new mesh
710                                 block->mesh = r.mesh;
711                         } else {
712                                 delete r.mesh;
713                         }
714                         if(r.ack_block_to_server)
715                         {
716                                 /*infostream<<"Client: ACK block ("<<r.p.X<<","<<r.p.Y
717                                                 <<","<<r.p.Z<<")"<<std::endl;*/
718                                 /*
719                                         Acknowledge block
720                                 */
721                                 /*
722                                         [0] u16 command
723                                         [2] u8 count
724                                         [3] v3s16 pos_0
725                                         [3+6] v3s16 pos_1
726                                         ...
727                                 */
728                                 u32 replysize = 2+1+6;
729                                 SharedBuffer<u8> reply(replysize);
730                                 writeU16(&reply[0], TOSERVER_GOTBLOCKS);
731                                 reply[2] = 1;
732                                 writeV3S16(&reply[3], r.p);
733                                 // Send as reliable
734                                 m_con.Send(PEER_ID_SERVER, 1, reply, true);
735                         }
736                 }
737                 if(num_processed_meshes > 0)
738                         g_profiler->graphAdd("num_processed_meshes", num_processed_meshes);
739         }
740
741         /*
742                 Load fetched media
743         */
744         if (m_media_downloader && m_media_downloader->isStarted()) {
745                 m_media_downloader->step(this);
746                 if (m_media_downloader->isDone()) {
747                         delete m_media_downloader;
748                         m_media_downloader = NULL;
749                 }
750         }
751
752         /*
753                 If the server didn't update the inventory in a while, revert
754                 the local inventory (so the player notices the lag problem
755                 and knows something is wrong).
756         */
757         if(m_inventory_from_server)
758         {
759                 float interval = 10.0;
760                 float count_before = floor(m_inventory_from_server_age / interval);
761
762                 m_inventory_from_server_age += dtime;
763
764                 float count_after = floor(m_inventory_from_server_age / interval);
765
766                 if(count_after != count_before)
767                 {
768                         // Do this every <interval> seconds after TOCLIENT_INVENTORY
769                         // Reset the locally changed inventory to the authoritative inventory
770                         Player *player = m_env.getLocalPlayer();
771                         player->inventory = *m_inventory_from_server;
772                         m_inventory_updated = true;
773                 }
774         }
775
776         /*
777                 Update positions of sounds attached to objects
778         */
779         {
780                 for(std::map<int, u16>::iterator
781                                 i = m_sounds_to_objects.begin();
782                                 i != m_sounds_to_objects.end(); i++)
783                 {
784                         int client_id = i->first;
785                         u16 object_id = i->second;
786                         ClientActiveObject *cao = m_env.getActiveObject(object_id);
787                         if(!cao)
788                                 continue;
789                         v3f pos = cao->getPosition();
790                         m_sound->updateSoundPosition(client_id, pos);
791                 }
792         }
793         
794         /*
795                 Handle removed remotely initiated sounds
796         */
797         m_removed_sounds_check_timer += dtime;
798         if(m_removed_sounds_check_timer >= 2.32)
799         {
800                 m_removed_sounds_check_timer = 0;
801                 // Find removed sounds and clear references to them
802                 std::set<s32> removed_server_ids;
803                 for(std::map<s32, int>::iterator
804                                 i = m_sounds_server_to_client.begin();
805                                 i != m_sounds_server_to_client.end();)
806                 {
807                         s32 server_id = i->first;
808                         int client_id = i->second;
809                         i++;
810                         if(!m_sound->soundExists(client_id)){
811                                 m_sounds_server_to_client.erase(server_id);
812                                 m_sounds_client_to_server.erase(client_id);
813                                 m_sounds_to_objects.erase(client_id);
814                                 removed_server_ids.insert(server_id);
815                         }
816                 }
817                 // Sync to server
818                 if(removed_server_ids.size() != 0)
819                 {
820                         std::ostringstream os(std::ios_base::binary);
821                         writeU16(os, TOSERVER_REMOVED_SOUNDS);
822                         writeU16(os, removed_server_ids.size());
823                         for(std::set<s32>::iterator i = removed_server_ids.begin();
824                                         i != removed_server_ids.end(); i++)
825                                 writeS32(os, *i);
826                         std::string s = os.str();
827                         SharedBuffer<u8> data((u8*)s.c_str(), s.size());
828                         // Send as reliable
829                         Send(0, data, true);
830                 }
831         }
832 }
833
834 bool Client::loadMedia(const std::string &data, const std::string &filename)
835 {
836         // Silly irrlicht's const-incorrectness
837         Buffer<char> data_rw(data.c_str(), data.size());
838         
839         std::string name;
840
841         const char *image_ext[] = {
842                 ".png", ".jpg", ".bmp", ".tga",
843                 ".pcx", ".ppm", ".psd", ".wal", ".rgb",
844                 NULL
845         };
846         name = removeStringEnd(filename, image_ext);
847         if(name != "")
848         {
849                 verbosestream<<"Client: Attempting to load image "
850                 <<"file \""<<filename<<"\""<<std::endl;
851
852                 io::IFileSystem *irrfs = m_device->getFileSystem();
853                 video::IVideoDriver *vdrv = m_device->getVideoDriver();
854
855                 // Create an irrlicht memory file
856                 io::IReadFile *rfile = irrfs->createMemoryReadFile(
857                                 *data_rw, data_rw.getSize(), "_tempreadfile");
858                 assert(rfile);
859                 // Read image
860                 video::IImage *img = vdrv->createImageFromFile(rfile);
861                 if(!img){
862                         errorstream<<"Client: Cannot create image from data of "
863                                         <<"file \""<<filename<<"\""<<std::endl;
864                         rfile->drop();
865                         return false;
866                 }
867                 else {
868                         m_tsrc->insertSourceImage(filename, img);
869                         img->drop();
870                         rfile->drop();
871                         return true;
872                 }
873         }
874
875         const char *sound_ext[] = {
876                 ".0.ogg", ".1.ogg", ".2.ogg", ".3.ogg", ".4.ogg",
877                 ".5.ogg", ".6.ogg", ".7.ogg", ".8.ogg", ".9.ogg",
878                 ".ogg", NULL
879         };
880         name = removeStringEnd(filename, sound_ext);
881         if(name != "")
882         {
883                 verbosestream<<"Client: Attempting to load sound "
884                 <<"file \""<<filename<<"\""<<std::endl;
885                 m_sound->loadSoundData(name, data);
886                 return true;
887         }
888
889         const char *model_ext[] = {
890                 ".x", ".b3d", ".md2", ".obj",
891                 NULL
892         };
893         name = removeStringEnd(filename, model_ext);
894         if(name != "")
895         {
896                 verbosestream<<"Client: Storing model into Irrlicht: "
897                                 <<"\""<<filename<<"\""<<std::endl;
898                 scene::ISceneManager *smgr = m_device->getSceneManager();
899
900                 //check if mesh was already cached
901                 scene::IAnimatedMesh *mesh =
902                         smgr->getMeshCache()->getMeshByName(filename.c_str());
903
904                 if (mesh != NULL) {
905                         errorstream << "Multiple models with name: " << filename.c_str() <<
906                                         " found replacing previous model!" << std::endl;
907
908                         smgr->getMeshCache()->removeMesh(mesh);
909                         mesh = 0;
910                 }
911
912                 io::IFileSystem *irrfs = m_device->getFileSystem();
913                 io::IReadFile *rfile = irrfs->createMemoryReadFile(
914                                 *data_rw, data_rw.getSize(), filename.c_str());
915                 assert(rfile);
916                 
917                 mesh = smgr->getMesh(rfile);
918                 smgr->getMeshCache()->addMesh(filename.c_str(), mesh);
919                 rfile->drop();
920                 return true;
921         }
922
923         errorstream<<"Client: Don't know how to load file \""
924                         <<filename<<"\""<<std::endl;
925         return false;
926 }
927
928 // Virtual methods from con::PeerHandler
929 void Client::peerAdded(con::Peer *peer)
930 {
931         infostream<<"Client::peerAdded(): peer->id="
932                         <<peer->id<<std::endl;
933 }
934 void Client::deletingPeer(con::Peer *peer, bool timeout)
935 {
936         infostream<<"Client::deletingPeer(): "
937                         "Server Peer is getting deleted "
938                         <<"(timeout="<<timeout<<")"<<std::endl;
939 }
940
941 /*
942         u16 command
943         u16 number of files requested
944         for each file {
945                 u16 length of name
946                 string name
947         }
948 */
949 void Client::request_media(const std::list<std::string> &file_requests)
950 {
951         std::ostringstream os(std::ios_base::binary);
952         writeU16(os, TOSERVER_REQUEST_MEDIA);
953         writeU16(os, file_requests.size());
954
955         for(std::list<std::string>::const_iterator i = file_requests.begin();
956                         i != file_requests.end(); ++i) {
957                 os<<serializeString(*i);
958         }
959
960         // Make data buffer
961         std::string s = os.str();
962         SharedBuffer<u8> data((u8*)s.c_str(), s.size());
963         // Send as reliable
964         Send(0, data, true);
965         infostream<<"Client: Sending media request list to server ("
966                         <<file_requests.size()<<" files)"<<std::endl;
967 }
968
969 void Client::received_media()
970 {
971         // notify server we received everything
972         std::ostringstream os(std::ios_base::binary);
973         writeU16(os, TOSERVER_RECEIVED_MEDIA);
974         std::string s = os.str();
975         SharedBuffer<u8> data((u8*)s.c_str(), s.size());
976         // Send as reliable
977         Send(0, data, true);
978         infostream<<"Client: Notifying server that we received all media"
979                         <<std::endl;
980 }
981
982 void Client::ReceiveAll()
983 {
984         DSTACK(__FUNCTION_NAME);
985         u32 start_ms = porting::getTimeMs();
986         for(;;)
987         {
988                 // Limit time even if there would be huge amounts of data to
989                 // process
990                 if(porting::getTimeMs() > start_ms + 100)
991                         break;
992                 
993                 try{
994                         Receive();
995                         g_profiler->graphAdd("client_received_packets", 1);
996                 }
997                 catch(con::NoIncomingDataException &e)
998                 {
999                         break;
1000                 }
1001                 catch(con::InvalidIncomingDataException &e)
1002                 {
1003                         infostream<<"Client::ReceiveAll(): "
1004                                         "InvalidIncomingDataException: what()="
1005                                         <<e.what()<<std::endl;
1006                 }
1007         }
1008 }
1009
1010 void Client::Receive()
1011 {
1012         DSTACK(__FUNCTION_NAME);
1013         SharedBuffer<u8> data;
1014         u16 sender_peer_id;
1015         u32 datasize;
1016         {
1017                 //TimeTaker t1("con mutex and receive", m_device);
1018                 //JMutexAutoLock lock(m_con_mutex); //bulk comment-out
1019                 datasize = m_con.Receive(sender_peer_id, data);
1020         }
1021         //TimeTaker t1("ProcessData", m_device);
1022         ProcessData(*data, datasize, sender_peer_id);
1023 }
1024
1025 /*
1026         sender_peer_id given to this shall be quaranteed to be a valid peer
1027 */
1028 void Client::ProcessData(u8 *data, u32 datasize, u16 sender_peer_id)
1029 {
1030         DSTACK(__FUNCTION_NAME);
1031
1032         // Ignore packets that don't even fit a command
1033         if(datasize < 2)
1034         {
1035                 m_packetcounter.add(60000);
1036                 return;
1037         }
1038
1039         ToClientCommand command = (ToClientCommand)readU16(&data[0]);
1040
1041         //infostream<<"Client: received command="<<command<<std::endl;
1042         m_packetcounter.add((u16)command);
1043         
1044         /*
1045                 If this check is removed, be sure to change the queue
1046                 system to know the ids
1047         */
1048         if(sender_peer_id != PEER_ID_SERVER)
1049         {
1050                 infostream<<"Client::ProcessData(): Discarding data not "
1051                                 "coming from server: peer_id="<<sender_peer_id
1052                                 <<std::endl;
1053                 return;
1054         }
1055
1056         u8 ser_version = m_server_ser_ver;
1057
1058         //infostream<<"Client received command="<<(int)command<<std::endl;
1059
1060         if(command == TOCLIENT_INIT)
1061         {
1062                 if(datasize < 3)
1063                         return;
1064
1065                 u8 deployed = data[2];
1066
1067                 infostream<<"Client: TOCLIENT_INIT received with "
1068                                 "deployed="<<((int)deployed&0xff)<<std::endl;
1069
1070                 if(!ser_ver_supported(deployed))
1071                 {
1072                         infostream<<"Client: TOCLIENT_INIT: Server sent "
1073                                         <<"unsupported ser_fmt_ver"<<std::endl;
1074                         return;
1075                 }
1076                 
1077                 m_server_ser_ver = deployed;
1078
1079                 // Get player position
1080                 v3s16 playerpos_s16(0, BS*2+BS*20, 0);
1081                 if(datasize >= 2+1+6)
1082                         playerpos_s16 = readV3S16(&data[2+1]);
1083                 v3f playerpos_f = intToFloat(playerpos_s16, BS) - v3f(0, BS/2, 0);
1084
1085                 { //envlock
1086                         //JMutexAutoLock envlock(m_env_mutex); //bulk comment-out
1087                         
1088                         // Set player position
1089                         Player *player = m_env.getLocalPlayer();
1090                         assert(player != NULL);
1091                         player->setPosition(playerpos_f);
1092                 }
1093                 
1094                 if(datasize >= 2+1+6+8)
1095                 {
1096                         // Get map seed
1097                         m_map_seed = readU64(&data[2+1+6]);
1098                         infostream<<"Client: received map seed: "<<m_map_seed<<std::endl;
1099                 }
1100
1101                 if(datasize >= 2+1+6+8+4)
1102                 {
1103                         // Get map seed
1104                         m_recommended_send_interval = readF1000(&data[2+1+6+8]);
1105                         infostream<<"Client: received recommended send interval "
1106                                         <<m_recommended_send_interval<<std::endl;
1107                 }
1108                 
1109                 // Reply to server
1110                 u32 replysize = 2;
1111                 SharedBuffer<u8> reply(replysize);
1112                 writeU16(&reply[0], TOSERVER_INIT2);
1113                 // Send as reliable
1114                 m_con.Send(PEER_ID_SERVER, 1, reply, true);
1115
1116                 return;
1117         }
1118
1119         if(command == TOCLIENT_ACCESS_DENIED)
1120         {
1121                 // The server didn't like our password. Note, this needs
1122                 // to be processed even if the serialisation format has
1123                 // not been agreed yet, the same as TOCLIENT_INIT.
1124                 m_access_denied = true;
1125                 m_access_denied_reason = L"Unknown";
1126                 if(datasize >= 4)
1127                 {
1128                         std::string datastring((char*)&data[2], datasize-2);
1129                         std::istringstream is(datastring, std::ios_base::binary);
1130                         m_access_denied_reason = deSerializeWideString(is);
1131                 }
1132                 return;
1133         }
1134
1135         if(ser_version == SER_FMT_VER_INVALID)
1136         {
1137                 infostream<<"Client: Server serialization"
1138                                 " format invalid or not initialized."
1139                                 " Skipping incoming command="<<command<<std::endl;
1140                 return;
1141         }
1142         
1143         // Just here to avoid putting the two if's together when
1144         // making some copypasta
1145         {}
1146
1147         if(command == TOCLIENT_REMOVENODE)
1148         {
1149                 if(datasize < 8)
1150                         return;
1151                 v3s16 p;
1152                 p.X = readS16(&data[2]);
1153                 p.Y = readS16(&data[4]);
1154                 p.Z = readS16(&data[6]);
1155                 
1156                 //TimeTaker t1("TOCLIENT_REMOVENODE");
1157                 
1158                 removeNode(p);
1159         }
1160         else if(command == TOCLIENT_ADDNODE)
1161         {
1162                 if(datasize < 8 + MapNode::serializedLength(ser_version))
1163                         return;
1164
1165                 v3s16 p;
1166                 p.X = readS16(&data[2]);
1167                 p.Y = readS16(&data[4]);
1168                 p.Z = readS16(&data[6]);
1169                 
1170                 //TimeTaker t1("TOCLIENT_ADDNODE");
1171
1172                 MapNode n;
1173                 n.deSerialize(&data[8], ser_version);
1174                 
1175                 bool remove_metadata = true;
1176                 u32 index = 8 + MapNode::serializedLength(ser_version);
1177                 if ((datasize >= index+1) && data[index]){
1178                         remove_metadata = false;
1179                 }
1180                 
1181                 addNode(p, n, remove_metadata);
1182         }
1183         else if(command == TOCLIENT_BLOCKDATA)
1184         {
1185                 // Ignore too small packet
1186                 if(datasize < 8)
1187                         return;
1188                         
1189                 v3s16 p;
1190                 p.X = readS16(&data[2]);
1191                 p.Y = readS16(&data[4]);
1192                 p.Z = readS16(&data[6]);
1193                 
1194                 /*infostream<<"Client: Thread: BLOCKDATA for ("
1195                                 <<p.X<<","<<p.Y<<","<<p.Z<<")"<<std::endl;*/
1196                 /*infostream<<"Client: Thread: BLOCKDATA for ("
1197                                 <<p.X<<","<<p.Y<<","<<p.Z<<")"<<std::endl;*/
1198                 
1199                 std::string datastring((char*)&data[8], datasize-8);
1200                 std::istringstream istr(datastring, std::ios_base::binary);
1201                 
1202                 MapSector *sector;
1203                 MapBlock *block;
1204                 
1205                 v2s16 p2d(p.X, p.Z);
1206                 sector = m_env.getMap().emergeSector(p2d);
1207                 
1208                 assert(sector->getPos() == p2d);
1209
1210                 //TimeTaker timer("MapBlock deSerialize");
1211                 // 0ms
1212                 
1213                 block = sector->getBlockNoCreateNoEx(p.Y);
1214                 if(block)
1215                 {
1216                         /*
1217                                 Update an existing block
1218                         */
1219                         //infostream<<"Updating"<<std::endl;
1220                         block->deSerialize(istr, ser_version, false);
1221                         block->deSerializeNetworkSpecific(istr);
1222                 }
1223                 else
1224                 {
1225                         /*
1226                                 Create a new block
1227                         */
1228                         //infostream<<"Creating new"<<std::endl;
1229                         block = new MapBlock(&m_env.getMap(), p, this);
1230                         block->deSerialize(istr, ser_version, false);
1231                         block->deSerializeNetworkSpecific(istr);
1232                         sector->insertBlock(block);
1233                 }
1234
1235 #if 0
1236                 /*
1237                         Acknowledge block
1238                 */
1239                 /*
1240                         [0] u16 command
1241                         [2] u8 count
1242                         [3] v3s16 pos_0
1243                         [3+6] v3s16 pos_1
1244                         ...
1245                 */
1246                 u32 replysize = 2+1+6;
1247                 SharedBuffer<u8> reply(replysize);
1248                 writeU16(&reply[0], TOSERVER_GOTBLOCKS);
1249                 reply[2] = 1;
1250                 writeV3S16(&reply[3], p);
1251                 // Send as reliable
1252                 m_con.Send(PEER_ID_SERVER, 1, reply, true);
1253 #endif
1254
1255                 /*
1256                         Add it to mesh update queue and set it to be acknowledged after update.
1257                 */
1258                 //infostream<<"Adding mesh update task for received block"<<std::endl;
1259                 addUpdateMeshTaskWithEdge(p, true);
1260         }
1261         else if(command == TOCLIENT_INVENTORY)
1262         {
1263                 if(datasize < 3)
1264                         return;
1265
1266                 //TimeTaker t1("Parsing TOCLIENT_INVENTORY", m_device);
1267
1268                 { //envlock
1269                         //TimeTaker t2("mutex locking", m_device);
1270                         //JMutexAutoLock envlock(m_env_mutex); //bulk comment-out
1271                         //t2.stop();
1272                         
1273                         //TimeTaker t3("istringstream init", m_device);
1274                         std::string datastring((char*)&data[2], datasize-2);
1275                         std::istringstream is(datastring, std::ios_base::binary);
1276                         //t3.stop();
1277                         
1278                         //TimeTaker t4("player get", m_device);
1279                         Player *player = m_env.getLocalPlayer();
1280                         assert(player != NULL);
1281                         //t4.stop();
1282
1283                         //TimeTaker t1("inventory.deSerialize()", m_device);
1284                         player->inventory.deSerialize(is);
1285                         //t1.stop();
1286
1287                         m_inventory_updated = true;
1288
1289                         delete m_inventory_from_server;
1290                         m_inventory_from_server = new Inventory(player->inventory);
1291                         m_inventory_from_server_age = 0.0;
1292
1293                         //infostream<<"Client got player inventory:"<<std::endl;
1294                         //player->inventory.print(infostream);
1295                 }
1296         }
1297         else if(command == TOCLIENT_TIME_OF_DAY)
1298         {
1299                 if(datasize < 4)
1300                         return;
1301                 
1302                 u16 time_of_day = readU16(&data[2]);
1303                 time_of_day = time_of_day % 24000;
1304                 //infostream<<"Client: time_of_day="<<time_of_day<<std::endl;
1305                 float time_speed = 0;
1306                 if(datasize >= 2 + 2 + 4){
1307                         time_speed = readF1000(&data[4]);
1308                 } else {
1309                         // Old message; try to approximate speed of time by ourselves
1310                         float time_of_day_f = (float)time_of_day / 24000.0;
1311                         float tod_diff_f = 0;
1312                         if(time_of_day_f < 0.2 && m_last_time_of_day_f > 0.8)
1313                                 tod_diff_f = time_of_day_f - m_last_time_of_day_f + 1.0;
1314                         else
1315                                 tod_diff_f = time_of_day_f - m_last_time_of_day_f;
1316                         m_last_time_of_day_f = time_of_day_f;
1317                         float time_diff = m_time_of_day_update_timer;
1318                         m_time_of_day_update_timer = 0;
1319                         if(m_time_of_day_set){
1320                                 time_speed = 3600.0*24.0 * tod_diff_f / time_diff;
1321                                 infostream<<"Client: Measured time_of_day speed (old format): "
1322                                                 <<time_speed<<" tod_diff_f="<<tod_diff_f
1323                                                 <<" time_diff="<<time_diff<<std::endl;
1324                         }
1325                 }
1326                 
1327                 // Update environment
1328                 m_env.setTimeOfDay(time_of_day);
1329                 m_env.setTimeOfDaySpeed(time_speed);
1330                 m_time_of_day_set = true;
1331
1332                 u32 dr = m_env.getDayNightRatio();
1333                 verbosestream<<"Client: time_of_day="<<time_of_day
1334                                 <<" time_speed="<<time_speed
1335                                 <<" dr="<<dr<<std::endl;
1336         }
1337         else if(command == TOCLIENT_CHAT_MESSAGE)
1338         {
1339                 /*
1340                         u16 command
1341                         u16 length
1342                         wstring message
1343                 */
1344                 u8 buf[6];
1345                 std::string datastring((char*)&data[2], datasize-2);
1346                 std::istringstream is(datastring, std::ios_base::binary);
1347                 
1348                 // Read stuff
1349                 is.read((char*)buf, 2);
1350                 u16 len = readU16(buf);
1351                 
1352                 std::wstring message;
1353                 for(u16 i=0; i<len; i++)
1354                 {
1355                         is.read((char*)buf, 2);
1356                         message += (wchar_t)readU16(buf);
1357                 }
1358
1359                 /*infostream<<"Client received chat message: "
1360                                 <<wide_to_narrow(message)<<std::endl;*/
1361                 
1362                 m_chat_queue.push_back(message);
1363         }
1364         else if(command == TOCLIENT_ACTIVE_OBJECT_REMOVE_ADD)
1365         {
1366                 //if(g_settings->getBool("enable_experimental"))
1367                 {
1368                         /*
1369                                 u16 command
1370                                 u16 count of removed objects
1371                                 for all removed objects {
1372                                         u16 id
1373                                 }
1374                                 u16 count of added objects
1375                                 for all added objects {
1376                                         u16 id
1377                                         u8 type
1378                                         u32 initialization data length
1379                                         string initialization data
1380                                 }
1381                         */
1382
1383                         char buf[6];
1384                         // Get all data except the command number
1385                         std::string datastring((char*)&data[2], datasize-2);
1386                         // Throw them in an istringstream
1387                         std::istringstream is(datastring, std::ios_base::binary);
1388
1389                         // Read stuff
1390                         
1391                         // Read removed objects
1392                         is.read(buf, 2);
1393                         u16 removed_count = readU16((u8*)buf);
1394                         for(u16 i=0; i<removed_count; i++)
1395                         {
1396                                 is.read(buf, 2);
1397                                 u16 id = readU16((u8*)buf);
1398                                 // Remove it
1399                                 {
1400                                         //JMutexAutoLock envlock(m_env_mutex); //bulk comment-out
1401                                         m_env.removeActiveObject(id);
1402                                 }
1403                         }
1404                         
1405                         // Read added objects
1406                         is.read(buf, 2);
1407                         u16 added_count = readU16((u8*)buf);
1408                         for(u16 i=0; i<added_count; i++)
1409                         {
1410                                 is.read(buf, 2);
1411                                 u16 id = readU16((u8*)buf);
1412                                 is.read(buf, 1);
1413                                 u8 type = readU8((u8*)buf);
1414                                 std::string data = deSerializeLongString(is);
1415                                 // Add it
1416                                 {
1417                                         //JMutexAutoLock envlock(m_env_mutex); //bulk comment-out
1418                                         m_env.addActiveObject(id, type, data);
1419                                 }
1420                         }
1421                 }
1422         }
1423         else if(command == TOCLIENT_ACTIVE_OBJECT_MESSAGES)
1424         {
1425                 //if(g_settings->getBool("enable_experimental"))
1426                 {
1427                         /*
1428                                 u16 command
1429                                 for all objects
1430                                 {
1431                                         u16 id
1432                                         u16 message length
1433                                         string message
1434                                 }
1435                         */
1436                         char buf[6];
1437                         // Get all data except the command number
1438                         std::string datastring((char*)&data[2], datasize-2);
1439                         // Throw them in an istringstream
1440                         std::istringstream is(datastring, std::ios_base::binary);
1441                         
1442                         while(is.eof() == false)
1443                         {
1444                                 // Read stuff
1445                                 is.read(buf, 2);
1446                                 u16 id = readU16((u8*)buf);
1447                                 if(is.eof())
1448                                         break;
1449                                 is.read(buf, 2);
1450                                 u16 message_size = readU16((u8*)buf);
1451                                 std::string message;
1452                                 message.reserve(message_size);
1453                                 for(u16 i=0; i<message_size; i++)
1454                                 {
1455                                         is.read(buf, 1);
1456                                         message.append(buf, 1);
1457                                 }
1458                                 // Pass on to the environment
1459                                 {
1460                                         //JMutexAutoLock envlock(m_env_mutex); //bulk comment-out
1461                                         m_env.processActiveObjectMessage(id, message);
1462                                 }
1463                         }
1464                 }
1465         }
1466         else if(command == TOCLIENT_MOVEMENT)
1467         {
1468                 std::string datastring((char*)&data[2], datasize-2);
1469                 std::istringstream is(datastring, std::ios_base::binary);
1470                 Player *player = m_env.getLocalPlayer();
1471                 assert(player != NULL);
1472
1473                 player->movement_acceleration_default = readF1000(is) * BS;
1474                 player->movement_acceleration_air = readF1000(is) * BS;
1475                 player->movement_acceleration_fast = readF1000(is) * BS;
1476                 player->movement_speed_walk = readF1000(is) * BS;
1477                 player->movement_speed_crouch = readF1000(is) * BS;
1478                 player->movement_speed_fast = readF1000(is) * BS;
1479                 player->movement_speed_climb = readF1000(is) * BS;
1480                 player->movement_speed_jump = readF1000(is) * BS;
1481                 player->movement_liquid_fluidity = readF1000(is) * BS;
1482                 player->movement_liquid_fluidity_smooth = readF1000(is) * BS;
1483                 player->movement_liquid_sink = readF1000(is) * BS;
1484                 player->movement_gravity = readF1000(is) * BS;
1485         }
1486         else if(command == TOCLIENT_HP)
1487         {
1488                 std::string datastring((char*)&data[2], datasize-2);
1489                 std::istringstream is(datastring, std::ios_base::binary);
1490                 Player *player = m_env.getLocalPlayer();
1491                 assert(player != NULL);
1492                 u8 oldhp = player->hp;
1493                 u8 hp = readU8(is);
1494                 player->hp = hp;
1495
1496                 if(hp < oldhp)
1497                 {
1498                         // Add to ClientEvent queue
1499                         ClientEvent event;
1500                         event.type = CE_PLAYER_DAMAGE;
1501                         event.player_damage.amount = oldhp - hp;
1502                         m_client_event_queue.push_back(event);
1503                 }
1504         }
1505         else if(command == TOCLIENT_BREATH)
1506         {
1507                 std::string datastring((char*)&data[2], datasize-2);
1508                 std::istringstream is(datastring, std::ios_base::binary);
1509                 Player *player = m_env.getLocalPlayer();
1510                 assert(player != NULL);
1511                 u16 breath = readU16(is);
1512                 player->setBreath(breath) ;
1513         }
1514         else if(command == TOCLIENT_MOVE_PLAYER)
1515         {
1516                 std::string datastring((char*)&data[2], datasize-2);
1517                 std::istringstream is(datastring, std::ios_base::binary);
1518                 Player *player = m_env.getLocalPlayer();
1519                 assert(player != NULL);
1520                 v3f pos = readV3F1000(is);
1521                 f32 pitch = readF1000(is);
1522                 f32 yaw = readF1000(is);
1523                 player->setPosition(pos);
1524                 /*player->setPitch(pitch);
1525                 player->setYaw(yaw);*/
1526
1527                 infostream<<"Client got TOCLIENT_MOVE_PLAYER"
1528                                 <<" pos=("<<pos.X<<","<<pos.Y<<","<<pos.Z<<")"
1529                                 <<" pitch="<<pitch
1530                                 <<" yaw="<<yaw
1531                                 <<std::endl;
1532
1533                 /*
1534                         Add to ClientEvent queue.
1535                         This has to be sent to the main program because otherwise
1536                         it would just force the pitch and yaw values to whatever
1537                         the camera points to.
1538                 */
1539                 ClientEvent event;
1540                 event.type = CE_PLAYER_FORCE_MOVE;
1541                 event.player_force_move.pitch = pitch;
1542                 event.player_force_move.yaw = yaw;
1543                 m_client_event_queue.push_back(event);
1544
1545                 // Ignore damage for a few seconds, so that the player doesn't
1546                 // get damage from falling on ground
1547                 m_ignore_damage_timer = 3.0;
1548         }
1549         else if(command == TOCLIENT_PLAYERITEM)
1550         {
1551                 infostream<<"Client: WARNING: Ignoring TOCLIENT_PLAYERITEM"<<std::endl;
1552         }
1553         else if(command == TOCLIENT_DEATHSCREEN)
1554         {
1555                 std::string datastring((char*)&data[2], datasize-2);
1556                 std::istringstream is(datastring, std::ios_base::binary);
1557                 
1558                 bool set_camera_point_target = readU8(is);
1559                 v3f camera_point_target = readV3F1000(is);
1560                 
1561                 ClientEvent event;
1562                 event.type = CE_DEATHSCREEN;
1563                 event.deathscreen.set_camera_point_target = set_camera_point_target;
1564                 event.deathscreen.camera_point_target_x = camera_point_target.X;
1565                 event.deathscreen.camera_point_target_y = camera_point_target.Y;
1566                 event.deathscreen.camera_point_target_z = camera_point_target.Z;
1567                 m_client_event_queue.push_back(event);
1568         }
1569         else if(command == TOCLIENT_ANNOUNCE_MEDIA)
1570         {
1571                 std::string datastring((char*)&data[2], datasize-2);
1572                 std::istringstream is(datastring, std::ios_base::binary);
1573
1574                 int num_files = readU16(is);
1575                 
1576                 infostream<<"Client: Received media announcement: packet size: "
1577                                 <<datasize<<std::endl;
1578
1579                 if (m_media_downloader == NULL ||
1580                                 m_media_downloader->isStarted()) {
1581                         const char *problem = m_media_downloader ?
1582                                 "we already saw another announcement" :
1583                                 "all media has been received already";
1584                         errorstream<<"Client: Received media announcement but "
1585                                 <<problem<<"! "
1586                                 <<" files="<<num_files
1587                                 <<" size="<<datasize<<std::endl;
1588                         return;
1589                 }
1590
1591                 // Mesh update thread must be stopped while
1592                 // updating content definitions
1593                 assert(!m_mesh_update_thread.IsRunning());
1594
1595                 for(int i=0; i<num_files; i++)
1596                 {
1597                         std::string name = deSerializeString(is);
1598                         std::string sha1_base64 = deSerializeString(is);
1599                         std::string sha1_raw = base64_decode(sha1_base64);
1600                         m_media_downloader->addFile(name, sha1_raw);
1601                 }
1602
1603                 std::vector<std::string> remote_media;
1604                 try {
1605                         Strfnd sf(deSerializeString(is));
1606                         while(!sf.atend()) {
1607                                 std::string baseurl = trim(sf.next(","));
1608                                 if(baseurl != "")
1609                                         m_media_downloader->addRemoteServer(baseurl);
1610                         }
1611                 }
1612                 catch(SerializationError) {
1613                         // not supported by server or turned off
1614                 }
1615
1616                 m_media_downloader->step(this);
1617                 if (m_media_downloader->isDone()) {
1618                         // might be done already if all media is in the cache
1619                         delete m_media_downloader;
1620                         m_media_downloader = NULL;
1621                 }
1622         }
1623         else if(command == TOCLIENT_MEDIA)
1624         {
1625                 std::string datastring((char*)&data[2], datasize-2);
1626                 std::istringstream is(datastring, std::ios_base::binary);
1627
1628                 /*
1629                         u16 command
1630                         u16 total number of file bunches
1631                         u16 index of this bunch
1632                         u32 number of files in this bunch
1633                         for each file {
1634                                 u16 length of name
1635                                 string name
1636                                 u32 length of data
1637                                 data
1638                         }
1639                 */
1640                 int num_bunches = readU16(is);
1641                 int bunch_i = readU16(is);
1642                 u32 num_files = readU32(is);
1643                 infostream<<"Client: Received files: bunch "<<bunch_i<<"/"
1644                                 <<num_bunches<<" files="<<num_files
1645                                 <<" size="<<datasize<<std::endl;
1646
1647                 if (num_files == 0)
1648                         return;
1649
1650                 if (m_media_downloader == NULL ||
1651                                 !m_media_downloader->isStarted()) {
1652                         const char *problem = m_media_downloader ?
1653                                 "media has not been requested" :
1654                                 "all media has been received already";
1655                         errorstream<<"Client: Received media but "
1656                                 <<problem<<"! "
1657                                 <<" bunch "<<bunch_i<<"/"<<num_bunches
1658                                 <<" files="<<num_files
1659                                 <<" size="<<datasize<<std::endl;
1660                         return;
1661                 }
1662
1663                 // Mesh update thread must be stopped while
1664                 // updating content definitions
1665                 assert(!m_mesh_update_thread.IsRunning());
1666
1667                 for(u32 i=0; i<num_files; i++){
1668                         std::string name = deSerializeString(is);
1669                         std::string data = deSerializeLongString(is);
1670                         m_media_downloader->conventionalTransferDone(
1671                                         name, data, this);
1672                 }
1673
1674                 if (m_media_downloader->isDone()) {
1675                         delete m_media_downloader;
1676                         m_media_downloader = NULL;
1677                 }
1678         }
1679         else if(command == TOCLIENT_TOOLDEF)
1680         {
1681                 infostream<<"Client: WARNING: Ignoring TOCLIENT_TOOLDEF"<<std::endl;
1682         }
1683         else if(command == TOCLIENT_NODEDEF)
1684         {
1685                 infostream<<"Client: Received node definitions: packet size: "
1686                                 <<datasize<<std::endl;
1687
1688                 // Mesh update thread must be stopped while
1689                 // updating content definitions
1690                 assert(!m_mesh_update_thread.IsRunning());
1691
1692                 // Decompress node definitions
1693                 std::string datastring((char*)&data[2], datasize-2);
1694                 std::istringstream is(datastring, std::ios_base::binary);
1695                 std::istringstream tmp_is(deSerializeLongString(is), std::ios::binary);
1696                 std::ostringstream tmp_os;
1697                 decompressZlib(tmp_is, tmp_os);
1698
1699                 // Deserialize node definitions
1700                 std::istringstream tmp_is2(tmp_os.str());
1701                 m_nodedef->deSerialize(tmp_is2);
1702                 m_nodedef_received = true;
1703         }
1704         else if(command == TOCLIENT_CRAFTITEMDEF)
1705         {
1706                 infostream<<"Client: WARNING: Ignoring TOCLIENT_CRAFTITEMDEF"<<std::endl;
1707         }
1708         else if(command == TOCLIENT_ITEMDEF)
1709         {
1710                 infostream<<"Client: Received item definitions: packet size: "
1711                                 <<datasize<<std::endl;
1712
1713                 // Mesh update thread must be stopped while
1714                 // updating content definitions
1715                 assert(!m_mesh_update_thread.IsRunning());
1716
1717                 // Decompress item definitions
1718                 std::string datastring((char*)&data[2], datasize-2);
1719                 std::istringstream is(datastring, std::ios_base::binary);
1720                 std::istringstream tmp_is(deSerializeLongString(is), std::ios::binary);
1721                 std::ostringstream tmp_os;
1722                 decompressZlib(tmp_is, tmp_os);
1723
1724                 // Deserialize node definitions
1725                 std::istringstream tmp_is2(tmp_os.str());
1726                 m_itemdef->deSerialize(tmp_is2);
1727                 m_itemdef_received = true;
1728         }
1729         else if(command == TOCLIENT_PLAY_SOUND)
1730         {
1731                 std::string datastring((char*)&data[2], datasize-2);
1732                 std::istringstream is(datastring, std::ios_base::binary);
1733
1734                 s32 server_id = readS32(is);
1735                 std::string name = deSerializeString(is);
1736                 float gain = readF1000(is);
1737                 int type = readU8(is); // 0=local, 1=positional, 2=object
1738                 v3f pos = readV3F1000(is);
1739                 u16 object_id = readU16(is);
1740                 bool loop = readU8(is);
1741                 // Start playing
1742                 int client_id = -1;
1743                 switch(type){
1744                 case 0: // local
1745                         client_id = m_sound->playSound(name, loop, gain);
1746                         break;
1747                 case 1: // positional
1748                         client_id = m_sound->playSoundAt(name, loop, gain, pos);
1749                         break;
1750                 case 2: { // object
1751                         ClientActiveObject *cao = m_env.getActiveObject(object_id);
1752                         if(cao)
1753                                 pos = cao->getPosition();
1754                         client_id = m_sound->playSoundAt(name, loop, gain, pos);
1755                         // TODO: Set up sound to move with object
1756                         break; }
1757                 default:
1758                         break;
1759                 }
1760                 if(client_id != -1){
1761                         m_sounds_server_to_client[server_id] = client_id;
1762                         m_sounds_client_to_server[client_id] = server_id;
1763                         if(object_id != 0)
1764                                 m_sounds_to_objects[client_id] = object_id;
1765                 }
1766         }
1767         else if(command == TOCLIENT_STOP_SOUND)
1768         {
1769                 std::string datastring((char*)&data[2], datasize-2);
1770                 std::istringstream is(datastring, std::ios_base::binary);
1771
1772                 s32 server_id = readS32(is);
1773                 std::map<s32, int>::iterator i =
1774                                 m_sounds_server_to_client.find(server_id);
1775                 if(i != m_sounds_server_to_client.end()){
1776                         int client_id = i->second;
1777                         m_sound->stopSound(client_id);
1778                 }
1779         }
1780         else if(command == TOCLIENT_PRIVILEGES)
1781         {
1782                 std::string datastring((char*)&data[2], datasize-2);
1783                 std::istringstream is(datastring, std::ios_base::binary);
1784                 
1785                 m_privileges.clear();
1786                 infostream<<"Client: Privileges updated: ";
1787                 u16 num_privileges = readU16(is);
1788                 for(u16 i=0; i<num_privileges; i++){
1789                         std::string priv = deSerializeString(is);
1790                         m_privileges.insert(priv);
1791                         infostream<<priv<<" ";
1792                 }
1793                 infostream<<std::endl;
1794         }
1795         else if(command == TOCLIENT_INVENTORY_FORMSPEC)
1796         {
1797                 std::string datastring((char*)&data[2], datasize-2);
1798                 std::istringstream is(datastring, std::ios_base::binary);
1799
1800                 // Store formspec in LocalPlayer
1801                 Player *player = m_env.getLocalPlayer();
1802                 assert(player != NULL);
1803                 player->inventory_formspec = deSerializeLongString(is);
1804         }
1805         else if(command == TOCLIENT_DETACHED_INVENTORY)
1806         {
1807                 std::string datastring((char*)&data[2], datasize-2);
1808                 std::istringstream is(datastring, std::ios_base::binary);
1809
1810                 std::string name = deSerializeString(is);
1811                 
1812                 infostream<<"Client: Detached inventory update: \""<<name<<"\""<<std::endl;
1813
1814                 Inventory *inv = NULL;
1815                 if(m_detached_inventories.count(name) > 0)
1816                         inv = m_detached_inventories[name];
1817                 else{
1818                         inv = new Inventory(m_itemdef);
1819                         m_detached_inventories[name] = inv;
1820                 }
1821                 inv->deSerialize(is);
1822         }
1823         else if(command == TOCLIENT_SHOW_FORMSPEC)
1824         {
1825                 std::string datastring((char*)&data[2], datasize-2);
1826                 std::istringstream is(datastring, std::ios_base::binary);
1827
1828                 std::string formspec = deSerializeLongString(is);
1829                 std::string formname = deSerializeString(is);
1830
1831                 ClientEvent event;
1832                 event.type = CE_SHOW_FORMSPEC;
1833                 // pointer is required as event is a struct only!
1834                 // adding a std:string to a struct isn't possible
1835                 event.show_formspec.formspec = new std::string(formspec);
1836                 event.show_formspec.formname = new std::string(formname);
1837                 m_client_event_queue.push_back(event);
1838         }
1839         else if(command == TOCLIENT_SPAWN_PARTICLE)
1840         {
1841                 std::string datastring((char*)&data[2], datasize-2);
1842                 std::istringstream is(datastring, std::ios_base::binary);
1843
1844                 v3f pos = readV3F1000(is);
1845                 v3f vel = readV3F1000(is);
1846                 v3f acc = readV3F1000(is);
1847                 float expirationtime = readF1000(is);
1848                 float size = readF1000(is);
1849                 bool collisiondetection = readU8(is);
1850                 std::string texture = deSerializeLongString(is);
1851
1852                 ClientEvent event;
1853                 event.type = CE_SPAWN_PARTICLE;
1854                 event.spawn_particle.pos = new v3f (pos);
1855                 event.spawn_particle.vel = new v3f (vel);
1856                 event.spawn_particle.acc = new v3f (acc);
1857
1858                 event.spawn_particle.expirationtime = expirationtime;
1859                 event.spawn_particle.size = size;
1860                 event.spawn_particle.collisiondetection =
1861                                 collisiondetection;
1862                 event.spawn_particle.texture = new std::string(texture);
1863
1864                 m_client_event_queue.push_back(event);
1865         }
1866         else if(command == TOCLIENT_ADD_PARTICLESPAWNER)
1867         {
1868                 std::string datastring((char*)&data[2], datasize-2);
1869                 std::istringstream is(datastring, std::ios_base::binary);
1870
1871                 u16 amount = readU16(is);
1872                 float spawntime = readF1000(is);
1873                 v3f minpos = readV3F1000(is);
1874                 v3f maxpos = readV3F1000(is);
1875                 v3f minvel = readV3F1000(is);
1876                 v3f maxvel = readV3F1000(is);
1877                 v3f minacc = readV3F1000(is);
1878                 v3f maxacc = readV3F1000(is);
1879                 float minexptime = readF1000(is);
1880                 float maxexptime = readF1000(is);
1881                 float minsize = readF1000(is);
1882                 float maxsize = readF1000(is);
1883                 bool collisiondetection = readU8(is);
1884                 std::string texture = deSerializeLongString(is);
1885                 u32 id = readU32(is);
1886
1887                 ClientEvent event;
1888                 event.type = CE_ADD_PARTICLESPAWNER;
1889                 event.add_particlespawner.amount = amount;
1890                 event.add_particlespawner.spawntime = spawntime;
1891
1892                 event.add_particlespawner.minpos = new v3f (minpos);
1893                 event.add_particlespawner.maxpos = new v3f (maxpos);
1894                 event.add_particlespawner.minvel = new v3f (minvel);
1895                 event.add_particlespawner.maxvel = new v3f (maxvel);
1896                 event.add_particlespawner.minacc = new v3f (minacc);
1897                 event.add_particlespawner.maxacc = new v3f (maxacc);
1898
1899                 event.add_particlespawner.minexptime = minexptime;
1900                 event.add_particlespawner.maxexptime = maxexptime;
1901                 event.add_particlespawner.minsize = minsize;
1902                 event.add_particlespawner.maxsize = maxsize;
1903                 event.add_particlespawner.collisiondetection = collisiondetection;
1904                 event.add_particlespawner.texture = new std::string(texture);
1905                 event.add_particlespawner.id = id;
1906
1907                 m_client_event_queue.push_back(event);
1908         }
1909         else if(command == TOCLIENT_DELETE_PARTICLESPAWNER)
1910         {
1911                 std::string datastring((char*)&data[2], datasize-2);
1912                 std::istringstream is(datastring, std::ios_base::binary);
1913
1914                 u32 id = readU16(is);
1915
1916                 ClientEvent event;
1917                 event.type = CE_DELETE_PARTICLESPAWNER;
1918                 event.delete_particlespawner.id = id;
1919
1920                 m_client_event_queue.push_back(event);
1921         }
1922         else if(command == TOCLIENT_HUDADD)
1923         {
1924                 std::string datastring((char *)&data[2], datasize - 2);
1925                 std::istringstream is(datastring, std::ios_base::binary);
1926
1927                 u32 id           = readU32(is);
1928                 u8 type          = readU8(is);
1929                 v2f pos          = readV2F1000(is);
1930                 std::string name = deSerializeString(is);
1931                 v2f scale        = readV2F1000(is);
1932                 std::string text = deSerializeString(is);
1933                 u32 number       = readU32(is);
1934                 u32 item         = readU32(is);
1935                 u32 dir          = readU32(is);
1936                 v2f align        = readV2F1000(is);
1937                 v2f offset       = readV2F1000(is);
1938
1939                 ClientEvent event;
1940                 event.type = CE_HUDADD;
1941                 event.hudadd.id     = id;
1942                 event.hudadd.type   = type;
1943                 event.hudadd.pos    = new v2f(pos);
1944                 event.hudadd.name   = new std::string(name);
1945                 event.hudadd.scale  = new v2f(scale);
1946                 event.hudadd.text   = new std::string(text);
1947                 event.hudadd.number = number;
1948                 event.hudadd.item   = item;
1949                 event.hudadd.dir    = dir;
1950                 event.hudadd.align  = new v2f(align);
1951                 event.hudadd.offset = new v2f(offset);
1952                 m_client_event_queue.push_back(event);
1953         }
1954         else if(command == TOCLIENT_HUDRM)
1955         {
1956                 std::string datastring((char *)&data[2], datasize - 2);
1957                 std::istringstream is(datastring, std::ios_base::binary);
1958
1959                 u32 id = readU32(is);
1960
1961                 ClientEvent event;
1962                 event.type = CE_HUDRM;
1963                 event.hudrm.id = id;
1964                 m_client_event_queue.push_back(event);
1965         }
1966         else if(command == TOCLIENT_HUDCHANGE)
1967         {
1968                 std::string sdata;
1969                 v2f v2fdata;
1970                 u32 intdata = 0;
1971                 
1972                 std::string datastring((char *)&data[2], datasize - 2);
1973                 std::istringstream is(datastring, std::ios_base::binary);
1974
1975                 u32 id  = readU32(is);
1976                 u8 stat = (HudElementStat)readU8(is);
1977                 
1978                 if (stat == HUD_STAT_POS || stat == HUD_STAT_SCALE ||
1979                         stat == HUD_STAT_ALIGN || stat == HUD_STAT_OFFSET)
1980                         v2fdata = readV2F1000(is);
1981                 else if (stat == HUD_STAT_NAME || stat == HUD_STAT_TEXT)
1982                         sdata = deSerializeString(is);
1983                 else
1984                         intdata = readU32(is);
1985                 
1986                 ClientEvent event;
1987                 event.type = CE_HUDCHANGE;
1988                 event.hudchange.id      = id;
1989                 event.hudchange.stat    = (HudElementStat)stat;
1990                 event.hudchange.v2fdata = new v2f(v2fdata);
1991                 event.hudchange.sdata   = new std::string(sdata);
1992                 event.hudchange.data    = intdata;
1993                 m_client_event_queue.push_back(event);
1994         }
1995         else if(command == TOCLIENT_HUD_SET_FLAGS)
1996         {
1997                 std::string datastring((char *)&data[2], datasize - 2);
1998                 std::istringstream is(datastring, std::ios_base::binary);
1999
2000                 Player *player = m_env.getLocalPlayer();
2001                 assert(player != NULL);
2002
2003                 u32 flags = readU32(is);
2004                 u32 mask  = readU32(is);
2005                 
2006                 player->hud_flags &= ~mask;
2007                 player->hud_flags |= flags;
2008         }
2009         else if(command == TOCLIENT_HUD_SET_PARAM)
2010         {
2011                 std::string datastring((char *)&data[2], datasize - 2);
2012                 std::istringstream is(datastring, std::ios_base::binary);
2013
2014                 Player *player = m_env.getLocalPlayer();
2015                 assert(player != NULL);
2016
2017                 u16 param         = readU16(is);
2018                 std::string value = deSerializeString(is);
2019
2020                 if(param == HUD_PARAM_HOTBAR_ITEMCOUNT && value.size() == 4){
2021                         s32 hotbar_itemcount = readS32((u8*) value.c_str());
2022                         if(hotbar_itemcount > 0 && hotbar_itemcount <= HUD_HOTBAR_ITEMCOUNT_MAX)
2023                                 player->hud_hotbar_itemcount = hotbar_itemcount;
2024                 } else if (param == HUD_PARAM_HOTBAR_IMAGE) {
2025                         ((LocalPlayer *) player)->hotbar_image = value;
2026                 } else if (param == HUD_PARAM_HOTBAR_SELECTED_IMAGE) {
2027                         ((LocalPlayer *) player)->hotbar_selected_image = value;
2028                 }
2029         }
2030         else
2031         {
2032                 infostream<<"Client: Ignoring unknown command "
2033                                 <<command<<std::endl;
2034         }
2035 }
2036
2037 void Client::Send(u16 channelnum, SharedBuffer<u8> data, bool reliable)
2038 {
2039         //JMutexAutoLock lock(m_con_mutex); //bulk comment-out
2040         m_con.Send(PEER_ID_SERVER, channelnum, data, reliable);
2041 }
2042
2043 void Client::interact(u8 action, const PointedThing& pointed)
2044 {
2045         if(connectedAndInitialized() == false){
2046                 infostream<<"Client::interact() "
2047                                 "cancelled (not connected)"
2048                                 <<std::endl;
2049                 return;
2050         }
2051
2052         std::ostringstream os(std::ios_base::binary);
2053
2054         /*
2055                 [0] u16 command
2056                 [2] u8 action
2057                 [3] u16 item
2058                 [5] u32 length of the next item
2059                 [9] serialized PointedThing
2060                 actions:
2061                 0: start digging (from undersurface) or use
2062                 1: stop digging (all parameters ignored)
2063                 2: digging completed
2064                 3: place block or item (to abovesurface)
2065                 4: use item
2066         */
2067         writeU16(os, TOSERVER_INTERACT);
2068         writeU8(os, action);
2069         writeU16(os, getPlayerItem());
2070         std::ostringstream tmp_os(std::ios::binary);
2071         pointed.serialize(tmp_os);
2072         os<<serializeLongString(tmp_os.str());
2073
2074         std::string s = os.str();
2075         SharedBuffer<u8> data((u8*)s.c_str(), s.size());
2076
2077         // Send as reliable
2078         Send(0, data, true);
2079 }
2080
2081 void Client::sendNodemetaFields(v3s16 p, const std::string &formname,
2082                 const std::map<std::string, std::string> &fields)
2083 {
2084         std::ostringstream os(std::ios_base::binary);
2085
2086         writeU16(os, TOSERVER_NODEMETA_FIELDS);
2087         writeV3S16(os, p);
2088         os<<serializeString(formname);
2089         writeU16(os, fields.size());
2090         for(std::map<std::string, std::string>::const_iterator
2091                         i = fields.begin(); i != fields.end(); i++){
2092                 const std::string &name = i->first;
2093                 const std::string &value = i->second;
2094                 os<<serializeString(name);
2095                 os<<serializeLongString(value);
2096         }
2097
2098         // Make data buffer
2099         std::string s = os.str();
2100         SharedBuffer<u8> data((u8*)s.c_str(), s.size());
2101         // Send as reliable
2102         Send(0, data, true);
2103 }
2104         
2105 void Client::sendInventoryFields(const std::string &formname,
2106                 const std::map<std::string, std::string> &fields)
2107 {
2108         std::ostringstream os(std::ios_base::binary);
2109
2110         writeU16(os, TOSERVER_INVENTORY_FIELDS);
2111         os<<serializeString(formname);
2112         writeU16(os, fields.size());
2113         for(std::map<std::string, std::string>::const_iterator
2114                         i = fields.begin(); i != fields.end(); i++){
2115                 const std::string &name = i->first;
2116                 const std::string &value = i->second;
2117                 os<<serializeString(name);
2118                 os<<serializeLongString(value);
2119         }
2120
2121         // Make data buffer
2122         std::string s = os.str();
2123         SharedBuffer<u8> data((u8*)s.c_str(), s.size());
2124         // Send as reliable
2125         Send(0, data, true);
2126 }
2127
2128 void Client::sendInventoryAction(InventoryAction *a)
2129 {
2130         std::ostringstream os(std::ios_base::binary);
2131         u8 buf[12];
2132         
2133         // Write command
2134         writeU16(buf, TOSERVER_INVENTORY_ACTION);
2135         os.write((char*)buf, 2);
2136
2137         a->serialize(os);
2138         
2139         // Make data buffer
2140         std::string s = os.str();
2141         SharedBuffer<u8> data((u8*)s.c_str(), s.size());
2142         // Send as reliable
2143         Send(0, data, true);
2144 }
2145
2146 void Client::sendChatMessage(const std::wstring &message)
2147 {
2148         std::ostringstream os(std::ios_base::binary);
2149         u8 buf[12];
2150         
2151         // Write command
2152         writeU16(buf, TOSERVER_CHAT_MESSAGE);
2153         os.write((char*)buf, 2);
2154         
2155         // Write length
2156         writeU16(buf, message.size());
2157         os.write((char*)buf, 2);
2158         
2159         // Write string
2160         for(u32 i=0; i<message.size(); i++)
2161         {
2162                 u16 w = message[i];
2163                 writeU16(buf, w);
2164                 os.write((char*)buf, 2);
2165         }
2166         
2167         // Make data buffer
2168         std::string s = os.str();
2169         SharedBuffer<u8> data((u8*)s.c_str(), s.size());
2170         // Send as reliable
2171         Send(0, data, true);
2172 }
2173
2174 void Client::sendChangePassword(const std::wstring oldpassword,
2175                 const std::wstring newpassword)
2176 {
2177         Player *player = m_env.getLocalPlayer();
2178         if(player == NULL)
2179                 return;
2180
2181         std::string playername = player->getName();
2182         std::string oldpwd = translatePassword(playername, oldpassword);
2183         std::string newpwd = translatePassword(playername, newpassword);
2184
2185         std::ostringstream os(std::ios_base::binary);
2186         u8 buf[2+PASSWORD_SIZE*2];
2187         /*
2188                 [0] u16 TOSERVER_PASSWORD
2189                 [2] u8[28] old password
2190                 [30] u8[28] new password
2191         */
2192
2193         writeU16(buf, TOSERVER_PASSWORD);
2194         for(u32 i=0;i<PASSWORD_SIZE-1;i++)
2195         {
2196                 buf[2+i] = i<oldpwd.length()?oldpwd[i]:0;
2197                 buf[30+i] = i<newpwd.length()?newpwd[i]:0;
2198         }
2199         buf[2+PASSWORD_SIZE-1] = 0;
2200         buf[30+PASSWORD_SIZE-1] = 0;
2201         os.write((char*)buf, 2+PASSWORD_SIZE*2);
2202
2203         // Make data buffer
2204         std::string s = os.str();
2205         SharedBuffer<u8> data((u8*)s.c_str(), s.size());
2206         // Send as reliable
2207         Send(0, data, true);
2208 }
2209
2210
2211 void Client::sendDamage(u8 damage)
2212 {
2213         DSTACK(__FUNCTION_NAME);
2214         std::ostringstream os(std::ios_base::binary);
2215
2216         writeU16(os, TOSERVER_DAMAGE);
2217         writeU8(os, damage);
2218
2219         // Make data buffer
2220         std::string s = os.str();
2221         SharedBuffer<u8> data((u8*)s.c_str(), s.size());
2222         // Send as reliable
2223         Send(0, data, true);
2224 }
2225
2226 void Client::sendBreath(u16 breath)
2227 {
2228         DSTACK(__FUNCTION_NAME);
2229         std::ostringstream os(std::ios_base::binary);
2230
2231         writeU16(os, TOSERVER_BREATH);
2232         writeU16(os, breath);
2233         // Make data buffer
2234         std::string s = os.str();
2235         SharedBuffer<u8> data((u8*)s.c_str(), s.size());
2236         // Send as reliable
2237         Send(0, data, true);
2238 }
2239
2240 void Client::sendRespawn()
2241 {
2242         DSTACK(__FUNCTION_NAME);
2243         std::ostringstream os(std::ios_base::binary);
2244
2245         writeU16(os, TOSERVER_RESPAWN);
2246
2247         // Make data buffer
2248         std::string s = os.str();
2249         SharedBuffer<u8> data((u8*)s.c_str(), s.size());
2250         // Send as reliable
2251         Send(0, data, true);
2252 }
2253
2254 void Client::sendPlayerPos()
2255 {
2256         //JMutexAutoLock envlock(m_env_mutex); //bulk comment-out
2257         
2258         LocalPlayer *myplayer = m_env.getLocalPlayer();
2259         if(myplayer == NULL)
2260                 return;
2261
2262         // Save bandwidth by only updating position when something changed
2263         if(myplayer->last_position == myplayer->getPosition() &&
2264                         myplayer->last_speed == myplayer->getSpeed() &&
2265                         myplayer->last_pitch == myplayer->getPitch() &&
2266                         myplayer->last_yaw == myplayer->getYaw() &&
2267                         myplayer->last_keyPressed == myplayer->keyPressed)
2268                 return;
2269
2270         myplayer->last_position = myplayer->getPosition();
2271         myplayer->last_speed = myplayer->getSpeed();
2272         myplayer->last_pitch = myplayer->getPitch();
2273         myplayer->last_yaw = myplayer->getYaw();
2274         myplayer->last_keyPressed = myplayer->keyPressed;
2275
2276         u16 our_peer_id;
2277         {
2278                 //JMutexAutoLock lock(m_con_mutex); //bulk comment-out
2279                 our_peer_id = m_con.GetPeerID();
2280         }
2281         
2282         // Set peer id if not set already
2283         if(myplayer->peer_id == PEER_ID_INEXISTENT)
2284                 myplayer->peer_id = our_peer_id;
2285         // Check that an existing peer_id is the same as the connection's
2286         assert(myplayer->peer_id == our_peer_id);
2287         
2288         v3f pf = myplayer->getPosition();
2289         v3s32 position(pf.X*100, pf.Y*100, pf.Z*100);
2290         v3f sf = myplayer->getSpeed();
2291         v3s32 speed(sf.X*100, sf.Y*100, sf.Z*100);
2292         s32 pitch = myplayer->getPitch() * 100;
2293         s32 yaw = myplayer->getYaw() * 100;
2294         u32 keyPressed=myplayer->keyPressed;
2295         /*
2296                 Format:
2297                 [0] u16 command
2298                 [2] v3s32 position*100
2299                 [2+12] v3s32 speed*100
2300                 [2+12+12] s32 pitch*100
2301                 [2+12+12+4] s32 yaw*100
2302                 [2+12+12+4+4] u32 keyPressed
2303         */
2304         SharedBuffer<u8> data(2+12+12+4+4+4);
2305         writeU16(&data[0], TOSERVER_PLAYERPOS);
2306         writeV3S32(&data[2], position);
2307         writeV3S32(&data[2+12], speed);
2308         writeS32(&data[2+12+12], pitch);
2309         writeS32(&data[2+12+12+4], yaw);
2310         writeU32(&data[2+12+12+4+4], keyPressed);
2311         // Send as unreliable
2312         Send(0, data, false);
2313 }
2314
2315 void Client::sendPlayerItem(u16 item)
2316 {
2317         Player *myplayer = m_env.getLocalPlayer();
2318         if(myplayer == NULL)
2319                 return;
2320
2321         u16 our_peer_id = m_con.GetPeerID();
2322
2323         // Set peer id if not set already
2324         if(myplayer->peer_id == PEER_ID_INEXISTENT)
2325                 myplayer->peer_id = our_peer_id;
2326         // Check that an existing peer_id is the same as the connection's
2327         assert(myplayer->peer_id == our_peer_id);
2328
2329         SharedBuffer<u8> data(2+2);
2330         writeU16(&data[0], TOSERVER_PLAYERITEM);
2331         writeU16(&data[2], item);
2332
2333         // Send as reliable
2334         Send(0, data, true);
2335 }
2336
2337 void Client::removeNode(v3s16 p)
2338 {
2339         std::map<v3s16, MapBlock*> modified_blocks;
2340
2341         try
2342         {
2343                 //TimeTaker t("removeNodeAndUpdate", m_device);
2344                 m_env.getMap().removeNodeAndUpdate(p, modified_blocks);
2345         }
2346         catch(InvalidPositionException &e)
2347         {
2348         }
2349         
2350         // add urgent task to update the modified node
2351         addUpdateMeshTaskForNode(p, false, true);
2352
2353         for(std::map<v3s16, MapBlock * >::iterator
2354                         i = modified_blocks.begin();
2355                         i != modified_blocks.end(); ++i)
2356         {
2357                 addUpdateMeshTaskWithEdge(i->first);
2358         }
2359 }
2360
2361 void Client::addNode(v3s16 p, MapNode n, bool remove_metadata)
2362 {
2363         TimeTaker timer1("Client::addNode()");
2364
2365         std::map<v3s16, MapBlock*> modified_blocks;
2366
2367         try
2368         {
2369                 //TimeTaker timer3("Client::addNode(): addNodeAndUpdate");
2370                 m_env.getMap().addNodeAndUpdate(p, n, modified_blocks, remove_metadata);
2371         }
2372         catch(InvalidPositionException &e)
2373         {}
2374         
2375         for(std::map<v3s16, MapBlock * >::iterator
2376                         i = modified_blocks.begin();
2377                         i != modified_blocks.end(); ++i)
2378         {
2379                 addUpdateMeshTaskWithEdge(i->first);
2380         }
2381 }
2382         
2383 void Client::setPlayerControl(PlayerControl &control)
2384 {
2385         //JMutexAutoLock envlock(m_env_mutex); //bulk comment-out
2386         LocalPlayer *player = m_env.getLocalPlayer();
2387         assert(player != NULL);
2388         player->control = control;
2389 }
2390
2391 void Client::selectPlayerItem(u16 item)
2392 {
2393         //JMutexAutoLock envlock(m_env_mutex); //bulk comment-out
2394         m_playeritem = item;
2395         m_inventory_updated = true;
2396         sendPlayerItem(item);
2397 }
2398
2399 // Returns true if the inventory of the local player has been
2400 // updated from the server. If it is true, it is set to false.
2401 bool Client::getLocalInventoryUpdated()
2402 {
2403         // m_inventory_updated is behind envlock
2404         //JMutexAutoLock envlock(m_env_mutex); //bulk comment-out
2405         bool updated = m_inventory_updated;
2406         m_inventory_updated = false;
2407         return updated;
2408 }
2409
2410 // Copies the inventory of the local player to parameter
2411 void Client::getLocalInventory(Inventory &dst)
2412 {
2413         //JMutexAutoLock envlock(m_env_mutex); //bulk comment-out
2414         Player *player = m_env.getLocalPlayer();
2415         assert(player != NULL);
2416         dst = player->inventory;
2417 }
2418
2419 Inventory* Client::getInventory(const InventoryLocation &loc)
2420 {
2421         switch(loc.type){
2422         case InventoryLocation::UNDEFINED:
2423         {}
2424         break;
2425         case InventoryLocation::CURRENT_PLAYER:
2426         {
2427                 Player *player = m_env.getLocalPlayer();
2428                 assert(player != NULL);
2429                 return &player->inventory;
2430         }
2431         break;
2432         case InventoryLocation::PLAYER:
2433         {
2434                 Player *player = m_env.getPlayer(loc.name.c_str());
2435                 if(!player)
2436                         return NULL;
2437                 return &player->inventory;
2438         }
2439         break;
2440         case InventoryLocation::NODEMETA:
2441         {
2442                 NodeMetadata *meta = m_env.getMap().getNodeMetadata(loc.p);
2443                 if(!meta)
2444                         return NULL;
2445                 return meta->getInventory();
2446         }
2447         break;
2448         case InventoryLocation::DETACHED:
2449         {
2450                 if(m_detached_inventories.count(loc.name) == 0)
2451                         return NULL;
2452                 return m_detached_inventories[loc.name];
2453         }
2454         break;
2455         default:
2456                 assert(0);
2457         }
2458         return NULL;
2459 }
2460 void Client::inventoryAction(InventoryAction *a)
2461 {
2462         /*
2463                 Send it to the server
2464         */
2465         sendInventoryAction(a);
2466
2467         /*
2468                 Predict some local inventory changes
2469         */
2470         a->clientApply(this, this);
2471
2472         // Remove it
2473         delete a;
2474 }
2475
2476 ClientActiveObject * Client::getSelectedActiveObject(
2477                 f32 max_d,
2478                 v3f from_pos_f_on_map,
2479                 core::line3d<f32> shootline_on_map
2480         )
2481 {
2482         std::vector<DistanceSortedActiveObject> objects;
2483
2484         m_env.getActiveObjects(from_pos_f_on_map, max_d, objects);
2485
2486         //infostream<<"Collected "<<objects.size()<<" nearby objects"<<std::endl;
2487         
2488         // Sort them.
2489         // After this, the closest object is the first in the array.
2490         std::sort(objects.begin(), objects.end());
2491
2492         for(u32 i=0; i<objects.size(); i++)
2493         {
2494                 ClientActiveObject *obj = objects[i].obj;
2495                 
2496                 core::aabbox3d<f32> *selection_box = obj->getSelectionBox();
2497                 if(selection_box == NULL)
2498                         continue;
2499
2500                 v3f pos = obj->getPosition();
2501
2502                 core::aabbox3d<f32> offsetted_box(
2503                                 selection_box->MinEdge + pos,
2504                                 selection_box->MaxEdge + pos
2505                 );
2506
2507                 if(offsetted_box.intersectsWithLine(shootline_on_map))
2508                 {
2509                         //infostream<<"Returning selected object"<<std::endl;
2510                         return obj;
2511                 }
2512         }
2513
2514         //infostream<<"No object selected; returning NULL."<<std::endl;
2515         return NULL;
2516 }
2517
2518 void Client::printDebugInfo(std::ostream &os)
2519 {
2520         //JMutexAutoLock lock1(m_fetchblock_mutex);
2521         /*JMutexAutoLock lock2(m_incoming_queue_mutex);
2522
2523         os<<"m_incoming_queue.getSize()="<<m_incoming_queue.getSize()
2524                 //<<", m_fetchblock_history.size()="<<m_fetchblock_history.size()
2525                 //<<", m_opt_not_found_history.size()="<<m_opt_not_found_history.size()
2526                 <<std::endl;*/
2527 }
2528
2529 std::list<std::string> Client::getConnectedPlayerNames()
2530 {
2531         return m_env.getPlayerNames();
2532 }
2533
2534 float Client::getAnimationTime()
2535 {
2536         return m_animation_time;
2537 }
2538
2539 int Client::getCrackLevel()
2540 {
2541         return m_crack_level;
2542 }
2543
2544 void Client::setCrack(int level, v3s16 pos)
2545 {
2546         int old_crack_level = m_crack_level;
2547         v3s16 old_crack_pos = m_crack_pos;
2548
2549         m_crack_level = level;
2550         m_crack_pos = pos;
2551
2552         if(old_crack_level >= 0 && (level < 0 || pos != old_crack_pos))
2553         {
2554                 // remove old crack
2555                 addUpdateMeshTaskForNode(old_crack_pos, false, true);
2556         }
2557         if(level >= 0 && (old_crack_level < 0 || pos != old_crack_pos))
2558         {
2559                 // add new crack
2560                 addUpdateMeshTaskForNode(pos, false, true);
2561         }
2562 }
2563
2564 u16 Client::getHP()
2565 {
2566         Player *player = m_env.getLocalPlayer();
2567         assert(player != NULL);
2568         return player->hp;
2569 }
2570
2571 u16 Client::getBreath()
2572 {
2573         Player *player = m_env.getLocalPlayer();
2574         assert(player != NULL);
2575         return player->getBreath();
2576 }
2577
2578 bool Client::getChatMessage(std::wstring &message)
2579 {
2580         if(m_chat_queue.size() == 0)
2581                 return false;
2582         message = m_chat_queue.pop_front();
2583         return true;
2584 }
2585
2586 void Client::typeChatMessage(const std::wstring &message)
2587 {
2588         // Discard empty line
2589         if(message == L"")
2590                 return;
2591
2592         // Send to others
2593         sendChatMessage(message);
2594
2595         // Show locally
2596         if (message[0] == L'/')
2597         {
2598                 m_chat_queue.push_back(
2599                                 (std::wstring)L"issued command: "+message);
2600         }
2601         else
2602         {
2603                 LocalPlayer *player = m_env.getLocalPlayer();
2604                 assert(player != NULL);
2605                 std::wstring name = narrow_to_wide(player->getName());
2606                 m_chat_queue.push_back(
2607                                 (std::wstring)L"<"+name+L"> "+message);
2608         }
2609 }
2610
2611 void Client::addUpdateMeshTask(v3s16 p, bool ack_to_server, bool urgent)
2612 {
2613         /*infostream<<"Client::addUpdateMeshTask(): "
2614                         <<"("<<p.X<<","<<p.Y<<","<<p.Z<<")"
2615                         <<" ack_to_server="<<ack_to_server
2616                         <<" urgent="<<urgent
2617                         <<std::endl;*/
2618
2619         MapBlock *b = m_env.getMap().getBlockNoCreateNoEx(p);
2620         if(b == NULL)
2621                 return;
2622         
2623         /*
2624                 Create a task to update the mesh of the block
2625         */
2626         
2627         MeshMakeData *data = new MeshMakeData(this);
2628         
2629         {
2630                 //TimeTaker timer("data fill");
2631                 // Release: ~0ms
2632                 // Debug: 1-6ms, avg=2ms
2633                 data->fill(b);
2634                 data->setCrack(m_crack_level, m_crack_pos);
2635                 data->setSmoothLighting(g_settings->getBool("smooth_lighting"));
2636         }
2637
2638         // Debug wait
2639         //while(m_mesh_update_thread.m_queue_in.size() > 0) sleep_ms(10);
2640         
2641         // Add task to queue
2642         m_mesh_update_thread.m_queue_in.addBlock(p, data, ack_to_server, urgent);
2643
2644         /*infostream<<"Mesh update input queue size is "
2645                         <<m_mesh_update_thread.m_queue_in.size()
2646                         <<std::endl;*/
2647 }
2648
2649 void Client::addUpdateMeshTaskWithEdge(v3s16 blockpos, bool ack_to_server, bool urgent)
2650 {
2651         /*{
2652                 v3s16 p = blockpos;
2653                 infostream<<"Client::addUpdateMeshTaskWithEdge(): "
2654                                 <<"("<<p.X<<","<<p.Y<<","<<p.Z<<")"
2655                                 <<std::endl;
2656         }*/
2657
2658         try{
2659                 v3s16 p = blockpos + v3s16(0,0,0);
2660                 //MapBlock *b = m_env.getMap().getBlockNoCreate(p);
2661                 addUpdateMeshTask(p, ack_to_server, urgent);
2662         }
2663         catch(InvalidPositionException &e){}
2664         // Leading edge
2665         for (int i=0;i<6;i++)
2666         {
2667                 try{
2668                         v3s16 p = blockpos + g_6dirs[i];
2669                         addUpdateMeshTask(p, false, urgent);
2670                 }
2671                 catch(InvalidPositionException &e){}
2672         }
2673 }
2674
2675 void Client::addUpdateMeshTaskForNode(v3s16 nodepos, bool ack_to_server, bool urgent)
2676 {
2677         {
2678                 v3s16 p = nodepos;
2679                 infostream<<"Client::addUpdateMeshTaskForNode(): "
2680                                 <<"("<<p.X<<","<<p.Y<<","<<p.Z<<")"
2681                                 <<std::endl;
2682         }
2683
2684         v3s16 blockpos = getNodeBlockPos(nodepos);
2685         v3s16 blockpos_relative = blockpos * MAP_BLOCKSIZE;
2686
2687         try{
2688                 v3s16 p = blockpos + v3s16(0,0,0);
2689                 addUpdateMeshTask(p, ack_to_server, urgent);
2690         }
2691         catch(InvalidPositionException &e){}
2692         // Leading edge
2693         if(nodepos.X == blockpos_relative.X){
2694                 try{
2695                         v3s16 p = blockpos + v3s16(-1,0,0);
2696                         addUpdateMeshTask(p, false, urgent);
2697                 }
2698                 catch(InvalidPositionException &e){}
2699         }
2700         if(nodepos.Y == blockpos_relative.Y){
2701                 try{
2702                         v3s16 p = blockpos + v3s16(0,-1,0);
2703                         addUpdateMeshTask(p, false, urgent);
2704                 }
2705                 catch(InvalidPositionException &e){}
2706         }
2707         if(nodepos.Z == blockpos_relative.Z){
2708                 try{
2709                         v3s16 p = blockpos + v3s16(0,0,-1);
2710                         addUpdateMeshTask(p, false, urgent);
2711                 }
2712                 catch(InvalidPositionException &e){}
2713         }
2714 }
2715
2716 ClientEvent Client::getClientEvent()
2717 {
2718         if(m_client_event_queue.size() == 0)
2719         {
2720                 ClientEvent event;
2721                 event.type = CE_NONE;
2722                 return event;
2723         }
2724         return m_client_event_queue.pop_front();
2725 }
2726
2727 float Client::mediaReceiveProgress()
2728 {
2729         if (m_media_downloader)
2730                 return m_media_downloader->getProgress();
2731         else
2732                 return 1.0; // downloader only exists when not yet done
2733 }
2734
2735 void draw_load_screen(const std::wstring &text,
2736                 IrrlichtDevice* device, gui::IGUIFont* font,
2737                 float dtime=0 ,int percent=0, bool clouds=true);
2738 void Client::afterContentReceived(IrrlichtDevice *device, gui::IGUIFont* font)
2739 {
2740         infostream<<"Client::afterContentReceived() started"<<std::endl;
2741         assert(m_itemdef_received);
2742         assert(m_nodedef_received);
2743         assert(mediaReceived());
2744         
2745         // Rebuild inherited images and recreate textures
2746         infostream<<"- Rebuilding images and textures"<<std::endl;
2747         m_tsrc->rebuildImagesAndTextures();
2748
2749         // Rebuild shaders
2750         infostream<<"- Rebuilding shaders"<<std::endl;
2751         m_shsrc->rebuildShaders();
2752
2753         // Update node aliases
2754         infostream<<"- Updating node aliases"<<std::endl;
2755         m_nodedef->updateAliases(m_itemdef);
2756
2757         // Update node textures
2758         infostream<<"- Updating node textures"<<std::endl;
2759         m_nodedef->updateTextures(m_tsrc);
2760
2761         // Preload item textures and meshes if configured to
2762         if(g_settings->getBool("preload_item_visuals"))
2763         {
2764                 verbosestream<<"Updating item textures and meshes"<<std::endl;
2765                 wchar_t* text = wgettext("Item textures...");
2766                 draw_load_screen(text,device,font,0,0);
2767                 std::set<std::string> names = m_itemdef->getAll();
2768                 size_t size = names.size();
2769                 size_t count = 0;
2770                 int percent = 0;
2771                 for(std::set<std::string>::const_iterator
2772                                 i = names.begin(); i != names.end(); ++i){
2773                         // Asking for these caches the result
2774                         m_itemdef->getInventoryTexture(*i, this);
2775                         m_itemdef->getWieldMesh(*i, this);
2776                         count++;
2777                         percent = count*100/size;
2778                         if (count%50 == 0) // only update every 50 item
2779                                 draw_load_screen(text,device,font,0,percent);
2780                 }
2781                 delete[] text;
2782         }
2783
2784         // Start mesh update thread after setting up content definitions
2785         infostream<<"- Starting mesh update thread"<<std::endl;
2786         m_mesh_update_thread.Start();
2787         
2788         infostream<<"Client::afterContentReceived() done"<<std::endl;
2789 }
2790
2791 float Client::getRTT(void)
2792 {
2793         try{
2794                 return m_con.GetPeerAvgRTT(PEER_ID_SERVER);
2795         } catch(con::PeerNotFoundException &e){
2796                 return 1337;
2797         }
2798 }
2799
2800 // IGameDef interface
2801 // Under envlock
2802 IItemDefManager* Client::getItemDefManager()
2803 {
2804         return m_itemdef;
2805 }
2806 INodeDefManager* Client::getNodeDefManager()
2807 {
2808         return m_nodedef;
2809 }
2810 ICraftDefManager* Client::getCraftDefManager()
2811 {
2812         return NULL;
2813         //return m_craftdef;
2814 }
2815 ITextureSource* Client::getTextureSource()
2816 {
2817         return m_tsrc;
2818 }
2819 IShaderSource* Client::getShaderSource()
2820 {
2821         return m_shsrc;
2822 }
2823 u16 Client::allocateUnknownNodeId(const std::string &name)
2824 {
2825         errorstream<<"Client::allocateUnknownNodeId(): "
2826                         <<"Client cannot allocate node IDs"<<std::endl;
2827         assert(0);
2828         return CONTENT_IGNORE;
2829 }
2830 ISoundManager* Client::getSoundManager()
2831 {
2832         return m_sound;
2833 }
2834 MtEventManager* Client::getEventManager()
2835 {
2836         return m_event;
2837 }
2838