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