]> git.lizzy.rs Git - minetest.git/blob - src/client.cpp
New HUD element - waypoint.
[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                 v3f world_pos;
1945                 try{
1946                         world_pos    = readV3F1000(is);
1947                 }catch(SerializationError &e) {};
1948
1949                 ClientEvent event;
1950                 event.type = CE_HUDADD;
1951                 event.hudadd.id     = id;
1952                 event.hudadd.type   = type;
1953                 event.hudadd.pos    = new v2f(pos);
1954                 event.hudadd.name   = new std::string(name);
1955                 event.hudadd.scale  = new v2f(scale);
1956                 event.hudadd.text   = new std::string(text);
1957                 event.hudadd.number = number;
1958                 event.hudadd.item   = item;
1959                 event.hudadd.dir    = dir;
1960                 event.hudadd.align  = new v2f(align);
1961                 event.hudadd.offset = new v2f(offset);
1962                 event.hudadd.world_pos = new v3f(world_pos);
1963                 m_client_event_queue.push_back(event);
1964         }
1965         else if(command == TOCLIENT_HUDRM)
1966         {
1967                 std::string datastring((char *)&data[2], datasize - 2);
1968                 std::istringstream is(datastring, std::ios_base::binary);
1969
1970                 u32 id = readU32(is);
1971
1972                 ClientEvent event;
1973                 event.type = CE_HUDRM;
1974                 event.hudrm.id = id;
1975                 m_client_event_queue.push_back(event);
1976         }
1977         else if(command == TOCLIENT_HUDCHANGE)
1978         {
1979                 std::string sdata;
1980                 v2f v2fdata;
1981                 v3f v3fdata;
1982                 u32 intdata = 0;
1983                 
1984                 std::string datastring((char *)&data[2], datasize - 2);
1985                 std::istringstream is(datastring, std::ios_base::binary);
1986
1987                 u32 id  = readU32(is);
1988                 u8 stat = (HudElementStat)readU8(is);
1989                 
1990                 if (stat == HUD_STAT_POS || stat == HUD_STAT_SCALE ||
1991                         stat == HUD_STAT_ALIGN || stat == HUD_STAT_OFFSET)
1992                         v2fdata = readV2F1000(is);
1993                 else if (stat == HUD_STAT_NAME || stat == HUD_STAT_TEXT)
1994                         sdata = deSerializeString(is);
1995                 else if (stat == HUD_STAT_WORLD_POS)
1996                         v3fdata = readV3F1000(is);
1997                 else
1998                         intdata = readU32(is);
1999                 
2000                 ClientEvent event;
2001                 event.type = CE_HUDCHANGE;
2002                 event.hudchange.id      = id;
2003                 event.hudchange.stat    = (HudElementStat)stat;
2004                 event.hudchange.v2fdata = new v2f(v2fdata);
2005                 event.hudchange.v3fdata = new v3f(v3fdata);
2006                 event.hudchange.sdata   = new std::string(sdata);
2007                 event.hudchange.data    = intdata;
2008                 m_client_event_queue.push_back(event);
2009         }
2010         else if(command == TOCLIENT_HUD_SET_FLAGS)
2011         {
2012                 std::string datastring((char *)&data[2], datasize - 2);
2013                 std::istringstream is(datastring, std::ios_base::binary);
2014
2015                 Player *player = m_env.getLocalPlayer();
2016                 assert(player != NULL);
2017
2018                 u32 flags = readU32(is);
2019                 u32 mask  = readU32(is);
2020                 
2021                 player->hud_flags &= ~mask;
2022                 player->hud_flags |= flags;
2023         }
2024         else if(command == TOCLIENT_HUD_SET_PARAM)
2025         {
2026                 std::string datastring((char *)&data[2], datasize - 2);
2027                 std::istringstream is(datastring, std::ios_base::binary);
2028
2029                 Player *player = m_env.getLocalPlayer();
2030                 assert(player != NULL);
2031
2032                 u16 param         = readU16(is);
2033                 std::string value = deSerializeString(is);
2034
2035                 if(param == HUD_PARAM_HOTBAR_ITEMCOUNT && value.size() == 4){
2036                         s32 hotbar_itemcount = readS32((u8*) value.c_str());
2037                         if(hotbar_itemcount > 0 && hotbar_itemcount <= HUD_HOTBAR_ITEMCOUNT_MAX)
2038                                 player->hud_hotbar_itemcount = hotbar_itemcount;
2039                 } else if (param == HUD_PARAM_HOTBAR_IMAGE) {
2040                         ((LocalPlayer *) player)->hotbar_image = value;
2041                 } else if (param == HUD_PARAM_HOTBAR_SELECTED_IMAGE) {
2042                         ((LocalPlayer *) player)->hotbar_selected_image = value;
2043                 }
2044         }
2045         else
2046         {
2047                 infostream<<"Client: Ignoring unknown command "
2048                                 <<command<<std::endl;
2049         }
2050 }
2051
2052 void Client::Send(u16 channelnum, SharedBuffer<u8> data, bool reliable)
2053 {
2054         //JMutexAutoLock lock(m_con_mutex); //bulk comment-out
2055         m_con.Send(PEER_ID_SERVER, channelnum, data, reliable);
2056 }
2057
2058 void Client::interact(u8 action, const PointedThing& pointed)
2059 {
2060         if(connectedAndInitialized() == false){
2061                 infostream<<"Client::interact() "
2062                                 "cancelled (not connected)"
2063                                 <<std::endl;
2064                 return;
2065         }
2066
2067         std::ostringstream os(std::ios_base::binary);
2068
2069         /*
2070                 [0] u16 command
2071                 [2] u8 action
2072                 [3] u16 item
2073                 [5] u32 length of the next item
2074                 [9] serialized PointedThing
2075                 actions:
2076                 0: start digging (from undersurface) or use
2077                 1: stop digging (all parameters ignored)
2078                 2: digging completed
2079                 3: place block or item (to abovesurface)
2080                 4: use item
2081         */
2082         writeU16(os, TOSERVER_INTERACT);
2083         writeU8(os, action);
2084         writeU16(os, getPlayerItem());
2085         std::ostringstream tmp_os(std::ios::binary);
2086         pointed.serialize(tmp_os);
2087         os<<serializeLongString(tmp_os.str());
2088
2089         std::string s = os.str();
2090         SharedBuffer<u8> data((u8*)s.c_str(), s.size());
2091
2092         // Send as reliable
2093         Send(0, data, true);
2094 }
2095
2096 void Client::sendNodemetaFields(v3s16 p, const std::string &formname,
2097                 const std::map<std::string, std::string> &fields)
2098 {
2099         std::ostringstream os(std::ios_base::binary);
2100
2101         writeU16(os, TOSERVER_NODEMETA_FIELDS);
2102         writeV3S16(os, p);
2103         os<<serializeString(formname);
2104         writeU16(os, fields.size());
2105         for(std::map<std::string, std::string>::const_iterator
2106                         i = fields.begin(); i != fields.end(); i++){
2107                 const std::string &name = i->first;
2108                 const std::string &value = i->second;
2109                 os<<serializeString(name);
2110                 os<<serializeLongString(value);
2111         }
2112
2113         // Make data buffer
2114         std::string s = os.str();
2115         SharedBuffer<u8> data((u8*)s.c_str(), s.size());
2116         // Send as reliable
2117         Send(0, data, true);
2118 }
2119         
2120 void Client::sendInventoryFields(const std::string &formname,
2121                 const std::map<std::string, std::string> &fields)
2122 {
2123         std::ostringstream os(std::ios_base::binary);
2124
2125         writeU16(os, TOSERVER_INVENTORY_FIELDS);
2126         os<<serializeString(formname);
2127         writeU16(os, fields.size());
2128         for(std::map<std::string, std::string>::const_iterator
2129                         i = fields.begin(); i != fields.end(); i++){
2130                 const std::string &name = i->first;
2131                 const std::string &value = i->second;
2132                 os<<serializeString(name);
2133                 os<<serializeLongString(value);
2134         }
2135
2136         // Make data buffer
2137         std::string s = os.str();
2138         SharedBuffer<u8> data((u8*)s.c_str(), s.size());
2139         // Send as reliable
2140         Send(0, data, true);
2141 }
2142
2143 void Client::sendInventoryAction(InventoryAction *a)
2144 {
2145         std::ostringstream os(std::ios_base::binary);
2146         u8 buf[12];
2147         
2148         // Write command
2149         writeU16(buf, TOSERVER_INVENTORY_ACTION);
2150         os.write((char*)buf, 2);
2151
2152         a->serialize(os);
2153         
2154         // Make data buffer
2155         std::string s = os.str();
2156         SharedBuffer<u8> data((u8*)s.c_str(), s.size());
2157         // Send as reliable
2158         Send(0, data, true);
2159 }
2160
2161 void Client::sendChatMessage(const std::wstring &message)
2162 {
2163         std::ostringstream os(std::ios_base::binary);
2164         u8 buf[12];
2165         
2166         // Write command
2167         writeU16(buf, TOSERVER_CHAT_MESSAGE);
2168         os.write((char*)buf, 2);
2169         
2170         // Write length
2171         writeU16(buf, message.size());
2172         os.write((char*)buf, 2);
2173         
2174         // Write string
2175         for(u32 i=0; i<message.size(); i++)
2176         {
2177                 u16 w = message[i];
2178                 writeU16(buf, w);
2179                 os.write((char*)buf, 2);
2180         }
2181         
2182         // Make data buffer
2183         std::string s = os.str();
2184         SharedBuffer<u8> data((u8*)s.c_str(), s.size());
2185         // Send as reliable
2186         Send(0, data, true);
2187 }
2188
2189 void Client::sendChangePassword(const std::wstring oldpassword,
2190                 const std::wstring newpassword)
2191 {
2192         Player *player = m_env.getLocalPlayer();
2193         if(player == NULL)
2194                 return;
2195
2196         std::string playername = player->getName();
2197         std::string oldpwd = translatePassword(playername, oldpassword);
2198         std::string newpwd = translatePassword(playername, newpassword);
2199
2200         std::ostringstream os(std::ios_base::binary);
2201         u8 buf[2+PASSWORD_SIZE*2];
2202         /*
2203                 [0] u16 TOSERVER_PASSWORD
2204                 [2] u8[28] old password
2205                 [30] u8[28] new password
2206         */
2207
2208         writeU16(buf, TOSERVER_PASSWORD);
2209         for(u32 i=0;i<PASSWORD_SIZE-1;i++)
2210         {
2211                 buf[2+i] = i<oldpwd.length()?oldpwd[i]:0;
2212                 buf[30+i] = i<newpwd.length()?newpwd[i]:0;
2213         }
2214         buf[2+PASSWORD_SIZE-1] = 0;
2215         buf[30+PASSWORD_SIZE-1] = 0;
2216         os.write((char*)buf, 2+PASSWORD_SIZE*2);
2217
2218         // Make data buffer
2219         std::string s = os.str();
2220         SharedBuffer<u8> data((u8*)s.c_str(), s.size());
2221         // Send as reliable
2222         Send(0, data, true);
2223 }
2224
2225
2226 void Client::sendDamage(u8 damage)
2227 {
2228         DSTACK(__FUNCTION_NAME);
2229         std::ostringstream os(std::ios_base::binary);
2230
2231         writeU16(os, TOSERVER_DAMAGE);
2232         writeU8(os, damage);
2233
2234         // Make data buffer
2235         std::string s = os.str();
2236         SharedBuffer<u8> data((u8*)s.c_str(), s.size());
2237         // Send as reliable
2238         Send(0, data, true);
2239 }
2240
2241 void Client::sendBreath(u16 breath)
2242 {
2243         DSTACK(__FUNCTION_NAME);
2244         std::ostringstream os(std::ios_base::binary);
2245
2246         writeU16(os, TOSERVER_BREATH);
2247         writeU16(os, breath);
2248         // Make data buffer
2249         std::string s = os.str();
2250         SharedBuffer<u8> data((u8*)s.c_str(), s.size());
2251         // Send as reliable
2252         Send(0, data, true);
2253 }
2254
2255 void Client::sendRespawn()
2256 {
2257         DSTACK(__FUNCTION_NAME);
2258         std::ostringstream os(std::ios_base::binary);
2259
2260         writeU16(os, TOSERVER_RESPAWN);
2261
2262         // Make data buffer
2263         std::string s = os.str();
2264         SharedBuffer<u8> data((u8*)s.c_str(), s.size());
2265         // Send as reliable
2266         Send(0, data, true);
2267 }
2268
2269 void Client::sendPlayerPos()
2270 {
2271         //JMutexAutoLock envlock(m_env_mutex); //bulk comment-out
2272         
2273         LocalPlayer *myplayer = m_env.getLocalPlayer();
2274         if(myplayer == NULL)
2275                 return;
2276
2277         // Save bandwidth by only updating position when something changed
2278         if(myplayer->last_position == myplayer->getPosition() &&
2279                         myplayer->last_speed == myplayer->getSpeed() &&
2280                         myplayer->last_pitch == myplayer->getPitch() &&
2281                         myplayer->last_yaw == myplayer->getYaw() &&
2282                         myplayer->last_keyPressed == myplayer->keyPressed)
2283                 return;
2284
2285         myplayer->last_position = myplayer->getPosition();
2286         myplayer->last_speed = myplayer->getSpeed();
2287         myplayer->last_pitch = myplayer->getPitch();
2288         myplayer->last_yaw = myplayer->getYaw();
2289         myplayer->last_keyPressed = myplayer->keyPressed;
2290
2291         u16 our_peer_id;
2292         {
2293                 //JMutexAutoLock lock(m_con_mutex); //bulk comment-out
2294                 our_peer_id = m_con.GetPeerID();
2295         }
2296         
2297         // Set peer id if not set already
2298         if(myplayer->peer_id == PEER_ID_INEXISTENT)
2299                 myplayer->peer_id = our_peer_id;
2300         // Check that an existing peer_id is the same as the connection's
2301         assert(myplayer->peer_id == our_peer_id);
2302         
2303         v3f pf = myplayer->getPosition();
2304         v3s32 position(pf.X*100, pf.Y*100, pf.Z*100);
2305         v3f sf = myplayer->getSpeed();
2306         v3s32 speed(sf.X*100, sf.Y*100, sf.Z*100);
2307         s32 pitch = myplayer->getPitch() * 100;
2308         s32 yaw = myplayer->getYaw() * 100;
2309         u32 keyPressed=myplayer->keyPressed;
2310         /*
2311                 Format:
2312                 [0] u16 command
2313                 [2] v3s32 position*100
2314                 [2+12] v3s32 speed*100
2315                 [2+12+12] s32 pitch*100
2316                 [2+12+12+4] s32 yaw*100
2317                 [2+12+12+4+4] u32 keyPressed
2318         */
2319         SharedBuffer<u8> data(2+12+12+4+4+4);
2320         writeU16(&data[0], TOSERVER_PLAYERPOS);
2321         writeV3S32(&data[2], position);
2322         writeV3S32(&data[2+12], speed);
2323         writeS32(&data[2+12+12], pitch);
2324         writeS32(&data[2+12+12+4], yaw);
2325         writeU32(&data[2+12+12+4+4], keyPressed);
2326         // Send as unreliable
2327         Send(0, data, false);
2328 }
2329
2330 void Client::sendPlayerItem(u16 item)
2331 {
2332         Player *myplayer = m_env.getLocalPlayer();
2333         if(myplayer == NULL)
2334                 return;
2335
2336         u16 our_peer_id = m_con.GetPeerID();
2337
2338         // Set peer id if not set already
2339         if(myplayer->peer_id == PEER_ID_INEXISTENT)
2340                 myplayer->peer_id = our_peer_id;
2341         // Check that an existing peer_id is the same as the connection's
2342         assert(myplayer->peer_id == our_peer_id);
2343
2344         SharedBuffer<u8> data(2+2);
2345         writeU16(&data[0], TOSERVER_PLAYERITEM);
2346         writeU16(&data[2], item);
2347
2348         // Send as reliable
2349         Send(0, data, true);
2350 }
2351
2352 void Client::removeNode(v3s16 p)
2353 {
2354         std::map<v3s16, MapBlock*> modified_blocks;
2355
2356         try
2357         {
2358                 //TimeTaker t("removeNodeAndUpdate", m_device);
2359                 m_env.getMap().removeNodeAndUpdate(p, modified_blocks);
2360         }
2361         catch(InvalidPositionException &e)
2362         {
2363         }
2364         
2365         // add urgent task to update the modified node
2366         addUpdateMeshTaskForNode(p, false, true);
2367
2368         for(std::map<v3s16, MapBlock * >::iterator
2369                         i = modified_blocks.begin();
2370                         i != modified_blocks.end(); ++i)
2371         {
2372                 addUpdateMeshTaskWithEdge(i->first);
2373         }
2374 }
2375
2376 void Client::addNode(v3s16 p, MapNode n, bool remove_metadata)
2377 {
2378         TimeTaker timer1("Client::addNode()");
2379
2380         std::map<v3s16, MapBlock*> modified_blocks;
2381
2382         try
2383         {
2384                 //TimeTaker timer3("Client::addNode(): addNodeAndUpdate");
2385                 m_env.getMap().addNodeAndUpdate(p, n, modified_blocks, remove_metadata);
2386         }
2387         catch(InvalidPositionException &e)
2388         {}
2389         
2390         for(std::map<v3s16, MapBlock * >::iterator
2391                         i = modified_blocks.begin();
2392                         i != modified_blocks.end(); ++i)
2393         {
2394                 addUpdateMeshTaskWithEdge(i->first);
2395         }
2396 }
2397         
2398 void Client::setPlayerControl(PlayerControl &control)
2399 {
2400         //JMutexAutoLock envlock(m_env_mutex); //bulk comment-out
2401         LocalPlayer *player = m_env.getLocalPlayer();
2402         assert(player != NULL);
2403         player->control = control;
2404 }
2405
2406 void Client::selectPlayerItem(u16 item)
2407 {
2408         //JMutexAutoLock envlock(m_env_mutex); //bulk comment-out
2409         m_playeritem = item;
2410         m_inventory_updated = true;
2411         sendPlayerItem(item);
2412 }
2413
2414 // Returns true if the inventory of the local player has been
2415 // updated from the server. If it is true, it is set to false.
2416 bool Client::getLocalInventoryUpdated()
2417 {
2418         // m_inventory_updated is behind envlock
2419         //JMutexAutoLock envlock(m_env_mutex); //bulk comment-out
2420         bool updated = m_inventory_updated;
2421         m_inventory_updated = false;
2422         return updated;
2423 }
2424
2425 // Copies the inventory of the local player to parameter
2426 void Client::getLocalInventory(Inventory &dst)
2427 {
2428         //JMutexAutoLock envlock(m_env_mutex); //bulk comment-out
2429         Player *player = m_env.getLocalPlayer();
2430         assert(player != NULL);
2431         dst = player->inventory;
2432 }
2433
2434 Inventory* Client::getInventory(const InventoryLocation &loc)
2435 {
2436         switch(loc.type){
2437         case InventoryLocation::UNDEFINED:
2438         {}
2439         break;
2440         case InventoryLocation::CURRENT_PLAYER:
2441         {
2442                 Player *player = m_env.getLocalPlayer();
2443                 assert(player != NULL);
2444                 return &player->inventory;
2445         }
2446         break;
2447         case InventoryLocation::PLAYER:
2448         {
2449                 Player *player = m_env.getPlayer(loc.name.c_str());
2450                 if(!player)
2451                         return NULL;
2452                 return &player->inventory;
2453         }
2454         break;
2455         case InventoryLocation::NODEMETA:
2456         {
2457                 NodeMetadata *meta = m_env.getMap().getNodeMetadata(loc.p);
2458                 if(!meta)
2459                         return NULL;
2460                 return meta->getInventory();
2461         }
2462         break;
2463         case InventoryLocation::DETACHED:
2464         {
2465                 if(m_detached_inventories.count(loc.name) == 0)
2466                         return NULL;
2467                 return m_detached_inventories[loc.name];
2468         }
2469         break;
2470         default:
2471                 assert(0);
2472         }
2473         return NULL;
2474 }
2475 void Client::inventoryAction(InventoryAction *a)
2476 {
2477         /*
2478                 Send it to the server
2479         */
2480         sendInventoryAction(a);
2481
2482         /*
2483                 Predict some local inventory changes
2484         */
2485         a->clientApply(this, this);
2486
2487         // Remove it
2488         delete a;
2489 }
2490
2491 ClientActiveObject * Client::getSelectedActiveObject(
2492                 f32 max_d,
2493                 v3f from_pos_f_on_map,
2494                 core::line3d<f32> shootline_on_map
2495         )
2496 {
2497         std::vector<DistanceSortedActiveObject> objects;
2498
2499         m_env.getActiveObjects(from_pos_f_on_map, max_d, objects);
2500
2501         //infostream<<"Collected "<<objects.size()<<" nearby objects"<<std::endl;
2502         
2503         // Sort them.
2504         // After this, the closest object is the first in the array.
2505         std::sort(objects.begin(), objects.end());
2506
2507         for(u32 i=0; i<objects.size(); i++)
2508         {
2509                 ClientActiveObject *obj = objects[i].obj;
2510                 
2511                 core::aabbox3d<f32> *selection_box = obj->getSelectionBox();
2512                 if(selection_box == NULL)
2513                         continue;
2514
2515                 v3f pos = obj->getPosition();
2516
2517                 core::aabbox3d<f32> offsetted_box(
2518                                 selection_box->MinEdge + pos,
2519                                 selection_box->MaxEdge + pos
2520                 );
2521
2522                 if(offsetted_box.intersectsWithLine(shootline_on_map))
2523                 {
2524                         //infostream<<"Returning selected object"<<std::endl;
2525                         return obj;
2526                 }
2527         }
2528
2529         //infostream<<"No object selected; returning NULL."<<std::endl;
2530         return NULL;
2531 }
2532
2533 void Client::printDebugInfo(std::ostream &os)
2534 {
2535         //JMutexAutoLock lock1(m_fetchblock_mutex);
2536         /*JMutexAutoLock lock2(m_incoming_queue_mutex);
2537
2538         os<<"m_incoming_queue.getSize()="<<m_incoming_queue.getSize()
2539                 //<<", m_fetchblock_history.size()="<<m_fetchblock_history.size()
2540                 //<<", m_opt_not_found_history.size()="<<m_opt_not_found_history.size()
2541                 <<std::endl;*/
2542 }
2543
2544 std::list<std::string> Client::getConnectedPlayerNames()
2545 {
2546         return m_env.getPlayerNames();
2547 }
2548
2549 float Client::getAnimationTime()
2550 {
2551         return m_animation_time;
2552 }
2553
2554 int Client::getCrackLevel()
2555 {
2556         return m_crack_level;
2557 }
2558
2559 void Client::setCrack(int level, v3s16 pos)
2560 {
2561         int old_crack_level = m_crack_level;
2562         v3s16 old_crack_pos = m_crack_pos;
2563
2564         m_crack_level = level;
2565         m_crack_pos = pos;
2566
2567         if(old_crack_level >= 0 && (level < 0 || pos != old_crack_pos))
2568         {
2569                 // remove old crack
2570                 addUpdateMeshTaskForNode(old_crack_pos, false, true);
2571         }
2572         if(level >= 0 && (old_crack_level < 0 || pos != old_crack_pos))
2573         {
2574                 // add new crack
2575                 addUpdateMeshTaskForNode(pos, false, true);
2576         }
2577 }
2578
2579 u16 Client::getHP()
2580 {
2581         Player *player = m_env.getLocalPlayer();
2582         assert(player != NULL);
2583         return player->hp;
2584 }
2585
2586 u16 Client::getBreath()
2587 {
2588         Player *player = m_env.getLocalPlayer();
2589         assert(player != NULL);
2590         return player->getBreath();
2591 }
2592
2593 bool Client::getChatMessage(std::wstring &message)
2594 {
2595         if(m_chat_queue.size() == 0)
2596                 return false;
2597         message = m_chat_queue.pop_front();
2598         return true;
2599 }
2600
2601 void Client::typeChatMessage(const std::wstring &message)
2602 {
2603         // Discard empty line
2604         if(message == L"")
2605                 return;
2606
2607         // Send to others
2608         sendChatMessage(message);
2609
2610         // Show locally
2611         if (message[0] == L'/')
2612         {
2613                 m_chat_queue.push_back(
2614                                 (std::wstring)L"issued command: "+message);
2615         }
2616         else
2617         {
2618                 LocalPlayer *player = m_env.getLocalPlayer();
2619                 assert(player != NULL);
2620                 std::wstring name = narrow_to_wide(player->getName());
2621                 m_chat_queue.push_back(
2622                                 (std::wstring)L"<"+name+L"> "+message);
2623         }
2624 }
2625
2626 void Client::addUpdateMeshTask(v3s16 p, bool ack_to_server, bool urgent)
2627 {
2628         /*infostream<<"Client::addUpdateMeshTask(): "
2629                         <<"("<<p.X<<","<<p.Y<<","<<p.Z<<")"
2630                         <<" ack_to_server="<<ack_to_server
2631                         <<" urgent="<<urgent
2632                         <<std::endl;*/
2633
2634         MapBlock *b = m_env.getMap().getBlockNoCreateNoEx(p);
2635         if(b == NULL)
2636                 return;
2637         
2638         /*
2639                 Create a task to update the mesh of the block
2640         */
2641         
2642         MeshMakeData *data = new MeshMakeData(this);
2643         
2644         {
2645                 //TimeTaker timer("data fill");
2646                 // Release: ~0ms
2647                 // Debug: 1-6ms, avg=2ms
2648                 data->fill(b);
2649                 data->setCrack(m_crack_level, m_crack_pos);
2650                 data->setSmoothLighting(g_settings->getBool("smooth_lighting"));
2651         }
2652
2653         // Debug wait
2654         //while(m_mesh_update_thread.m_queue_in.size() > 0) sleep_ms(10);
2655         
2656         // Add task to queue
2657         m_mesh_update_thread.m_queue_in.addBlock(p, data, ack_to_server, urgent);
2658
2659         /*infostream<<"Mesh update input queue size is "
2660                         <<m_mesh_update_thread.m_queue_in.size()
2661                         <<std::endl;*/
2662 }
2663
2664 void Client::addUpdateMeshTaskWithEdge(v3s16 blockpos, bool ack_to_server, bool urgent)
2665 {
2666         /*{
2667                 v3s16 p = blockpos;
2668                 infostream<<"Client::addUpdateMeshTaskWithEdge(): "
2669                                 <<"("<<p.X<<","<<p.Y<<","<<p.Z<<")"
2670                                 <<std::endl;
2671         }*/
2672
2673         try{
2674                 v3s16 p = blockpos + v3s16(0,0,0);
2675                 //MapBlock *b = m_env.getMap().getBlockNoCreate(p);
2676                 addUpdateMeshTask(p, ack_to_server, urgent);
2677         }
2678         catch(InvalidPositionException &e){}
2679         // Leading edge
2680         for (int i=0;i<6;i++)
2681         {
2682                 try{
2683                         v3s16 p = blockpos + g_6dirs[i];
2684                         addUpdateMeshTask(p, false, urgent);
2685                 }
2686                 catch(InvalidPositionException &e){}
2687         }
2688 }
2689
2690 void Client::addUpdateMeshTaskForNode(v3s16 nodepos, bool ack_to_server, bool urgent)
2691 {
2692         {
2693                 v3s16 p = nodepos;
2694                 infostream<<"Client::addUpdateMeshTaskForNode(): "
2695                                 <<"("<<p.X<<","<<p.Y<<","<<p.Z<<")"
2696                                 <<std::endl;
2697         }
2698
2699         v3s16 blockpos = getNodeBlockPos(nodepos);
2700         v3s16 blockpos_relative = blockpos * MAP_BLOCKSIZE;
2701
2702         try{
2703                 v3s16 p = blockpos + v3s16(0,0,0);
2704                 addUpdateMeshTask(p, ack_to_server, urgent);
2705         }
2706         catch(InvalidPositionException &e){}
2707         // Leading edge
2708         if(nodepos.X == blockpos_relative.X){
2709                 try{
2710                         v3s16 p = blockpos + v3s16(-1,0,0);
2711                         addUpdateMeshTask(p, false, urgent);
2712                 }
2713                 catch(InvalidPositionException &e){}
2714         }
2715         if(nodepos.Y == blockpos_relative.Y){
2716                 try{
2717                         v3s16 p = blockpos + v3s16(0,-1,0);
2718                         addUpdateMeshTask(p, false, urgent);
2719                 }
2720                 catch(InvalidPositionException &e){}
2721         }
2722         if(nodepos.Z == blockpos_relative.Z){
2723                 try{
2724                         v3s16 p = blockpos + v3s16(0,0,-1);
2725                         addUpdateMeshTask(p, false, urgent);
2726                 }
2727                 catch(InvalidPositionException &e){}
2728         }
2729 }
2730
2731 ClientEvent Client::getClientEvent()
2732 {
2733         if(m_client_event_queue.size() == 0)
2734         {
2735                 ClientEvent event;
2736                 event.type = CE_NONE;
2737                 return event;
2738         }
2739         return m_client_event_queue.pop_front();
2740 }
2741
2742 float Client::mediaReceiveProgress()
2743 {
2744         if (m_media_downloader)
2745                 return m_media_downloader->getProgress();
2746         else
2747                 return 1.0; // downloader only exists when not yet done
2748 }
2749
2750 void draw_load_screen(const std::wstring &text,
2751                 IrrlichtDevice* device, gui::IGUIFont* font,
2752                 float dtime=0 ,int percent=0, bool clouds=true);
2753 void Client::afterContentReceived(IrrlichtDevice *device, gui::IGUIFont* font)
2754 {
2755         infostream<<"Client::afterContentReceived() started"<<std::endl;
2756         assert(m_itemdef_received);
2757         assert(m_nodedef_received);
2758         assert(mediaReceived());
2759         
2760         // Rebuild inherited images and recreate textures
2761         infostream<<"- Rebuilding images and textures"<<std::endl;
2762         m_tsrc->rebuildImagesAndTextures();
2763
2764         // Rebuild shaders
2765         infostream<<"- Rebuilding shaders"<<std::endl;
2766         m_shsrc->rebuildShaders();
2767
2768         // Update node aliases
2769         infostream<<"- Updating node aliases"<<std::endl;
2770         m_nodedef->updateAliases(m_itemdef);
2771
2772         // Update node textures
2773         infostream<<"- Updating node textures"<<std::endl;
2774         m_nodedef->updateTextures(m_tsrc);
2775
2776         // Preload item textures and meshes if configured to
2777         if(g_settings->getBool("preload_item_visuals"))
2778         {
2779                 verbosestream<<"Updating item textures and meshes"<<std::endl;
2780                 wchar_t* text = wgettext("Item textures...");
2781                 draw_load_screen(text,device,font,0,0);
2782                 std::set<std::string> names = m_itemdef->getAll();
2783                 size_t size = names.size();
2784                 size_t count = 0;
2785                 int percent = 0;
2786                 for(std::set<std::string>::const_iterator
2787                                 i = names.begin(); i != names.end(); ++i){
2788                         // Asking for these caches the result
2789                         m_itemdef->getInventoryTexture(*i, this);
2790                         m_itemdef->getWieldMesh(*i, this);
2791                         count++;
2792                         percent = count*100/size;
2793                         if (count%50 == 0) // only update every 50 item
2794                                 draw_load_screen(text,device,font,0,percent);
2795                 }
2796                 delete[] text;
2797         }
2798
2799         // Start mesh update thread after setting up content definitions
2800         infostream<<"- Starting mesh update thread"<<std::endl;
2801         m_mesh_update_thread.Start();
2802         
2803         infostream<<"Client::afterContentReceived() done"<<std::endl;
2804 }
2805
2806 float Client::getRTT(void)
2807 {
2808         try{
2809                 return m_con.GetPeerAvgRTT(PEER_ID_SERVER);
2810         } catch(con::PeerNotFoundException &e){
2811                 return 1337;
2812         }
2813 }
2814
2815 // IGameDef interface
2816 // Under envlock
2817 IItemDefManager* Client::getItemDefManager()
2818 {
2819         return m_itemdef;
2820 }
2821 INodeDefManager* Client::getNodeDefManager()
2822 {
2823         return m_nodedef;
2824 }
2825 ICraftDefManager* Client::getCraftDefManager()
2826 {
2827         return NULL;
2828         //return m_craftdef;
2829 }
2830 ITextureSource* Client::getTextureSource()
2831 {
2832         return m_tsrc;
2833 }
2834 IShaderSource* Client::getShaderSource()
2835 {
2836         return m_shsrc;
2837 }
2838 u16 Client::allocateUnknownNodeId(const std::string &name)
2839 {
2840         errorstream<<"Client::allocateUnknownNodeId(): "
2841                         <<"Client cannot allocate node IDs"<<std::endl;
2842         assert(0);
2843         return CONTENT_IGNORE;
2844 }
2845 ISoundManager* Client::getSoundManager()
2846 {
2847         return m_sound;
2848 }
2849 MtEventManager* Client::getEventManager()
2850 {
2851         return m_event;
2852 }
2853
2854 scene::IAnimatedMesh* Client::getMesh(const std::string &filename)
2855 {
2856         std::map<std::string, std::string>::const_iterator i =
2857                         m_mesh_data.find(filename);
2858         if(i == m_mesh_data.end()){
2859                 errorstream<<"Client::getMesh(): Mesh not found: \""<<filename<<"\""
2860                                 <<std::endl;
2861                 return NULL;
2862         }
2863         const std::string &data = i->second;
2864         scene::ISceneManager *smgr = m_device->getSceneManager();
2865
2866         // Create the mesh, remove it from cache and return it
2867         // This allows unique vertex colors and other properties for each instance
2868         Buffer<char> data_rw(data.c_str(), data.size()); // Const-incorrect Irrlicht
2869         io::IFileSystem *irrfs = m_device->getFileSystem();
2870         io::IReadFile *rfile = irrfs->createMemoryReadFile(
2871                         *data_rw, data_rw.getSize(), filename.c_str());
2872         assert(rfile);
2873         scene::IAnimatedMesh *mesh = smgr->getMesh(rfile);
2874         rfile->drop();
2875         // NOTE: By playing with Irrlicht refcounts, maybe we could cache a bunch
2876         // of uniquely named instances and re-use them
2877         mesh->grab();
2878         smgr->getMeshCache()->removeMesh(mesh);
2879         return mesh;
2880 }
2881