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