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