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