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