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