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