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