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