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