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