8db6f2f4009123238a06fe3e622146dc9f9c4e5c
[oweals/minetest.git] / src / client.cpp
1 /*
2 Minetest
3 Copyright (C) 2013 celeron55, Perttu Ahola <celeron55@gmail.com>
4
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU Lesser General Public License as published by
7 the Free Software Foundation; either version 2.1 of the License, or
8 (at your option) any later version.
9
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 GNU Lesser General Public License for more details.
14
15 You should have received a copy of the GNU Lesser General Public License along
16 with this program; if not, write to the Free Software Foundation, Inc.,
17 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18 */
19
20 #include "client.h"
21 #include <iostream>
22 #include "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                 rfile->drop();
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 if(command == TOCLIENT_HUDADD)
2044         {
2045                 std::string datastring((char *)&data[2], datasize - 2);
2046                 std::istringstream is(datastring, std::ios_base::binary);
2047
2048                 u32 id           = readU32(is);
2049                 u8 type          = readU8(is);
2050                 v2f pos          = readV2F1000(is);
2051                 std::string name = deSerializeString(is);
2052                 v2f scale        = readV2F1000(is);
2053                 std::string text = deSerializeString(is);
2054                 u32 number       = readU32(is);
2055                 u32 item         = readU32(is);
2056                 u32 dir          = readU32(is);
2057                 v2f align        = readV2F1000(is);
2058
2059                 ClientEvent event;
2060                 event.type = CE_HUDADD;
2061                 event.hudadd.id     = id;
2062                 event.hudadd.type   = type;
2063                 event.hudadd.pos    = new v2f(pos);
2064                 event.hudadd.name   = new std::string(name);
2065                 event.hudadd.scale  = new v2f(scale);
2066                 event.hudadd.text   = new std::string(text);
2067                 event.hudadd.number = number;
2068                 event.hudadd.item   = item;
2069                 event.hudadd.dir    = dir;
2070                 event.hudadd.align  = new v2f(align);
2071                 m_client_event_queue.push_back(event);
2072         }
2073         else if(command == TOCLIENT_HUDRM)
2074         {
2075                 std::string datastring((char *)&data[2], datasize - 2);
2076                 std::istringstream is(datastring, std::ios_base::binary);
2077
2078                 u32 id = readU32(is);
2079
2080                 ClientEvent event;
2081                 event.type = CE_HUDRM;
2082                 event.hudrm.id = id;
2083                 m_client_event_queue.push_back(event);
2084         }
2085         else if(command == TOCLIENT_HUDCHANGE)
2086         {       
2087                 std::string sdata;
2088                 v2f v2fdata;
2089                 u32 intdata = 0;
2090                 
2091                 std::string datastring((char *)&data[2], datasize - 2);
2092                 std::istringstream is(datastring, std::ios_base::binary);
2093
2094                 u32 id  = readU32(is);
2095                 u8 stat = (HudElementStat)readU8(is);
2096                 
2097                 if (stat == HUD_STAT_POS || stat == HUD_STAT_SCALE)
2098                         v2fdata = readV2F1000(is);
2099                 else if (stat == HUD_STAT_NAME || stat == HUD_STAT_TEXT)
2100                         sdata = deSerializeString(is);
2101                 else
2102                         intdata = readU32(is);
2103                 
2104                 ClientEvent event;
2105                 event.type = CE_HUDCHANGE;
2106                 event.hudchange.id      = id;
2107                 event.hudchange.stat    = (HudElementStat)stat;
2108                 event.hudchange.v2fdata = new v2f(v2fdata);
2109                 event.hudchange.sdata   = new std::string(sdata);
2110                 event.hudchange.data    = intdata;
2111                 m_client_event_queue.push_back(event);
2112         }
2113         else
2114         {
2115                 infostream<<"Client: Ignoring unknown command "
2116                                 <<command<<std::endl;
2117         }
2118 }
2119
2120 void Client::Send(u16 channelnum, SharedBuffer<u8> data, bool reliable)
2121 {
2122         //JMutexAutoLock lock(m_con_mutex); //bulk comment-out
2123         m_con.Send(PEER_ID_SERVER, channelnum, data, reliable);
2124 }
2125
2126 void Client::interact(u8 action, const PointedThing& pointed)
2127 {
2128         if(connectedAndInitialized() == false){
2129                 infostream<<"Client::interact() "
2130                                 "cancelled (not connected)"
2131                                 <<std::endl;
2132                 return;
2133         }
2134
2135         std::ostringstream os(std::ios_base::binary);
2136
2137         /*
2138                 [0] u16 command
2139                 [2] u8 action
2140                 [3] u16 item
2141                 [5] u32 length of the next item
2142                 [9] serialized PointedThing
2143                 actions:
2144                 0: start digging (from undersurface) or use
2145                 1: stop digging (all parameters ignored)
2146                 2: digging completed
2147                 3: place block or item (to abovesurface)
2148                 4: use item
2149         */
2150         writeU16(os, TOSERVER_INTERACT);
2151         writeU8(os, action);
2152         writeU16(os, getPlayerItem());
2153         std::ostringstream tmp_os(std::ios::binary);
2154         pointed.serialize(tmp_os);
2155         os<<serializeLongString(tmp_os.str());
2156
2157         std::string s = os.str();
2158         SharedBuffer<u8> data((u8*)s.c_str(), s.size());
2159
2160         // Send as reliable
2161         Send(0, data, true);
2162 }
2163
2164 void Client::sendNodemetaFields(v3s16 p, const std::string &formname,
2165                 const std::map<std::string, std::string> &fields)
2166 {
2167         std::ostringstream os(std::ios_base::binary);
2168
2169         writeU16(os, TOSERVER_NODEMETA_FIELDS);
2170         writeV3S16(os, p);
2171         os<<serializeString(formname);
2172         writeU16(os, fields.size());
2173         for(std::map<std::string, std::string>::const_iterator
2174                         i = fields.begin(); i != fields.end(); i++){
2175                 const std::string &name = i->first;
2176                 const std::string &value = i->second;
2177                 os<<serializeString(name);
2178                 os<<serializeLongString(value);
2179         }
2180
2181         // Make data buffer
2182         std::string s = os.str();
2183         SharedBuffer<u8> data((u8*)s.c_str(), s.size());
2184         // Send as reliable
2185         Send(0, data, true);
2186 }
2187         
2188 void Client::sendInventoryFields(const std::string &formname, 
2189                 const std::map<std::string, std::string> &fields)
2190 {
2191         std::ostringstream os(std::ios_base::binary);
2192
2193         writeU16(os, TOSERVER_INVENTORY_FIELDS);
2194         os<<serializeString(formname);
2195         writeU16(os, fields.size());
2196         for(std::map<std::string, std::string>::const_iterator
2197                         i = fields.begin(); i != fields.end(); i++){
2198                 const std::string &name = i->first;
2199                 const std::string &value = i->second;
2200                 os<<serializeString(name);
2201                 os<<serializeLongString(value);
2202         }
2203
2204         // Make data buffer
2205         std::string s = os.str();
2206         SharedBuffer<u8> data((u8*)s.c_str(), s.size());
2207         // Send as reliable
2208         Send(0, data, true);
2209 }
2210
2211 void Client::sendInventoryAction(InventoryAction *a)
2212 {
2213         std::ostringstream os(std::ios_base::binary);
2214         u8 buf[12];
2215         
2216         // Write command
2217         writeU16(buf, TOSERVER_INVENTORY_ACTION);
2218         os.write((char*)buf, 2);
2219
2220         a->serialize(os);
2221         
2222         // Make data buffer
2223         std::string s = os.str();
2224         SharedBuffer<u8> data((u8*)s.c_str(), s.size());
2225         // Send as reliable
2226         Send(0, data, true);
2227 }
2228
2229 void Client::sendChatMessage(const std::wstring &message)
2230 {
2231         std::ostringstream os(std::ios_base::binary);
2232         u8 buf[12];
2233         
2234         // Write command
2235         writeU16(buf, TOSERVER_CHAT_MESSAGE);
2236         os.write((char*)buf, 2);
2237         
2238         // Write length
2239         writeU16(buf, message.size());
2240         os.write((char*)buf, 2);
2241         
2242         // Write string
2243         for(u32 i=0; i<message.size(); i++)
2244         {
2245                 u16 w = message[i];
2246                 writeU16(buf, w);
2247                 os.write((char*)buf, 2);
2248         }
2249         
2250         // Make data buffer
2251         std::string s = os.str();
2252         SharedBuffer<u8> data((u8*)s.c_str(), s.size());
2253         // Send as reliable
2254         Send(0, data, true);
2255 }
2256
2257 void Client::sendChangePassword(const std::wstring oldpassword,
2258                 const std::wstring newpassword)
2259 {
2260         Player *player = m_env.getLocalPlayer();
2261         if(player == NULL)
2262                 return;
2263
2264         std::string playername = player->getName();
2265         std::string oldpwd = translatePassword(playername, oldpassword);
2266         std::string newpwd = translatePassword(playername, newpassword);
2267
2268         std::ostringstream os(std::ios_base::binary);
2269         u8 buf[2+PASSWORD_SIZE*2];
2270         /*
2271                 [0] u16 TOSERVER_PASSWORD
2272                 [2] u8[28] old password
2273                 [30] u8[28] new password
2274         */
2275
2276         writeU16(buf, TOSERVER_PASSWORD);
2277         for(u32 i=0;i<PASSWORD_SIZE-1;i++)
2278         {
2279                 buf[2+i] = i<oldpwd.length()?oldpwd[i]:0;
2280                 buf[30+i] = i<newpwd.length()?newpwd[i]:0;
2281         }
2282         buf[2+PASSWORD_SIZE-1] = 0;
2283         buf[30+PASSWORD_SIZE-1] = 0;
2284         os.write((char*)buf, 2+PASSWORD_SIZE*2);
2285
2286         // Make data buffer
2287         std::string s = os.str();
2288         SharedBuffer<u8> data((u8*)s.c_str(), s.size());
2289         // Send as reliable
2290         Send(0, data, true);
2291 }
2292
2293
2294 void Client::sendDamage(u8 damage)
2295 {
2296         DSTACK(__FUNCTION_NAME);
2297         std::ostringstream os(std::ios_base::binary);
2298
2299         writeU16(os, TOSERVER_DAMAGE);
2300         writeU8(os, damage);
2301
2302         // Make data buffer
2303         std::string s = os.str();
2304         SharedBuffer<u8> data((u8*)s.c_str(), s.size());
2305         // Send as reliable
2306         Send(0, data, true);
2307 }
2308
2309 void Client::sendRespawn()
2310 {
2311         DSTACK(__FUNCTION_NAME);
2312         std::ostringstream os(std::ios_base::binary);
2313
2314         writeU16(os, TOSERVER_RESPAWN);
2315
2316         // Make data buffer
2317         std::string s = os.str();
2318         SharedBuffer<u8> data((u8*)s.c_str(), s.size());
2319         // Send as reliable
2320         Send(0, data, true);
2321 }
2322
2323 void Client::sendPlayerPos()
2324 {
2325         //JMutexAutoLock envlock(m_env_mutex); //bulk comment-out
2326         
2327         LocalPlayer *myplayer = m_env.getLocalPlayer();
2328         if(myplayer == NULL)
2329                 return;
2330
2331         // Save bandwidth by only updating position when something changed
2332         if(myplayer->last_position == myplayer->getPosition() &&
2333                         myplayer->last_speed == myplayer->getSpeed() &&
2334                         myplayer->last_pitch == myplayer->getPitch() &&
2335                         myplayer->last_yaw == myplayer->getYaw() &&
2336                         myplayer->last_keyPressed == myplayer->keyPressed)
2337                 return;
2338
2339         myplayer->last_position = myplayer->getPosition();
2340         myplayer->last_speed = myplayer->getSpeed();
2341         myplayer->last_pitch = myplayer->getPitch();
2342         myplayer->last_yaw = myplayer->getYaw();
2343         myplayer->last_keyPressed = myplayer->keyPressed;
2344
2345         u16 our_peer_id;
2346         {
2347                 //JMutexAutoLock lock(m_con_mutex); //bulk comment-out
2348                 our_peer_id = m_con.GetPeerID();
2349         }
2350         
2351         // Set peer id if not set already
2352         if(myplayer->peer_id == PEER_ID_INEXISTENT)
2353                 myplayer->peer_id = our_peer_id;
2354         // Check that an existing peer_id is the same as the connection's
2355         assert(myplayer->peer_id == our_peer_id);
2356         
2357         v3f pf = myplayer->getPosition();
2358         v3s32 position(pf.X*100, pf.Y*100, pf.Z*100);
2359         v3f sf = myplayer->getSpeed();
2360         v3s32 speed(sf.X*100, sf.Y*100, sf.Z*100);
2361         s32 pitch = myplayer->getPitch() * 100;
2362         s32 yaw = myplayer->getYaw() * 100;
2363         u32 keyPressed=myplayer->keyPressed;
2364         /*
2365                 Format:
2366                 [0] u16 command
2367                 [2] v3s32 position*100
2368                 [2+12] v3s32 speed*100
2369                 [2+12+12] s32 pitch*100
2370                 [2+12+12+4] s32 yaw*100
2371                 [2+12+12+4+4] u32 keyPressed
2372         */
2373         SharedBuffer<u8> data(2+12+12+4+4+4);
2374         writeU16(&data[0], TOSERVER_PLAYERPOS);
2375         writeV3S32(&data[2], position);
2376         writeV3S32(&data[2+12], speed);
2377         writeS32(&data[2+12+12], pitch);
2378         writeS32(&data[2+12+12+4], yaw);        
2379         writeU32(&data[2+12+12+4+4], keyPressed);
2380         // Send as unreliable
2381         Send(0, data, false);
2382 }
2383
2384 void Client::sendPlayerItem(u16 item)
2385 {
2386         Player *myplayer = m_env.getLocalPlayer();
2387         if(myplayer == NULL)
2388                 return;
2389
2390         u16 our_peer_id = m_con.GetPeerID();
2391
2392         // Set peer id if not set already
2393         if(myplayer->peer_id == PEER_ID_INEXISTENT)
2394                 myplayer->peer_id = our_peer_id;
2395         // Check that an existing peer_id is the same as the connection's
2396         assert(myplayer->peer_id == our_peer_id);
2397
2398         SharedBuffer<u8> data(2+2);
2399         writeU16(&data[0], TOSERVER_PLAYERITEM);
2400         writeU16(&data[2], item);
2401
2402         // Send as reliable
2403         Send(0, data, true);
2404 }
2405
2406 void Client::removeNode(v3s16 p)
2407 {
2408         std::map<v3s16, MapBlock*> modified_blocks;
2409
2410         try
2411         {
2412                 //TimeTaker t("removeNodeAndUpdate", m_device);
2413                 m_env.getMap().removeNodeAndUpdate(p, modified_blocks);
2414         }
2415         catch(InvalidPositionException &e)
2416         {
2417         }
2418         
2419         // add urgent task to update the modified node
2420         addUpdateMeshTaskForNode(p, false, true);
2421
2422         for(std::map<v3s16, MapBlock * >::iterator
2423                         i = modified_blocks.begin();
2424                         i != modified_blocks.end(); ++i)
2425         {
2426                 addUpdateMeshTaskWithEdge(i->first);
2427         }
2428 }
2429
2430 void Client::addNode(v3s16 p, MapNode n)
2431 {
2432         TimeTaker timer1("Client::addNode()");
2433
2434         std::map<v3s16, MapBlock*> modified_blocks;
2435
2436         try
2437         {
2438                 //TimeTaker timer3("Client::addNode(): addNodeAndUpdate");
2439                 m_env.getMap().addNodeAndUpdate(p, n, modified_blocks);
2440         }
2441         catch(InvalidPositionException &e)
2442         {}
2443         
2444         for(std::map<v3s16, MapBlock * >::iterator
2445                         i = modified_blocks.begin();
2446                         i != modified_blocks.end(); ++i)
2447         {
2448                 addUpdateMeshTaskWithEdge(i->first);
2449         }
2450 }
2451         
2452 void Client::setPlayerControl(PlayerControl &control)
2453 {
2454         //JMutexAutoLock envlock(m_env_mutex); //bulk comment-out
2455         LocalPlayer *player = m_env.getLocalPlayer();
2456         assert(player != NULL);
2457         player->control = control;
2458 }
2459
2460 void Client::selectPlayerItem(u16 item)
2461 {
2462         //JMutexAutoLock envlock(m_env_mutex); //bulk comment-out
2463         m_playeritem = item;
2464         m_inventory_updated = true;
2465         sendPlayerItem(item);
2466 }
2467
2468 // Returns true if the inventory of the local player has been
2469 // updated from the server. If it is true, it is set to false.
2470 bool Client::getLocalInventoryUpdated()
2471 {
2472         // m_inventory_updated is behind envlock
2473         //JMutexAutoLock envlock(m_env_mutex); //bulk comment-out
2474         bool updated = m_inventory_updated;
2475         m_inventory_updated = false;
2476         return updated;
2477 }
2478
2479 // Copies the inventory of the local player to parameter
2480 void Client::getLocalInventory(Inventory &dst)
2481 {
2482         //JMutexAutoLock envlock(m_env_mutex); //bulk comment-out
2483         Player *player = m_env.getLocalPlayer();
2484         assert(player != NULL);
2485         dst = player->inventory;
2486 }
2487
2488 Inventory* Client::getInventory(const InventoryLocation &loc)
2489 {
2490         switch(loc.type){
2491         case InventoryLocation::UNDEFINED:
2492         {}
2493         break;
2494         case InventoryLocation::CURRENT_PLAYER:
2495         {
2496                 Player *player = m_env.getLocalPlayer();
2497                 assert(player != NULL);
2498                 return &player->inventory;
2499         }
2500         break;
2501         case InventoryLocation::PLAYER:
2502         {
2503                 Player *player = m_env.getPlayer(loc.name.c_str());
2504                 if(!player)
2505                         return NULL;
2506                 return &player->inventory;
2507         }
2508         break;
2509         case InventoryLocation::NODEMETA:
2510         {
2511                 NodeMetadata *meta = m_env.getMap().getNodeMetadata(loc.p);
2512                 if(!meta)
2513                         return NULL;
2514                 return meta->getInventory();
2515         }
2516         break;
2517         case InventoryLocation::DETACHED:
2518         {
2519                 if(m_detached_inventories.count(loc.name) == 0)
2520                         return NULL;
2521                 return m_detached_inventories[loc.name];
2522         }
2523         break;
2524         default:
2525                 assert(0);
2526         }
2527         return NULL;
2528 }
2529 void Client::inventoryAction(InventoryAction *a)
2530 {
2531         /*
2532                 Send it to the server
2533         */
2534         sendInventoryAction(a);
2535
2536         /*
2537                 Predict some local inventory changes
2538         */
2539         a->clientApply(this, this);
2540 }
2541
2542 ClientActiveObject * Client::getSelectedActiveObject(
2543                 f32 max_d,
2544                 v3f from_pos_f_on_map,
2545                 core::line3d<f32> shootline_on_map
2546         )
2547 {
2548         std::vector<DistanceSortedActiveObject> objects;
2549
2550         m_env.getActiveObjects(from_pos_f_on_map, max_d, objects);
2551
2552         //infostream<<"Collected "<<objects.size()<<" nearby objects"<<std::endl;
2553         
2554         // Sort them.
2555         // After this, the closest object is the first in the array.
2556         std::sort(objects.begin(), objects.end());
2557
2558         for(u32 i=0; i<objects.size(); i++)
2559         {
2560                 ClientActiveObject *obj = objects[i].obj;
2561                 
2562                 core::aabbox3d<f32> *selection_box = obj->getSelectionBox();
2563                 if(selection_box == NULL)
2564                         continue;
2565
2566                 v3f pos = obj->getPosition();
2567
2568                 core::aabbox3d<f32> offsetted_box(
2569                                 selection_box->MinEdge + pos,
2570                                 selection_box->MaxEdge + pos
2571                 );
2572
2573                 if(offsetted_box.intersectsWithLine(shootline_on_map))
2574                 {
2575                         //infostream<<"Returning selected object"<<std::endl;
2576                         return obj;
2577                 }
2578         }
2579
2580         //infostream<<"No object selected; returning NULL."<<std::endl;
2581         return NULL;
2582 }
2583
2584 void Client::printDebugInfo(std::ostream &os)
2585 {
2586         //JMutexAutoLock lock1(m_fetchblock_mutex);
2587         /*JMutexAutoLock lock2(m_incoming_queue_mutex);
2588
2589         os<<"m_incoming_queue.getSize()="<<m_incoming_queue.getSize()
2590                 //<<", m_fetchblock_history.size()="<<m_fetchblock_history.size()
2591                 //<<", m_opt_not_found_history.size()="<<m_opt_not_found_history.size()
2592                 <<std::endl;*/
2593 }
2594
2595 std::list<std::string> Client::getConnectedPlayerNames()
2596 {
2597         return m_env.getPlayerNames();
2598 }
2599
2600 float Client::getAnimationTime()
2601 {
2602         return m_animation_time;
2603 }
2604
2605 int Client::getCrackLevel()
2606 {
2607         return m_crack_level;
2608 }
2609
2610 void Client::setCrack(int level, v3s16 pos)
2611 {
2612         int old_crack_level = m_crack_level;
2613         v3s16 old_crack_pos = m_crack_pos;
2614
2615         m_crack_level = level;
2616         m_crack_pos = pos;
2617
2618         if(old_crack_level >= 0 && (level < 0 || pos != old_crack_pos))
2619         {
2620                 // remove old crack
2621                 addUpdateMeshTaskForNode(old_crack_pos, false, true);
2622         }
2623         if(level >= 0 && (old_crack_level < 0 || pos != old_crack_pos))
2624         {
2625                 // add new crack
2626                 addUpdateMeshTaskForNode(pos, false, true);
2627         }
2628 }
2629
2630 u16 Client::getHP()
2631 {
2632         Player *player = m_env.getLocalPlayer();
2633         assert(player != NULL);
2634         return player->hp;
2635 }
2636
2637 bool Client::getChatMessage(std::wstring &message)
2638 {
2639         if(m_chat_queue.size() == 0)
2640                 return false;
2641         message = m_chat_queue.pop_front();
2642         return true;
2643 }
2644
2645 void Client::typeChatMessage(const std::wstring &message)
2646 {
2647         // Discard empty line
2648         if(message == L"")
2649                 return;
2650
2651         // Send to others
2652         sendChatMessage(message);
2653
2654         // Show locally
2655         if (message[0] == L'/')
2656         {
2657                 m_chat_queue.push_back(
2658                                 (std::wstring)L"issued command: "+message);
2659         }
2660         else
2661         {
2662                 LocalPlayer *player = m_env.getLocalPlayer();
2663                 assert(player != NULL);
2664                 std::wstring name = narrow_to_wide(player->getName());
2665                 m_chat_queue.push_back(
2666                                 (std::wstring)L"<"+name+L"> "+message);
2667         }
2668 }
2669
2670 void Client::addUpdateMeshTask(v3s16 p, bool ack_to_server, bool urgent)
2671 {
2672         /*infostream<<"Client::addUpdateMeshTask(): "
2673                         <<"("<<p.X<<","<<p.Y<<","<<p.Z<<")"
2674                         <<" ack_to_server="<<ack_to_server
2675                         <<" urgent="<<urgent
2676                         <<std::endl;*/
2677
2678         MapBlock *b = m_env.getMap().getBlockNoCreateNoEx(p);
2679         if(b == NULL)
2680                 return;
2681         
2682         /*
2683                 Create a task to update the mesh of the block
2684         */
2685         
2686         MeshMakeData *data = new MeshMakeData(this);
2687         
2688         {
2689                 //TimeTaker timer("data fill");
2690                 // Release: ~0ms
2691                 // Debug: 1-6ms, avg=2ms
2692                 data->fill(b);
2693                 data->setCrack(m_crack_level, m_crack_pos);
2694                 data->setSmoothLighting(g_settings->getBool("smooth_lighting"));
2695         }
2696
2697         // Debug wait
2698         //while(m_mesh_update_thread.m_queue_in.size() > 0) sleep_ms(10);
2699         
2700         // Add task to queue
2701         m_mesh_update_thread.m_queue_in.addBlock(p, data, ack_to_server, urgent);
2702
2703         /*infostream<<"Mesh update input queue size is "
2704                         <<m_mesh_update_thread.m_queue_in.size()
2705                         <<std::endl;*/
2706 }
2707
2708 void Client::addUpdateMeshTaskWithEdge(v3s16 blockpos, bool ack_to_server, bool urgent)
2709 {
2710         /*{
2711                 v3s16 p = blockpos;
2712                 infostream<<"Client::addUpdateMeshTaskWithEdge(): "
2713                                 <<"("<<p.X<<","<<p.Y<<","<<p.Z<<")"
2714                                 <<std::endl;
2715         }*/
2716
2717         try{
2718                 v3s16 p = blockpos + v3s16(0,0,0);
2719                 //MapBlock *b = m_env.getMap().getBlockNoCreate(p);
2720                 addUpdateMeshTask(p, ack_to_server, urgent);
2721         }
2722         catch(InvalidPositionException &e){}
2723         // Leading edge
2724         try{
2725                 v3s16 p = blockpos + v3s16(-1,0,0);
2726                 addUpdateMeshTask(p, false, urgent);
2727         }
2728         catch(InvalidPositionException &e){}
2729         try{
2730                 v3s16 p = blockpos + v3s16(0,-1,0);
2731                 addUpdateMeshTask(p, false, urgent);
2732         }
2733         catch(InvalidPositionException &e){}
2734         try{
2735                 v3s16 p = blockpos + v3s16(0,0,-1);
2736                 addUpdateMeshTask(p, false, urgent);
2737         }
2738         catch(InvalidPositionException &e){}
2739 }
2740
2741 void Client::addUpdateMeshTaskForNode(v3s16 nodepos, bool ack_to_server, bool urgent)
2742 {
2743         {
2744                 v3s16 p = nodepos;
2745                 infostream<<"Client::addUpdateMeshTaskForNode(): "
2746                                 <<"("<<p.X<<","<<p.Y<<","<<p.Z<<")"
2747                                 <<std::endl;
2748         }
2749
2750         v3s16 blockpos = getNodeBlockPos(nodepos);
2751         v3s16 blockpos_relative = blockpos * MAP_BLOCKSIZE;
2752
2753         try{
2754                 v3s16 p = blockpos + v3s16(0,0,0);
2755                 addUpdateMeshTask(p, ack_to_server, urgent);
2756         }
2757         catch(InvalidPositionException &e){}
2758         // Leading edge
2759         if(nodepos.X == blockpos_relative.X){
2760                 try{
2761                         v3s16 p = blockpos + v3s16(-1,0,0);
2762                         addUpdateMeshTask(p, false, urgent);
2763                 }
2764                 catch(InvalidPositionException &e){}
2765         }
2766         if(nodepos.Y == blockpos_relative.Y){
2767                 try{
2768                         v3s16 p = blockpos + v3s16(0,-1,0);
2769                         addUpdateMeshTask(p, false, urgent);
2770                 }
2771                 catch(InvalidPositionException &e){}
2772         }
2773         if(nodepos.Z == blockpos_relative.Z){
2774                 try{
2775                         v3s16 p = blockpos + v3s16(0,0,-1);
2776                         addUpdateMeshTask(p, false, urgent);
2777                 }
2778                 catch(InvalidPositionException &e){}
2779         }
2780 }
2781
2782 ClientEvent Client::getClientEvent()
2783 {
2784         if(m_client_event_queue.size() == 0)
2785         {
2786                 ClientEvent event;
2787                 event.type = CE_NONE;
2788                 return event;
2789         }
2790         return m_client_event_queue.pop_front();
2791 }
2792
2793 void Client::afterContentReceived()
2794 {
2795         infostream<<"Client::afterContentReceived() started"<<std::endl;
2796         assert(m_itemdef_received);
2797         assert(m_nodedef_received);
2798         assert(texturesReceived());
2799         
2800         // remove the information about which checksum each texture
2801         // ought to have
2802         m_media_name_sha1_map.clear();
2803
2804         // Rebuild inherited images and recreate textures
2805         infostream<<"- Rebuilding images and textures"<<std::endl;
2806         m_tsrc->rebuildImagesAndTextures();
2807
2808         // Update texture atlas
2809         infostream<<"- Updating texture atlas"<<std::endl;
2810         if(g_settings->getBool("enable_texture_atlas"))
2811                 m_tsrc->buildMainAtlas(this);
2812
2813         // Rebuild shaders
2814         m_shsrc->rebuildShaders();
2815
2816         // Update node aliases
2817         infostream<<"- Updating node aliases"<<std::endl;
2818         m_nodedef->updateAliases(m_itemdef);
2819
2820         // Update node textures
2821         infostream<<"- Updating node textures"<<std::endl;
2822         m_nodedef->updateTextures(m_tsrc);
2823
2824         // Preload item textures and meshes if configured to
2825         if(g_settings->getBool("preload_item_visuals"))
2826         {
2827                 verbosestream<<"Updating item textures and meshes"<<std::endl;
2828                 std::set<std::string> names = m_itemdef->getAll();
2829                 for(std::set<std::string>::const_iterator
2830                                 i = names.begin(); i != names.end(); ++i){
2831                         // Asking for these caches the result
2832                         m_itemdef->getInventoryTexture(*i, this);
2833                         m_itemdef->getWieldMesh(*i, this);
2834                 }
2835         }
2836
2837         // Start mesh update thread after setting up content definitions
2838         infostream<<"- Starting mesh update thread"<<std::endl;
2839         m_mesh_update_thread.Start();
2840         
2841         infostream<<"Client::afterContentReceived() done"<<std::endl;
2842 }
2843
2844 float Client::getRTT(void)
2845 {
2846         try{
2847                 return m_con.GetPeerAvgRTT(PEER_ID_SERVER);
2848         } catch(con::PeerNotFoundException &e){
2849                 return 1337;
2850         }
2851 }
2852
2853 // IGameDef interface
2854 // Under envlock
2855 IItemDefManager* Client::getItemDefManager()
2856 {
2857         return m_itemdef;
2858 }
2859 INodeDefManager* Client::getNodeDefManager()
2860 {
2861         return m_nodedef;
2862 }
2863 ICraftDefManager* Client::getCraftDefManager()
2864 {
2865         return NULL;
2866         //return m_craftdef;
2867 }
2868 ITextureSource* Client::getTextureSource()
2869 {
2870         return m_tsrc;
2871 }
2872 IShaderSource* Client::getShaderSource()
2873 {
2874         return m_shsrc;
2875 }
2876 u16 Client::allocateUnknownNodeId(const std::string &name)
2877 {
2878         errorstream<<"Client::allocateUnknownNodeId(): "
2879                         <<"Client cannot allocate node IDs"<<std::endl;
2880         assert(0);
2881         return CONTENT_IGNORE;
2882 }
2883 ISoundManager* Client::getSoundManager()
2884 {
2885         return m_sound;
2886 }
2887 MtEventManager* Client::getEventManager()
2888 {
2889         return m_event;
2890 }
2891