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