]> git.lizzy.rs Git - dragonfireclient.git/blob - src/client.cpp
Fix modstore/favourites hang by adding asynchronous lua job support
[dragonfireclient.git] / src / client.cpp
1 /*
2 Minetest
3 Copyright (C) 2013 celeron55, Perttu Ahola <celeron55@gmail.com>
4
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU Lesser General Public License as published by
7 the Free Software Foundation; either version 2.1 of the License, or
8 (at your option) any later version.
9
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 GNU Lesser General Public License for more details.
14
15 You should have received a copy of the GNU Lesser General Public License along
16 with this program; if not, write to the Free Software Foundation, Inc.,
17 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18 */
19
20 #include "client.h"
21 #include <iostream>
22 #include "clientserver.h"
23 #include "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                 addNode(p, n);
1266         }
1267         else if(command == TOCLIENT_BLOCKDATA)
1268         {
1269                 // Ignore too small packet
1270                 if(datasize < 8)
1271                         return;
1272                         
1273                 v3s16 p;
1274                 p.X = readS16(&data[2]);
1275                 p.Y = readS16(&data[4]);
1276                 p.Z = readS16(&data[6]);
1277                 
1278                 /*infostream<<"Client: Thread: BLOCKDATA for ("
1279                                 <<p.X<<","<<p.Y<<","<<p.Z<<")"<<std::endl;*/
1280                 /*infostream<<"Client: Thread: BLOCKDATA for ("
1281                                 <<p.X<<","<<p.Y<<","<<p.Z<<")"<<std::endl;*/
1282                 
1283                 std::string datastring((char*)&data[8], datasize-8);
1284                 std::istringstream istr(datastring, std::ios_base::binary);
1285                 
1286                 MapSector *sector;
1287                 MapBlock *block;
1288                 
1289                 v2s16 p2d(p.X, p.Z);
1290                 sector = m_env.getMap().emergeSector(p2d);
1291                 
1292                 assert(sector->getPos() == p2d);
1293
1294                 //TimeTaker timer("MapBlock deSerialize");
1295                 // 0ms
1296                 
1297                 block = sector->getBlockNoCreateNoEx(p.Y);
1298                 if(block)
1299                 {
1300                         /*
1301                                 Update an existing block
1302                         */
1303                         //infostream<<"Updating"<<std::endl;
1304                         block->deSerialize(istr, ser_version, false);
1305                         block->deSerializeNetworkSpecific(istr);
1306                 }
1307                 else
1308                 {
1309                         /*
1310                                 Create a new block
1311                         */
1312                         //infostream<<"Creating new"<<std::endl;
1313                         block = new MapBlock(&m_env.getMap(), p, this);
1314                         block->deSerialize(istr, ser_version, false);
1315                         block->deSerializeNetworkSpecific(istr);
1316                         sector->insertBlock(block);
1317                 }
1318
1319 #if 0
1320                 /*
1321                         Acknowledge block
1322                 */
1323                 /*
1324                         [0] u16 command
1325                         [2] u8 count
1326                         [3] v3s16 pos_0
1327                         [3+6] v3s16 pos_1
1328                         ...
1329                 */
1330                 u32 replysize = 2+1+6;
1331                 SharedBuffer<u8> reply(replysize);
1332                 writeU16(&reply[0], TOSERVER_GOTBLOCKS);
1333                 reply[2] = 1;
1334                 writeV3S16(&reply[3], p);
1335                 // Send as reliable
1336                 m_con.Send(PEER_ID_SERVER, 1, reply, true);
1337 #endif
1338
1339                 /*
1340                         Add it to mesh update queue and set it to be acknowledged after update.
1341                 */
1342                 //infostream<<"Adding mesh update task for received block"<<std::endl;
1343                 addUpdateMeshTaskWithEdge(p, true);
1344         }
1345         else if(command == TOCLIENT_INVENTORY)
1346         {
1347                 if(datasize < 3)
1348                         return;
1349
1350                 //TimeTaker t1("Parsing TOCLIENT_INVENTORY", m_device);
1351
1352                 { //envlock
1353                         //TimeTaker t2("mutex locking", m_device);
1354                         //JMutexAutoLock envlock(m_env_mutex); //bulk comment-out
1355                         //t2.stop();
1356                         
1357                         //TimeTaker t3("istringstream init", m_device);
1358                         std::string datastring((char*)&data[2], datasize-2);
1359                         std::istringstream is(datastring, std::ios_base::binary);
1360                         //t3.stop();
1361                         
1362                         //TimeTaker t4("player get", m_device);
1363                         Player *player = m_env.getLocalPlayer();
1364                         assert(player != NULL);
1365                         //t4.stop();
1366
1367                         //TimeTaker t1("inventory.deSerialize()", m_device);
1368                         player->inventory.deSerialize(is);
1369                         //t1.stop();
1370
1371                         m_inventory_updated = true;
1372
1373                         delete m_inventory_from_server;
1374                         m_inventory_from_server = new Inventory(player->inventory);
1375                         m_inventory_from_server_age = 0.0;
1376
1377                         //infostream<<"Client got player inventory:"<<std::endl;
1378                         //player->inventory.print(infostream);
1379                 }
1380         }
1381         else if(command == TOCLIENT_TIME_OF_DAY)
1382         {
1383                 if(datasize < 4)
1384                         return;
1385                 
1386                 u16 time_of_day = readU16(&data[2]);
1387                 time_of_day = time_of_day % 24000;
1388                 //infostream<<"Client: time_of_day="<<time_of_day<<std::endl;
1389                 float time_speed = 0;
1390                 if(datasize >= 2 + 2 + 4){
1391                         time_speed = readF1000(&data[4]);
1392                 } else {
1393                         // Old message; try to approximate speed of time by ourselves
1394                         float time_of_day_f = (float)time_of_day / 24000.0;
1395                         float tod_diff_f = 0;
1396                         if(time_of_day_f < 0.2 && m_last_time_of_day_f > 0.8)
1397                                 tod_diff_f = time_of_day_f - m_last_time_of_day_f + 1.0;
1398                         else
1399                                 tod_diff_f = time_of_day_f - m_last_time_of_day_f;
1400                         m_last_time_of_day_f = time_of_day_f;
1401                         float time_diff = m_time_of_day_update_timer;
1402                         m_time_of_day_update_timer = 0;
1403                         if(m_time_of_day_set){
1404                                 time_speed = 3600.0*24.0 * tod_diff_f / time_diff;
1405                                 infostream<<"Client: Measured time_of_day speed (old format): "
1406                                                 <<time_speed<<" tod_diff_f="<<tod_diff_f
1407                                                 <<" time_diff="<<time_diff<<std::endl;
1408                         }
1409                 }
1410                 
1411                 // Update environment
1412                 m_env.setTimeOfDay(time_of_day);
1413                 m_env.setTimeOfDaySpeed(time_speed);
1414                 m_time_of_day_set = true;
1415
1416                 u32 dr = m_env.getDayNightRatio();
1417                 verbosestream<<"Client: time_of_day="<<time_of_day
1418                                 <<" time_speed="<<time_speed
1419                                 <<" dr="<<dr<<std::endl;
1420         }
1421         else if(command == TOCLIENT_CHAT_MESSAGE)
1422         {
1423                 /*
1424                         u16 command
1425                         u16 length
1426                         wstring message
1427                 */
1428                 u8 buf[6];
1429                 std::string datastring((char*)&data[2], datasize-2);
1430                 std::istringstream is(datastring, std::ios_base::binary);
1431                 
1432                 // Read stuff
1433                 is.read((char*)buf, 2);
1434                 u16 len = readU16(buf);
1435                 
1436                 std::wstring message;
1437                 for(u16 i=0; i<len; i++)
1438                 {
1439                         is.read((char*)buf, 2);
1440                         message += (wchar_t)readU16(buf);
1441                 }
1442
1443                 /*infostream<<"Client received chat message: "
1444                                 <<wide_to_narrow(message)<<std::endl;*/
1445                 
1446                 m_chat_queue.push_back(message);
1447         }
1448         else if(command == TOCLIENT_ACTIVE_OBJECT_REMOVE_ADD)
1449         {
1450                 //if(g_settings->getBool("enable_experimental"))
1451                 {
1452                         /*
1453                                 u16 command
1454                                 u16 count of removed objects
1455                                 for all removed objects {
1456                                         u16 id
1457                                 }
1458                                 u16 count of added objects
1459                                 for all added objects {
1460                                         u16 id
1461                                         u8 type
1462                                         u32 initialization data length
1463                                         string initialization data
1464                                 }
1465                         */
1466
1467                         char buf[6];
1468                         // Get all data except the command number
1469                         std::string datastring((char*)&data[2], datasize-2);
1470                         // Throw them in an istringstream
1471                         std::istringstream is(datastring, std::ios_base::binary);
1472
1473                         // Read stuff
1474                         
1475                         // Read removed objects
1476                         is.read(buf, 2);
1477                         u16 removed_count = readU16((u8*)buf);
1478                         for(u16 i=0; i<removed_count; i++)
1479                         {
1480                                 is.read(buf, 2);
1481                                 u16 id = readU16((u8*)buf);
1482                                 // Remove it
1483                                 {
1484                                         //JMutexAutoLock envlock(m_env_mutex); //bulk comment-out
1485                                         m_env.removeActiveObject(id);
1486                                 }
1487                         }
1488                         
1489                         // Read added objects
1490                         is.read(buf, 2);
1491                         u16 added_count = readU16((u8*)buf);
1492                         for(u16 i=0; i<added_count; i++)
1493                         {
1494                                 is.read(buf, 2);
1495                                 u16 id = readU16((u8*)buf);
1496                                 is.read(buf, 1);
1497                                 u8 type = readU8((u8*)buf);
1498                                 std::string data = deSerializeLongString(is);
1499                                 // Add it
1500                                 {
1501                                         //JMutexAutoLock envlock(m_env_mutex); //bulk comment-out
1502                                         m_env.addActiveObject(id, type, data);
1503                                 }
1504                         }
1505                 }
1506         }
1507         else if(command == TOCLIENT_ACTIVE_OBJECT_MESSAGES)
1508         {
1509                 //if(g_settings->getBool("enable_experimental"))
1510                 {
1511                         /*
1512                                 u16 command
1513                                 for all objects
1514                                 {
1515                                         u16 id
1516                                         u16 message length
1517                                         string message
1518                                 }
1519                         */
1520                         char buf[6];
1521                         // Get all data except the command number
1522                         std::string datastring((char*)&data[2], datasize-2);
1523                         // Throw them in an istringstream
1524                         std::istringstream is(datastring, std::ios_base::binary);
1525                         
1526                         while(is.eof() == false)
1527                         {
1528                                 // Read stuff
1529                                 is.read(buf, 2);
1530                                 u16 id = readU16((u8*)buf);
1531                                 if(is.eof())
1532                                         break;
1533                                 is.read(buf, 2);
1534                                 u16 message_size = readU16((u8*)buf);
1535                                 std::string message;
1536                                 message.reserve(message_size);
1537                                 for(u16 i=0; i<message_size; i++)
1538                                 {
1539                                         is.read(buf, 1);
1540                                         message.append(buf, 1);
1541                                 }
1542                                 // Pass on to the environment
1543                                 {
1544                                         //JMutexAutoLock envlock(m_env_mutex); //bulk comment-out
1545                                         m_env.processActiveObjectMessage(id, message);
1546                                 }
1547                         }
1548                 }
1549         }
1550         else if(command == TOCLIENT_MOVEMENT)
1551         {
1552                 std::string datastring((char*)&data[2], datasize-2);
1553                 std::istringstream is(datastring, std::ios_base::binary);
1554                 Player *player = m_env.getLocalPlayer();
1555                 assert(player != NULL);
1556
1557                 player->movement_acceleration_default = readF1000(is) * BS;
1558                 player->movement_acceleration_air = readF1000(is) * BS;
1559                 player->movement_acceleration_fast = readF1000(is) * BS;
1560                 player->movement_speed_walk = readF1000(is) * BS;
1561                 player->movement_speed_crouch = readF1000(is) * BS;
1562                 player->movement_speed_fast = readF1000(is) * BS;
1563                 player->movement_speed_climb = readF1000(is) * BS;
1564                 player->movement_speed_jump = readF1000(is) * BS;
1565                 player->movement_liquid_fluidity = readF1000(is) * BS;
1566                 player->movement_liquid_fluidity_smooth = readF1000(is) * BS;
1567                 player->movement_liquid_sink = readF1000(is) * BS;
1568                 player->movement_gravity = readF1000(is) * BS;
1569         }
1570         else if(command == TOCLIENT_HP)
1571         {
1572                 std::string datastring((char*)&data[2], datasize-2);
1573                 std::istringstream is(datastring, std::ios_base::binary);
1574                 Player *player = m_env.getLocalPlayer();
1575                 assert(player != NULL);
1576                 u8 oldhp = player->hp;
1577                 u8 hp = readU8(is);
1578                 player->hp = hp;
1579
1580                 if(hp < oldhp)
1581                 {
1582                         // Add to ClientEvent queue
1583                         ClientEvent event;
1584                         event.type = CE_PLAYER_DAMAGE;
1585                         event.player_damage.amount = oldhp - hp;
1586                         m_client_event_queue.push_back(event);
1587                 }
1588         }
1589         else if(command == TOCLIENT_BREATH)
1590         {
1591                 std::string datastring((char*)&data[2], datasize-2);
1592                 std::istringstream is(datastring, std::ios_base::binary);
1593                 Player *player = m_env.getLocalPlayer();
1594                 assert(player != NULL);
1595                 u16 breath = readU16(is);
1596                 player->setBreath(breath) ;
1597         }
1598         else if(command == TOCLIENT_MOVE_PLAYER)
1599         {
1600                 std::string datastring((char*)&data[2], datasize-2);
1601                 std::istringstream is(datastring, std::ios_base::binary);
1602                 Player *player = m_env.getLocalPlayer();
1603                 assert(player != NULL);
1604                 v3f pos = readV3F1000(is);
1605                 f32 pitch = readF1000(is);
1606                 f32 yaw = readF1000(is);
1607                 player->setPosition(pos);
1608                 /*player->setPitch(pitch);
1609                 player->setYaw(yaw);*/
1610
1611                 infostream<<"Client got TOCLIENT_MOVE_PLAYER"
1612                                 <<" pos=("<<pos.X<<","<<pos.Y<<","<<pos.Z<<")"
1613                                 <<" pitch="<<pitch
1614                                 <<" yaw="<<yaw
1615                                 <<std::endl;
1616
1617                 /*
1618                         Add to ClientEvent queue.
1619                         This has to be sent to the main program because otherwise
1620                         it would just force the pitch and yaw values to whatever
1621                         the camera points to.
1622                 */
1623                 ClientEvent event;
1624                 event.type = CE_PLAYER_FORCE_MOVE;
1625                 event.player_force_move.pitch = pitch;
1626                 event.player_force_move.yaw = yaw;
1627                 m_client_event_queue.push_back(event);
1628
1629                 // Ignore damage for a few seconds, so that the player doesn't
1630                 // get damage from falling on ground
1631                 m_ignore_damage_timer = 3.0;
1632         }
1633         else if(command == TOCLIENT_PLAYERITEM)
1634         {
1635                 infostream<<"Client: WARNING: Ignoring TOCLIENT_PLAYERITEM"<<std::endl;
1636         }
1637         else if(command == TOCLIENT_DEATHSCREEN)
1638         {
1639                 std::string datastring((char*)&data[2], datasize-2);
1640                 std::istringstream is(datastring, std::ios_base::binary);
1641                 
1642                 bool set_camera_point_target = readU8(is);
1643                 v3f camera_point_target = readV3F1000(is);
1644                 
1645                 ClientEvent event;
1646                 event.type = CE_DEATHSCREEN;
1647                 event.deathscreen.set_camera_point_target = set_camera_point_target;
1648                 event.deathscreen.camera_point_target_x = camera_point_target.X;
1649                 event.deathscreen.camera_point_target_y = camera_point_target.Y;
1650                 event.deathscreen.camera_point_target_z = camera_point_target.Z;
1651                 m_client_event_queue.push_back(event);
1652         }
1653         else if(command == TOCLIENT_ANNOUNCE_MEDIA)
1654         {
1655                 std::string datastring((char*)&data[2], datasize-2);
1656                 std::istringstream is(datastring, std::ios_base::binary);
1657
1658                 // Mesh update thread must be stopped while
1659                 // updating content definitions
1660                 assert(!m_mesh_update_thread.IsRunning());
1661
1662                 int num_files = readU16(is);
1663                 
1664                 infostream<<"Client: Received media announcement: packet size: "
1665                                 <<datasize<<std::endl;
1666
1667                 std::list<MediaRequest> file_requests;
1668
1669                 for(int i=0; i<num_files; i++)
1670                 {
1671                         //read file from cache
1672                         std::string name = deSerializeString(is);
1673                         std::string sha1_base64 = deSerializeString(is);
1674
1675                         // if name contains illegal characters, ignore the file
1676                         if(!string_allowed(name, TEXTURENAME_ALLOWED_CHARS)){
1677                                 errorstream<<"Client: ignoring illegal file name "
1678                                                 <<"sent by server: \""<<name<<"\""<<std::endl;
1679                                 continue;
1680                         }
1681
1682                         std::string sha1_raw = base64_decode(sha1_base64);
1683                         std::string sha1_hex = hex_encode(sha1_raw);
1684                         std::ostringstream tmp_os(std::ios_base::binary);
1685                         bool found_in_cache = m_media_cache.load_sha1(sha1_raw, tmp_os);
1686                         m_media_name_sha1_map[name] = sha1_raw;
1687
1688                         // If found in cache, try to load it from there
1689                         if(found_in_cache)
1690                         {
1691                                 bool success = loadMedia(tmp_os.str(), name);
1692                                 if(success){
1693                                         verbosestream<<"Client: Loaded cached media: "
1694                                                         <<sha1_hex<<" \""<<name<<"\""<<std::endl;
1695                                         continue;
1696                                 } else{
1697                                         infostream<<"Client: Failed to load cached media: "
1698                                                         <<sha1_hex<<" \""<<name<<"\""<<std::endl;
1699                                 }
1700                         }
1701                         // Didn't load from cache; queue it to be requested
1702                         verbosestream<<"Client: Adding file to request list: \""
1703                                         <<sha1_hex<<" \""<<name<<"\""<<std::endl;
1704                         file_requests.push_back(MediaRequest(name));
1705                 }
1706
1707                 std::string remote_media = "";
1708                 try {
1709                         remote_media = deSerializeString(is);
1710                 }
1711                 catch(SerializationError) {
1712                         // not supported by server or turned off
1713                 }
1714
1715                 m_media_count = file_requests.size();
1716                 m_media_receive_started = true;
1717
1718                 if (remote_media == "" || !USE_CURL) {
1719                         request_media(file_requests);
1720                 } else {
1721                         #if USE_CURL
1722                         std::list<MediaFetchThread*>::iterator cur = m_media_fetch_threads.begin();
1723                         for(std::list<MediaRequest>::iterator i = file_requests.begin();
1724                                         i != file_requests.end(); ++i) {
1725                                 (*cur)->m_file_requests.push_back(*i);
1726                                 cur++;
1727                                 if (cur == m_media_fetch_threads.end())
1728                                         cur = m_media_fetch_threads.begin();
1729                         }
1730                         for (std::list<MediaFetchThread*>::iterator i = m_media_fetch_threads.begin();
1731                                         i != m_media_fetch_threads.end(); ++i) {
1732                                 (*i)->m_remote_url = remote_media;
1733                                 (*i)->Start();
1734                         }
1735                         #endif
1736
1737                         // notify server we received everything
1738                         std::ostringstream os(std::ios_base::binary);
1739                         writeU16(os, TOSERVER_RECEIVED_MEDIA);
1740                         std::string s = os.str();
1741                         SharedBuffer<u8> data((u8*)s.c_str(), s.size());
1742                         // Send as reliable
1743                         Send(0, data, true);
1744                 }
1745                 ClientEvent event;
1746                 event.type = CE_TEXTURES_UPDATED;
1747                 m_client_event_queue.push_back(event);
1748         }
1749         else if(command == TOCLIENT_MEDIA)
1750         {
1751                 std::string datastring((char*)&data[2], datasize-2);
1752                 std::istringstream is(datastring, std::ios_base::binary);
1753
1754                 /*
1755                         u16 command
1756                         u16 total number of file bunches
1757                         u16 index of this bunch
1758                         u32 number of files in this bunch
1759                         for each file {
1760                                 u16 length of name
1761                                 string name
1762                                 u32 length of data
1763                                 data
1764                         }
1765                 */
1766                 int num_bunches = readU16(is);
1767                 int bunch_i = readU16(is);
1768                 u32 num_files = readU32(is);
1769                 infostream<<"Client: Received files: bunch "<<bunch_i<<"/"
1770                                 <<num_bunches<<" files="<<num_files
1771                                 <<" size="<<datasize<<std::endl;
1772
1773                 // Check total and received media count
1774                 assert(m_media_received_count <= m_media_count);
1775                 if (num_files > m_media_count - m_media_received_count) {
1776                         errorstream<<"Client: Received more files than requested:"
1777                                 <<" total count="<<m_media_count
1778                                 <<" total received="<<m_media_received_count
1779                                 <<" bunch "<<bunch_i<<"/"<<num_bunches
1780                                 <<" files="<<num_files
1781                                 <<" size="<<datasize<<std::endl;
1782                         num_files = m_media_count - m_media_received_count;
1783                 }
1784                 if (num_files == 0)
1785                         return;
1786
1787                 // Mesh update thread must be stopped while
1788                 // updating content definitions
1789                 assert(!m_mesh_update_thread.IsRunning());
1790
1791                 for(u32 i=0; i<num_files; i++){
1792                         assert(m_media_received_count < m_media_count);
1793                         m_media_received_count++;
1794                         std::string name = deSerializeString(is);
1795                         std::string data = deSerializeLongString(is);
1796
1797                         // if name contains illegal characters, ignore the file
1798                         if(!string_allowed(name, TEXTURENAME_ALLOWED_CHARS)){
1799                                 errorstream<<"Client: ignoring illegal file name "
1800                                                 <<"sent by server: \""<<name<<"\""<<std::endl;
1801                                 continue;
1802                         }
1803                         
1804                         bool success = loadMedia(data, name);
1805                         if(success){
1806                                 verbosestream<<"Client: Loaded received media: "
1807                                                 <<"\""<<name<<"\". Caching."<<std::endl;
1808                         } else{
1809                                 infostream<<"Client: Failed to load received media: "
1810                                                 <<"\""<<name<<"\". Not caching."<<std::endl;
1811                                 continue;
1812                         }
1813
1814                         bool did = fs::CreateAllDirs(getMediaCacheDir());
1815                         if(!did){
1816                                 errorstream<<"Could not create media cache directory"
1817                                                 <<std::endl;
1818                         }
1819
1820                         {
1821                                 std::map<std::string, std::string>::iterator n;
1822                                 n = m_media_name_sha1_map.find(name);
1823                                 if(n == m_media_name_sha1_map.end())
1824                                         errorstream<<"The server sent a file that has not "
1825                                                         <<"been announced."<<std::endl;
1826                                 else
1827                                         m_media_cache.update_sha1(data);
1828                         }
1829                 }
1830
1831                 ClientEvent event;
1832                 event.type = CE_TEXTURES_UPDATED;
1833                 m_client_event_queue.push_back(event);
1834         }
1835         else if(command == TOCLIENT_TOOLDEF)
1836         {
1837                 infostream<<"Client: WARNING: Ignoring TOCLIENT_TOOLDEF"<<std::endl;
1838         }
1839         else if(command == TOCLIENT_NODEDEF)
1840         {
1841                 infostream<<"Client: Received node definitions: packet size: "
1842                                 <<datasize<<std::endl;
1843
1844                 // Mesh update thread must be stopped while
1845                 // updating content definitions
1846                 assert(!m_mesh_update_thread.IsRunning());
1847
1848                 // Decompress node definitions
1849                 std::string datastring((char*)&data[2], datasize-2);
1850                 std::istringstream is(datastring, std::ios_base::binary);
1851                 std::istringstream tmp_is(deSerializeLongString(is), std::ios::binary);
1852                 std::ostringstream tmp_os;
1853                 decompressZlib(tmp_is, tmp_os);
1854
1855                 // Deserialize node definitions
1856                 std::istringstream tmp_is2(tmp_os.str());
1857                 m_nodedef->deSerialize(tmp_is2);
1858                 m_nodedef_received = true;
1859         }
1860         else if(command == TOCLIENT_CRAFTITEMDEF)
1861         {
1862                 infostream<<"Client: WARNING: Ignoring TOCLIENT_CRAFTITEMDEF"<<std::endl;
1863         }
1864         else if(command == TOCLIENT_ITEMDEF)
1865         {
1866                 infostream<<"Client: Received item definitions: packet size: "
1867                                 <<datasize<<std::endl;
1868
1869                 // Mesh update thread must be stopped while
1870                 // updating content definitions
1871                 assert(!m_mesh_update_thread.IsRunning());
1872
1873                 // Decompress item definitions
1874                 std::string datastring((char*)&data[2], datasize-2);
1875                 std::istringstream is(datastring, std::ios_base::binary);
1876                 std::istringstream tmp_is(deSerializeLongString(is), std::ios::binary);
1877                 std::ostringstream tmp_os;
1878                 decompressZlib(tmp_is, tmp_os);
1879
1880                 // Deserialize node definitions
1881                 std::istringstream tmp_is2(tmp_os.str());
1882                 m_itemdef->deSerialize(tmp_is2);
1883                 m_itemdef_received = true;
1884         }
1885         else if(command == TOCLIENT_PLAY_SOUND)
1886         {
1887                 std::string datastring((char*)&data[2], datasize-2);
1888                 std::istringstream is(datastring, std::ios_base::binary);
1889
1890                 s32 server_id = readS32(is);
1891                 std::string name = deSerializeString(is);
1892                 float gain = readF1000(is);
1893                 int type = readU8(is); // 0=local, 1=positional, 2=object
1894                 v3f pos = readV3F1000(is);
1895                 u16 object_id = readU16(is);
1896                 bool loop = readU8(is);
1897                 // Start playing
1898                 int client_id = -1;
1899                 switch(type){
1900                 case 0: // local
1901                         client_id = m_sound->playSound(name, loop, gain);
1902                         break;
1903                 case 1: // positional
1904                         client_id = m_sound->playSoundAt(name, loop, gain, pos);
1905                         break;
1906                 case 2: { // object
1907                         ClientActiveObject *cao = m_env.getActiveObject(object_id);
1908                         if(cao)
1909                                 pos = cao->getPosition();
1910                         client_id = m_sound->playSoundAt(name, loop, gain, pos);
1911                         // TODO: Set up sound to move with object
1912                         break; }
1913                 default:
1914                         break;
1915                 }
1916                 if(client_id != -1){
1917                         m_sounds_server_to_client[server_id] = client_id;
1918                         m_sounds_client_to_server[client_id] = server_id;
1919                         if(object_id != 0)
1920                                 m_sounds_to_objects[client_id] = object_id;
1921                 }
1922         }
1923         else if(command == TOCLIENT_STOP_SOUND)
1924         {
1925                 std::string datastring((char*)&data[2], datasize-2);
1926                 std::istringstream is(datastring, std::ios_base::binary);
1927
1928                 s32 server_id = readS32(is);
1929                 std::map<s32, int>::iterator i =
1930                                 m_sounds_server_to_client.find(server_id);
1931                 if(i != m_sounds_server_to_client.end()){
1932                         int client_id = i->second;
1933                         m_sound->stopSound(client_id);
1934                 }
1935         }
1936         else if(command == TOCLIENT_PRIVILEGES)
1937         {
1938                 std::string datastring((char*)&data[2], datasize-2);
1939                 std::istringstream is(datastring, std::ios_base::binary);
1940                 
1941                 m_privileges.clear();
1942                 infostream<<"Client: Privileges updated: ";
1943                 u16 num_privileges = readU16(is);
1944                 for(u16 i=0; i<num_privileges; i++){
1945                         std::string priv = deSerializeString(is);
1946                         m_privileges.insert(priv);
1947                         infostream<<priv<<" ";
1948                 }
1949                 infostream<<std::endl;
1950         }
1951         else if(command == TOCLIENT_INVENTORY_FORMSPEC)
1952         {
1953                 std::string datastring((char*)&data[2], datasize-2);
1954                 std::istringstream is(datastring, std::ios_base::binary);
1955
1956                 // Store formspec in LocalPlayer
1957                 Player *player = m_env.getLocalPlayer();
1958                 assert(player != NULL);
1959                 player->inventory_formspec = deSerializeLongString(is);
1960         }
1961         else if(command == TOCLIENT_DETACHED_INVENTORY)
1962         {
1963                 std::string datastring((char*)&data[2], datasize-2);
1964                 std::istringstream is(datastring, std::ios_base::binary);
1965
1966                 std::string name = deSerializeString(is);
1967                 
1968                 infostream<<"Client: Detached inventory update: \""<<name<<"\""<<std::endl;
1969
1970                 Inventory *inv = NULL;
1971                 if(m_detached_inventories.count(name) > 0)
1972                         inv = m_detached_inventories[name];
1973                 else{
1974                         inv = new Inventory(m_itemdef);
1975                         m_detached_inventories[name] = inv;
1976                 }
1977                 inv->deSerialize(is);
1978         }
1979         else if(command == TOCLIENT_SHOW_FORMSPEC)
1980         {
1981                 std::string datastring((char*)&data[2], datasize-2);
1982                 std::istringstream is(datastring, std::ios_base::binary);
1983
1984                 std::string formspec = deSerializeLongString(is);
1985                 std::string formname = deSerializeString(is);
1986
1987                 ClientEvent event;
1988                 event.type = CE_SHOW_FORMSPEC;
1989                 // pointer is required as event is a struct only!
1990                 // adding a std:string to a struct isn't possible
1991                 event.show_formspec.formspec = new std::string(formspec);
1992                 event.show_formspec.formname = new std::string(formname);
1993                 m_client_event_queue.push_back(event);
1994         }
1995         else if(command == TOCLIENT_SPAWN_PARTICLE)
1996         {
1997                 std::string datastring((char*)&data[2], datasize-2);
1998                 std::istringstream is(datastring, std::ios_base::binary);
1999
2000                 v3f pos = readV3F1000(is);
2001                 v3f vel = readV3F1000(is);
2002                 v3f acc = readV3F1000(is);
2003                 float expirationtime = readF1000(is);
2004                 float size = readF1000(is);
2005                 bool collisiondetection = readU8(is);
2006                 std::string texture = deSerializeLongString(is);
2007
2008                 ClientEvent event;
2009                 event.type = CE_SPAWN_PARTICLE;
2010                 event.spawn_particle.pos = new v3f (pos);
2011                 event.spawn_particle.vel = new v3f (vel);
2012                 event.spawn_particle.acc = new v3f (acc);
2013
2014                 event.spawn_particle.expirationtime = expirationtime;
2015                 event.spawn_particle.size = size;
2016                 event.spawn_particle.collisiondetection =
2017                                 collisiondetection;
2018                 event.spawn_particle.texture = new std::string(texture);
2019
2020                 m_client_event_queue.push_back(event);
2021         }
2022         else if(command == TOCLIENT_ADD_PARTICLESPAWNER)
2023         {
2024                 std::string datastring((char*)&data[2], datasize-2);
2025                 std::istringstream is(datastring, std::ios_base::binary);
2026
2027                 u16 amount = readU16(is);
2028                 float spawntime = readF1000(is);
2029                 v3f minpos = readV3F1000(is);
2030                 v3f maxpos = readV3F1000(is);
2031                 v3f minvel = readV3F1000(is);
2032                 v3f maxvel = readV3F1000(is);
2033                 v3f minacc = readV3F1000(is);
2034                 v3f maxacc = readV3F1000(is);
2035                 float minexptime = readF1000(is);
2036                 float maxexptime = readF1000(is);
2037                 float minsize = readF1000(is);
2038                 float maxsize = readF1000(is);
2039                 bool collisiondetection = readU8(is);
2040                 std::string texture = deSerializeLongString(is);
2041                 u32 id = readU32(is);
2042
2043                 ClientEvent event;
2044                 event.type = CE_ADD_PARTICLESPAWNER;
2045                 event.add_particlespawner.amount = amount;
2046                 event.add_particlespawner.spawntime = spawntime;
2047
2048                 event.add_particlespawner.minpos = new v3f (minpos);
2049                 event.add_particlespawner.maxpos = new v3f (maxpos);
2050                 event.add_particlespawner.minvel = new v3f (minvel);
2051                 event.add_particlespawner.maxvel = new v3f (maxvel);
2052                 event.add_particlespawner.minacc = new v3f (minacc);
2053                 event.add_particlespawner.maxacc = new v3f (maxacc);
2054
2055                 event.add_particlespawner.minexptime = minexptime;
2056                 event.add_particlespawner.maxexptime = maxexptime;
2057                 event.add_particlespawner.minsize = minsize;
2058                 event.add_particlespawner.maxsize = maxsize;
2059                 event.add_particlespawner.collisiondetection = collisiondetection;
2060                 event.add_particlespawner.texture = new std::string(texture);
2061                 event.add_particlespawner.id = id;
2062
2063                 m_client_event_queue.push_back(event);
2064         }
2065         else if(command == TOCLIENT_DELETE_PARTICLESPAWNER)
2066         {
2067                 std::string datastring((char*)&data[2], datasize-2);
2068                 std::istringstream is(datastring, std::ios_base::binary);
2069
2070                 u32 id = readU16(is);
2071
2072                 ClientEvent event;
2073                 event.type = CE_DELETE_PARTICLESPAWNER;
2074                 event.delete_particlespawner.id = id;
2075
2076                 m_client_event_queue.push_back(event);
2077         }
2078         else if(command == TOCLIENT_HUDADD)
2079         {
2080                 std::string datastring((char *)&data[2], datasize - 2);
2081                 std::istringstream is(datastring, std::ios_base::binary);
2082
2083                 u32 id           = readU32(is);
2084                 u8 type          = readU8(is);
2085                 v2f pos          = readV2F1000(is);
2086                 std::string name = deSerializeString(is);
2087                 v2f scale        = readV2F1000(is);
2088                 std::string text = deSerializeString(is);
2089                 u32 number       = readU32(is);
2090                 u32 item         = readU32(is);
2091                 u32 dir          = readU32(is);
2092                 v2f align        = readV2F1000(is);
2093                 v2f offset       = readV2F1000(is);
2094
2095                 ClientEvent event;
2096                 event.type = CE_HUDADD;
2097                 event.hudadd.id     = id;
2098                 event.hudadd.type   = type;
2099                 event.hudadd.pos    = new v2f(pos);
2100                 event.hudadd.name   = new std::string(name);
2101                 event.hudadd.scale  = new v2f(scale);
2102                 event.hudadd.text   = new std::string(text);
2103                 event.hudadd.number = number;
2104                 event.hudadd.item   = item;
2105                 event.hudadd.dir    = dir;
2106                 event.hudadd.align  = new v2f(align);
2107                 event.hudadd.offset = new v2f(offset);
2108                 m_client_event_queue.push_back(event);
2109         }
2110         else if(command == TOCLIENT_HUDRM)
2111         {
2112                 std::string datastring((char *)&data[2], datasize - 2);
2113                 std::istringstream is(datastring, std::ios_base::binary);
2114
2115                 u32 id = readU32(is);
2116
2117                 ClientEvent event;
2118                 event.type = CE_HUDRM;
2119                 event.hudrm.id = id;
2120                 m_client_event_queue.push_back(event);
2121         }
2122         else if(command == TOCLIENT_HUDCHANGE)
2123         {       
2124                 std::string sdata;
2125                 v2f v2fdata;
2126                 u32 intdata = 0;
2127                 
2128                 std::string datastring((char *)&data[2], datasize - 2);
2129                 std::istringstream is(datastring, std::ios_base::binary);
2130
2131                 u32 id  = readU32(is);
2132                 u8 stat = (HudElementStat)readU8(is);
2133                 
2134                 if (stat == HUD_STAT_POS || stat == HUD_STAT_SCALE ||
2135                         stat == HUD_STAT_ALIGN || stat == HUD_STAT_OFFSET)
2136                         v2fdata = readV2F1000(is);
2137                 else if (stat == HUD_STAT_NAME || stat == HUD_STAT_TEXT)
2138                         sdata = deSerializeString(is);
2139                 else
2140                         intdata = readU32(is);
2141                 
2142                 ClientEvent event;
2143                 event.type = CE_HUDCHANGE;
2144                 event.hudchange.id      = id;
2145                 event.hudchange.stat    = (HudElementStat)stat;
2146                 event.hudchange.v2fdata = new v2f(v2fdata);
2147                 event.hudchange.sdata   = new std::string(sdata);
2148                 event.hudchange.data    = intdata;
2149                 m_client_event_queue.push_back(event);
2150         }
2151         else if(command == TOCLIENT_HUD_SET_FLAGS)
2152         {       
2153                 std::string datastring((char *)&data[2], datasize - 2);
2154                 std::istringstream is(datastring, std::ios_base::binary);
2155
2156                 Player *player = m_env.getLocalPlayer();
2157                 assert(player != NULL);
2158
2159                 u32 flags = readU32(is);
2160                 u32 mask  = readU32(is);
2161                 
2162                 player->hud_flags &= ~mask;
2163                 player->hud_flags |= flags;
2164         }
2165         else if(command == TOCLIENT_HUD_SET_PARAM)
2166         {
2167                 std::string datastring((char *)&data[2], datasize - 2);
2168                 std::istringstream is(datastring, std::ios_base::binary);
2169
2170                 Player *player = m_env.getLocalPlayer();
2171                 assert(player != NULL);
2172
2173                 u16 param         = readU16(is);
2174                 std::string value = deSerializeString(is);
2175
2176                 if(param == HUD_PARAM_HOTBAR_ITEMCOUNT && value.size() == 4){
2177                         s32 hotbar_itemcount = readS32((u8*) value.c_str());
2178                         if(hotbar_itemcount > 0 && hotbar_itemcount <= HUD_HOTBAR_ITEMCOUNT_MAX)
2179                                 player->hud_hotbar_itemcount = hotbar_itemcount;
2180                 } else if (param == HUD_PARAM_HOTBAR_IMAGE) {
2181                         ((LocalPlayer *) player)->hotbar_image = value;
2182                 } else if (param == HUD_PARAM_HOTBAR_SELECTED_IMAGE) {
2183                         ((LocalPlayer *) player)->hotbar_selected_image = value;
2184                 }
2185         }
2186         else
2187         {
2188                 infostream<<"Client: Ignoring unknown command "
2189                                 <<command<<std::endl;
2190         }
2191 }
2192
2193 void Client::Send(u16 channelnum, SharedBuffer<u8> data, bool reliable)
2194 {
2195         //JMutexAutoLock lock(m_con_mutex); //bulk comment-out
2196         m_con.Send(PEER_ID_SERVER, channelnum, data, reliable);
2197 }
2198
2199 void Client::interact(u8 action, const PointedThing& pointed)
2200 {
2201         if(connectedAndInitialized() == false){
2202                 infostream<<"Client::interact() "
2203                                 "cancelled (not connected)"
2204                                 <<std::endl;
2205                 return;
2206         }
2207
2208         std::ostringstream os(std::ios_base::binary);
2209
2210         /*
2211                 [0] u16 command
2212                 [2] u8 action
2213                 [3] u16 item
2214                 [5] u32 length of the next item
2215                 [9] serialized PointedThing
2216                 actions:
2217                 0: start digging (from undersurface) or use
2218                 1: stop digging (all parameters ignored)
2219                 2: digging completed
2220                 3: place block or item (to abovesurface)
2221                 4: use item
2222         */
2223         writeU16(os, TOSERVER_INTERACT);
2224         writeU8(os, action);
2225         writeU16(os, getPlayerItem());
2226         std::ostringstream tmp_os(std::ios::binary);
2227         pointed.serialize(tmp_os);
2228         os<<serializeLongString(tmp_os.str());
2229
2230         std::string s = os.str();
2231         SharedBuffer<u8> data((u8*)s.c_str(), s.size());
2232
2233         // Send as reliable
2234         Send(0, data, true);
2235 }
2236
2237 void Client::sendNodemetaFields(v3s16 p, const std::string &formname,
2238                 const std::map<std::string, std::string> &fields)
2239 {
2240         std::ostringstream os(std::ios_base::binary);
2241
2242         writeU16(os, TOSERVER_NODEMETA_FIELDS);
2243         writeV3S16(os, p);
2244         os<<serializeString(formname);
2245         writeU16(os, fields.size());
2246         for(std::map<std::string, std::string>::const_iterator
2247                         i = fields.begin(); i != fields.end(); i++){
2248                 const std::string &name = i->first;
2249                 const std::string &value = i->second;
2250                 os<<serializeString(name);
2251                 os<<serializeLongString(value);
2252         }
2253
2254         // Make data buffer
2255         std::string s = os.str();
2256         SharedBuffer<u8> data((u8*)s.c_str(), s.size());
2257         // Send as reliable
2258         Send(0, data, true);
2259 }
2260         
2261 void Client::sendInventoryFields(const std::string &formname, 
2262                 const std::map<std::string, std::string> &fields)
2263 {
2264         std::ostringstream os(std::ios_base::binary);
2265
2266         writeU16(os, TOSERVER_INVENTORY_FIELDS);
2267         os<<serializeString(formname);
2268         writeU16(os, fields.size());
2269         for(std::map<std::string, std::string>::const_iterator
2270                         i = fields.begin(); i != fields.end(); i++){
2271                 const std::string &name = i->first;
2272                 const std::string &value = i->second;
2273                 os<<serializeString(name);
2274                 os<<serializeLongString(value);
2275         }
2276
2277         // Make data buffer
2278         std::string s = os.str();
2279         SharedBuffer<u8> data((u8*)s.c_str(), s.size());
2280         // Send as reliable
2281         Send(0, data, true);
2282 }
2283
2284 void Client::sendInventoryAction(InventoryAction *a)
2285 {
2286         std::ostringstream os(std::ios_base::binary);
2287         u8 buf[12];
2288         
2289         // Write command
2290         writeU16(buf, TOSERVER_INVENTORY_ACTION);
2291         os.write((char*)buf, 2);
2292
2293         a->serialize(os);
2294         
2295         // Make data buffer
2296         std::string s = os.str();
2297         SharedBuffer<u8> data((u8*)s.c_str(), s.size());
2298         // Send as reliable
2299         Send(0, data, true);
2300 }
2301
2302 void Client::sendChatMessage(const std::wstring &message)
2303 {
2304         std::ostringstream os(std::ios_base::binary);
2305         u8 buf[12];
2306         
2307         // Write command
2308         writeU16(buf, TOSERVER_CHAT_MESSAGE);
2309         os.write((char*)buf, 2);
2310         
2311         // Write length
2312         writeU16(buf, message.size());
2313         os.write((char*)buf, 2);
2314         
2315         // Write string
2316         for(u32 i=0; i<message.size(); i++)
2317         {
2318                 u16 w = message[i];
2319                 writeU16(buf, w);
2320                 os.write((char*)buf, 2);
2321         }
2322         
2323         // Make data buffer
2324         std::string s = os.str();
2325         SharedBuffer<u8> data((u8*)s.c_str(), s.size());
2326         // Send as reliable
2327         Send(0, data, true);
2328 }
2329
2330 void Client::sendChangePassword(const std::wstring oldpassword,
2331                 const std::wstring newpassword)
2332 {
2333         Player *player = m_env.getLocalPlayer();
2334         if(player == NULL)
2335                 return;
2336
2337         std::string playername = player->getName();
2338         std::string oldpwd = translatePassword(playername, oldpassword);
2339         std::string newpwd = translatePassword(playername, newpassword);
2340
2341         std::ostringstream os(std::ios_base::binary);
2342         u8 buf[2+PASSWORD_SIZE*2];
2343         /*
2344                 [0] u16 TOSERVER_PASSWORD
2345                 [2] u8[28] old password
2346                 [30] u8[28] new password
2347         */
2348
2349         writeU16(buf, TOSERVER_PASSWORD);
2350         for(u32 i=0;i<PASSWORD_SIZE-1;i++)
2351         {
2352                 buf[2+i] = i<oldpwd.length()?oldpwd[i]:0;
2353                 buf[30+i] = i<newpwd.length()?newpwd[i]:0;
2354         }
2355         buf[2+PASSWORD_SIZE-1] = 0;
2356         buf[30+PASSWORD_SIZE-1] = 0;
2357         os.write((char*)buf, 2+PASSWORD_SIZE*2);
2358
2359         // Make data buffer
2360         std::string s = os.str();
2361         SharedBuffer<u8> data((u8*)s.c_str(), s.size());
2362         // Send as reliable
2363         Send(0, data, true);
2364 }
2365
2366
2367 void Client::sendDamage(u8 damage)
2368 {
2369         DSTACK(__FUNCTION_NAME);
2370         std::ostringstream os(std::ios_base::binary);
2371
2372         writeU16(os, TOSERVER_DAMAGE);
2373         writeU8(os, damage);
2374
2375         // Make data buffer
2376         std::string s = os.str();
2377         SharedBuffer<u8> data((u8*)s.c_str(), s.size());
2378         // Send as reliable
2379         Send(0, data, true);
2380 }
2381
2382 void Client::sendBreath(u16 breath)
2383 {
2384         DSTACK(__FUNCTION_NAME);
2385         std::ostringstream os(std::ios_base::binary);
2386
2387         writeU16(os, TOSERVER_BREATH);
2388         writeU16(os, breath);
2389         // Make data buffer
2390         std::string s = os.str();
2391         SharedBuffer<u8> data((u8*)s.c_str(), s.size());
2392         // Send as reliable
2393         Send(0, data, true);
2394 }
2395
2396 void Client::sendRespawn()
2397 {
2398         DSTACK(__FUNCTION_NAME);
2399         std::ostringstream os(std::ios_base::binary);
2400
2401         writeU16(os, TOSERVER_RESPAWN);
2402
2403         // Make data buffer
2404         std::string s = os.str();
2405         SharedBuffer<u8> data((u8*)s.c_str(), s.size());
2406         // Send as reliable
2407         Send(0, data, true);
2408 }
2409
2410 void Client::sendPlayerPos()
2411 {
2412         //JMutexAutoLock envlock(m_env_mutex); //bulk comment-out
2413         
2414         LocalPlayer *myplayer = m_env.getLocalPlayer();
2415         if(myplayer == NULL)
2416                 return;
2417
2418         // Save bandwidth by only updating position when something changed
2419         if(myplayer->last_position == myplayer->getPosition() &&
2420                         myplayer->last_speed == myplayer->getSpeed() &&
2421                         myplayer->last_pitch == myplayer->getPitch() &&
2422                         myplayer->last_yaw == myplayer->getYaw() &&
2423                         myplayer->last_keyPressed == myplayer->keyPressed)
2424                 return;
2425
2426         myplayer->last_position = myplayer->getPosition();
2427         myplayer->last_speed = myplayer->getSpeed();
2428         myplayer->last_pitch = myplayer->getPitch();
2429         myplayer->last_yaw = myplayer->getYaw();
2430         myplayer->last_keyPressed = myplayer->keyPressed;
2431
2432         u16 our_peer_id;
2433         {
2434                 //JMutexAutoLock lock(m_con_mutex); //bulk comment-out
2435                 our_peer_id = m_con.GetPeerID();
2436         }
2437         
2438         // Set peer id if not set already
2439         if(myplayer->peer_id == PEER_ID_INEXISTENT)
2440                 myplayer->peer_id = our_peer_id;
2441         // Check that an existing peer_id is the same as the connection's
2442         assert(myplayer->peer_id == our_peer_id);
2443         
2444         v3f pf = myplayer->getPosition();
2445         v3s32 position(pf.X*100, pf.Y*100, pf.Z*100);
2446         v3f sf = myplayer->getSpeed();
2447         v3s32 speed(sf.X*100, sf.Y*100, sf.Z*100);
2448         s32 pitch = myplayer->getPitch() * 100;
2449         s32 yaw = myplayer->getYaw() * 100;
2450         u32 keyPressed=myplayer->keyPressed;
2451         /*
2452                 Format:
2453                 [0] u16 command
2454                 [2] v3s32 position*100
2455                 [2+12] v3s32 speed*100
2456                 [2+12+12] s32 pitch*100
2457                 [2+12+12+4] s32 yaw*100
2458                 [2+12+12+4+4] u32 keyPressed
2459         */
2460         SharedBuffer<u8> data(2+12+12+4+4+4);
2461         writeU16(&data[0], TOSERVER_PLAYERPOS);
2462         writeV3S32(&data[2], position);
2463         writeV3S32(&data[2+12], speed);
2464         writeS32(&data[2+12+12], pitch);
2465         writeS32(&data[2+12+12+4], yaw);        
2466         writeU32(&data[2+12+12+4+4], keyPressed);
2467         // Send as unreliable
2468         Send(0, data, false);
2469 }
2470
2471 void Client::sendPlayerItem(u16 item)
2472 {
2473         Player *myplayer = m_env.getLocalPlayer();
2474         if(myplayer == NULL)
2475                 return;
2476
2477         u16 our_peer_id = m_con.GetPeerID();
2478
2479         // Set peer id if not set already
2480         if(myplayer->peer_id == PEER_ID_INEXISTENT)
2481                 myplayer->peer_id = our_peer_id;
2482         // Check that an existing peer_id is the same as the connection's
2483         assert(myplayer->peer_id == our_peer_id);
2484
2485         SharedBuffer<u8> data(2+2);
2486         writeU16(&data[0], TOSERVER_PLAYERITEM);
2487         writeU16(&data[2], item);
2488
2489         // Send as reliable
2490         Send(0, data, true);
2491 }
2492
2493 void Client::removeNode(v3s16 p)
2494 {
2495         std::map<v3s16, MapBlock*> modified_blocks;
2496
2497         try
2498         {
2499                 //TimeTaker t("removeNodeAndUpdate", m_device);
2500                 m_env.getMap().removeNodeAndUpdate(p, modified_blocks);
2501         }
2502         catch(InvalidPositionException &e)
2503         {
2504         }
2505         
2506         // add urgent task to update the modified node
2507         addUpdateMeshTaskForNode(p, false, true);
2508
2509         for(std::map<v3s16, MapBlock * >::iterator
2510                         i = modified_blocks.begin();
2511                         i != modified_blocks.end(); ++i)
2512         {
2513                 addUpdateMeshTaskWithEdge(i->first);
2514         }
2515 }
2516
2517 void Client::addNode(v3s16 p, MapNode n)
2518 {
2519         TimeTaker timer1("Client::addNode()");
2520
2521         std::map<v3s16, MapBlock*> modified_blocks;
2522
2523         try
2524         {
2525                 //TimeTaker timer3("Client::addNode(): addNodeAndUpdate");
2526                 m_env.getMap().addNodeAndUpdate(p, n, modified_blocks);
2527         }
2528         catch(InvalidPositionException &e)
2529         {}
2530         
2531         for(std::map<v3s16, MapBlock * >::iterator
2532                         i = modified_blocks.begin();
2533                         i != modified_blocks.end(); ++i)
2534         {
2535                 addUpdateMeshTaskWithEdge(i->first);
2536         }
2537 }
2538         
2539 void Client::setPlayerControl(PlayerControl &control)
2540 {
2541         //JMutexAutoLock envlock(m_env_mutex); //bulk comment-out
2542         LocalPlayer *player = m_env.getLocalPlayer();
2543         assert(player != NULL);
2544         player->control = control;
2545 }
2546
2547 void Client::selectPlayerItem(u16 item)
2548 {
2549         //JMutexAutoLock envlock(m_env_mutex); //bulk comment-out
2550         m_playeritem = item;
2551         m_inventory_updated = true;
2552         sendPlayerItem(item);
2553 }
2554
2555 // Returns true if the inventory of the local player has been
2556 // updated from the server. If it is true, it is set to false.
2557 bool Client::getLocalInventoryUpdated()
2558 {
2559         // m_inventory_updated is behind envlock
2560         //JMutexAutoLock envlock(m_env_mutex); //bulk comment-out
2561         bool updated = m_inventory_updated;
2562         m_inventory_updated = false;
2563         return updated;
2564 }
2565
2566 // Copies the inventory of the local player to parameter
2567 void Client::getLocalInventory(Inventory &dst)
2568 {
2569         //JMutexAutoLock envlock(m_env_mutex); //bulk comment-out
2570         Player *player = m_env.getLocalPlayer();
2571         assert(player != NULL);
2572         dst = player->inventory;
2573 }
2574
2575 Inventory* Client::getInventory(const InventoryLocation &loc)
2576 {
2577         switch(loc.type){
2578         case InventoryLocation::UNDEFINED:
2579         {}
2580         break;
2581         case InventoryLocation::CURRENT_PLAYER:
2582         {
2583                 Player *player = m_env.getLocalPlayer();
2584                 assert(player != NULL);
2585                 return &player->inventory;
2586         }
2587         break;
2588         case InventoryLocation::PLAYER:
2589         {
2590                 Player *player = m_env.getPlayer(loc.name.c_str());
2591                 if(!player)
2592                         return NULL;
2593                 return &player->inventory;
2594         }
2595         break;
2596         case InventoryLocation::NODEMETA:
2597         {
2598                 NodeMetadata *meta = m_env.getMap().getNodeMetadata(loc.p);
2599                 if(!meta)
2600                         return NULL;
2601                 return meta->getInventory();
2602         }
2603         break;
2604         case InventoryLocation::DETACHED:
2605         {
2606                 if(m_detached_inventories.count(loc.name) == 0)
2607                         return NULL;
2608                 return m_detached_inventories[loc.name];
2609         }
2610         break;
2611         default:
2612                 assert(0);
2613         }
2614         return NULL;
2615 }
2616 void Client::inventoryAction(InventoryAction *a)
2617 {
2618         /*
2619                 Send it to the server
2620         */
2621         sendInventoryAction(a);
2622
2623         /*
2624                 Predict some local inventory changes
2625         */
2626         a->clientApply(this, this);
2627
2628         // Remove it
2629         delete a;
2630 }
2631
2632 ClientActiveObject * Client::getSelectedActiveObject(
2633                 f32 max_d,
2634                 v3f from_pos_f_on_map,
2635                 core::line3d<f32> shootline_on_map
2636         )
2637 {
2638         std::vector<DistanceSortedActiveObject> objects;
2639
2640         m_env.getActiveObjects(from_pos_f_on_map, max_d, objects);
2641
2642         //infostream<<"Collected "<<objects.size()<<" nearby objects"<<std::endl;
2643         
2644         // Sort them.
2645         // After this, the closest object is the first in the array.
2646         std::sort(objects.begin(), objects.end());
2647
2648         for(u32 i=0; i<objects.size(); i++)
2649         {
2650                 ClientActiveObject *obj = objects[i].obj;
2651                 
2652                 core::aabbox3d<f32> *selection_box = obj->getSelectionBox();
2653                 if(selection_box == NULL)
2654                         continue;
2655
2656                 v3f pos = obj->getPosition();
2657
2658                 core::aabbox3d<f32> offsetted_box(
2659                                 selection_box->MinEdge + pos,
2660                                 selection_box->MaxEdge + pos
2661                 );
2662
2663                 if(offsetted_box.intersectsWithLine(shootline_on_map))
2664                 {
2665                         //infostream<<"Returning selected object"<<std::endl;
2666                         return obj;
2667                 }
2668         }
2669
2670         //infostream<<"No object selected; returning NULL."<<std::endl;
2671         return NULL;
2672 }
2673
2674 void Client::printDebugInfo(std::ostream &os)
2675 {
2676         //JMutexAutoLock lock1(m_fetchblock_mutex);
2677         /*JMutexAutoLock lock2(m_incoming_queue_mutex);
2678
2679         os<<"m_incoming_queue.getSize()="<<m_incoming_queue.getSize()
2680                 //<<", m_fetchblock_history.size()="<<m_fetchblock_history.size()
2681                 //<<", m_opt_not_found_history.size()="<<m_opt_not_found_history.size()
2682                 <<std::endl;*/
2683 }
2684
2685 std::list<std::string> Client::getConnectedPlayerNames()
2686 {
2687         return m_env.getPlayerNames();
2688 }
2689
2690 float Client::getAnimationTime()
2691 {
2692         return m_animation_time;
2693 }
2694
2695 int Client::getCrackLevel()
2696 {
2697         return m_crack_level;
2698 }
2699
2700 void Client::setCrack(int level, v3s16 pos)
2701 {
2702         int old_crack_level = m_crack_level;
2703         v3s16 old_crack_pos = m_crack_pos;
2704
2705         m_crack_level = level;
2706         m_crack_pos = pos;
2707
2708         if(old_crack_level >= 0 && (level < 0 || pos != old_crack_pos))
2709         {
2710                 // remove old crack
2711                 addUpdateMeshTaskForNode(old_crack_pos, false, true);
2712         }
2713         if(level >= 0 && (old_crack_level < 0 || pos != old_crack_pos))
2714         {
2715                 // add new crack
2716                 addUpdateMeshTaskForNode(pos, false, true);
2717         }
2718 }
2719
2720 u16 Client::getHP()
2721 {
2722         Player *player = m_env.getLocalPlayer();
2723         assert(player != NULL);
2724         return player->hp;
2725 }
2726
2727 u16 Client::getBreath()
2728 {
2729         Player *player = m_env.getLocalPlayer();
2730         assert(player != NULL);
2731         return player->getBreath();
2732 }
2733
2734 bool Client::getChatMessage(std::wstring &message)
2735 {
2736         if(m_chat_queue.size() == 0)
2737                 return false;
2738         message = m_chat_queue.pop_front();
2739         return true;
2740 }
2741
2742 void Client::typeChatMessage(const std::wstring &message)
2743 {
2744         // Discard empty line
2745         if(message == L"")
2746                 return;
2747
2748         // Send to others
2749         sendChatMessage(message);
2750
2751         // Show locally
2752         if (message[0] == L'/')
2753         {
2754                 m_chat_queue.push_back(
2755                                 (std::wstring)L"issued command: "+message);
2756         }
2757         else
2758         {
2759                 LocalPlayer *player = m_env.getLocalPlayer();
2760                 assert(player != NULL);
2761                 std::wstring name = narrow_to_wide(player->getName());
2762                 m_chat_queue.push_back(
2763                                 (std::wstring)L"<"+name+L"> "+message);
2764         }
2765 }
2766
2767 void Client::addUpdateMeshTask(v3s16 p, bool ack_to_server, bool urgent)
2768 {
2769         /*infostream<<"Client::addUpdateMeshTask(): "
2770                         <<"("<<p.X<<","<<p.Y<<","<<p.Z<<")"
2771                         <<" ack_to_server="<<ack_to_server
2772                         <<" urgent="<<urgent
2773                         <<std::endl;*/
2774
2775         MapBlock *b = m_env.getMap().getBlockNoCreateNoEx(p);
2776         if(b == NULL)
2777                 return;
2778         
2779         /*
2780                 Create a task to update the mesh of the block
2781         */
2782         
2783         MeshMakeData *data = new MeshMakeData(this);
2784         
2785         {
2786                 //TimeTaker timer("data fill");
2787                 // Release: ~0ms
2788                 // Debug: 1-6ms, avg=2ms
2789                 data->fill(b);
2790                 data->setCrack(m_crack_level, m_crack_pos);
2791                 data->setSmoothLighting(g_settings->getBool("smooth_lighting"));
2792         }
2793
2794         // Debug wait
2795         //while(m_mesh_update_thread.m_queue_in.size() > 0) sleep_ms(10);
2796         
2797         // Add task to queue
2798         m_mesh_update_thread.m_queue_in.addBlock(p, data, ack_to_server, urgent);
2799
2800         /*infostream<<"Mesh update input queue size is "
2801                         <<m_mesh_update_thread.m_queue_in.size()
2802                         <<std::endl;*/
2803 }
2804
2805 void Client::addUpdateMeshTaskWithEdge(v3s16 blockpos, bool ack_to_server, bool urgent)
2806 {
2807         /*{
2808                 v3s16 p = blockpos;
2809                 infostream<<"Client::addUpdateMeshTaskWithEdge(): "
2810                                 <<"("<<p.X<<","<<p.Y<<","<<p.Z<<")"
2811                                 <<std::endl;
2812         }*/
2813
2814         try{
2815                 v3s16 p = blockpos + v3s16(0,0,0);
2816                 //MapBlock *b = m_env.getMap().getBlockNoCreate(p);
2817                 addUpdateMeshTask(p, ack_to_server, urgent);
2818         }
2819         catch(InvalidPositionException &e){}
2820         // Leading edge
2821         for (int i=0;i<6;i++)
2822         {
2823                 try{
2824                         v3s16 p = blockpos + g_6dirs[i];
2825                         addUpdateMeshTask(p, false, urgent);
2826                 }
2827                 catch(InvalidPositionException &e){}
2828         }
2829 }
2830
2831 void Client::addUpdateMeshTaskForNode(v3s16 nodepos, bool ack_to_server, bool urgent)
2832 {
2833         {
2834                 v3s16 p = nodepos;
2835                 infostream<<"Client::addUpdateMeshTaskForNode(): "
2836                                 <<"("<<p.X<<","<<p.Y<<","<<p.Z<<")"
2837                                 <<std::endl;
2838         }
2839
2840         v3s16 blockpos = getNodeBlockPos(nodepos);
2841         v3s16 blockpos_relative = blockpos * MAP_BLOCKSIZE;
2842
2843         try{
2844                 v3s16 p = blockpos + v3s16(0,0,0);
2845                 addUpdateMeshTask(p, ack_to_server, urgent);
2846         }
2847         catch(InvalidPositionException &e){}
2848         // Leading edge
2849         if(nodepos.X == blockpos_relative.X){
2850                 try{
2851                         v3s16 p = blockpos + v3s16(-1,0,0);
2852                         addUpdateMeshTask(p, false, urgent);
2853                 }
2854                 catch(InvalidPositionException &e){}
2855         }
2856         if(nodepos.Y == blockpos_relative.Y){
2857                 try{
2858                         v3s16 p = blockpos + v3s16(0,-1,0);
2859                         addUpdateMeshTask(p, false, urgent);
2860                 }
2861                 catch(InvalidPositionException &e){}
2862         }
2863         if(nodepos.Z == blockpos_relative.Z){
2864                 try{
2865                         v3s16 p = blockpos + v3s16(0,0,-1);
2866                         addUpdateMeshTask(p, false, urgent);
2867                 }
2868                 catch(InvalidPositionException &e){}
2869         }
2870 }
2871
2872 ClientEvent Client::getClientEvent()
2873 {
2874         if(m_client_event_queue.size() == 0)
2875         {
2876                 ClientEvent event;
2877                 event.type = CE_NONE;
2878                 return event;
2879         }
2880         return m_client_event_queue.pop_front();
2881 }
2882
2883 void draw_load_screen(const std::wstring &text,
2884                 IrrlichtDevice* device, gui::IGUIFont* font,
2885                 float dtime=0 ,int percent=0, bool clouds=true);
2886 void Client::afterContentReceived(IrrlichtDevice *device, gui::IGUIFont* font)
2887 {
2888         infostream<<"Client::afterContentReceived() started"<<std::endl;
2889         assert(m_itemdef_received);
2890         assert(m_nodedef_received);
2891         assert(texturesReceived());
2892         
2893         // remove the information about which checksum each texture
2894         // ought to have
2895         m_media_name_sha1_map.clear();
2896
2897         // Rebuild inherited images and recreate textures
2898         infostream<<"- Rebuilding images and textures"<<std::endl;
2899         m_tsrc->rebuildImagesAndTextures();
2900
2901         // Rebuild shaders
2902         infostream<<"- Rebuilding shaders"<<std::endl;
2903         m_shsrc->rebuildShaders();
2904
2905         // Update node aliases
2906         infostream<<"- Updating node aliases"<<std::endl;
2907         m_nodedef->updateAliases(m_itemdef);
2908
2909         // Update node textures
2910         infostream<<"- Updating node textures"<<std::endl;
2911         m_nodedef->updateTextures(m_tsrc);
2912
2913         // Preload item textures and meshes if configured to
2914         if(g_settings->getBool("preload_item_visuals"))
2915         {
2916                 verbosestream<<"Updating item textures and meshes"<<std::endl;
2917                 wchar_t* text = wgettext("Item textures...");
2918                 draw_load_screen(text,device,font,0,0);
2919                 std::set<std::string> names = m_itemdef->getAll();
2920                 size_t size = names.size();
2921                 size_t count = 0;
2922                 int percent = 0;
2923                 for(std::set<std::string>::const_iterator
2924                                 i = names.begin(); i != names.end(); ++i){
2925                         // Asking for these caches the result
2926                         m_itemdef->getInventoryTexture(*i, this);
2927                         m_itemdef->getWieldMesh(*i, this);
2928                         count++;
2929                         percent = count*100/size;
2930                         if (count%50 == 0) // only update every 50 item
2931                                 draw_load_screen(text,device,font,0,percent);
2932                 }
2933                 delete[] text;
2934         }
2935
2936         // Start mesh update thread after setting up content definitions
2937         infostream<<"- Starting mesh update thread"<<std::endl;
2938         m_mesh_update_thread.Start();
2939         
2940         infostream<<"Client::afterContentReceived() done"<<std::endl;
2941 }
2942
2943 float Client::getRTT(void)
2944 {
2945         try{
2946                 return m_con.GetPeerAvgRTT(PEER_ID_SERVER);
2947         } catch(con::PeerNotFoundException &e){
2948                 return 1337;
2949         }
2950 }
2951
2952 // IGameDef interface
2953 // Under envlock
2954 IItemDefManager* Client::getItemDefManager()
2955 {
2956         return m_itemdef;
2957 }
2958 INodeDefManager* Client::getNodeDefManager()
2959 {
2960         return m_nodedef;
2961 }
2962 ICraftDefManager* Client::getCraftDefManager()
2963 {
2964         return NULL;
2965         //return m_craftdef;
2966 }
2967 ITextureSource* Client::getTextureSource()
2968 {
2969         return m_tsrc;
2970 }
2971 IShaderSource* Client::getShaderSource()
2972 {
2973         return m_shsrc;
2974 }
2975 u16 Client::allocateUnknownNodeId(const std::string &name)
2976 {
2977         errorstream<<"Client::allocateUnknownNodeId(): "
2978                         <<"Client cannot allocate node IDs"<<std::endl;
2979         assert(0);
2980         return CONTENT_IGNORE;
2981 }
2982 ISoundManager* Client::getSoundManager()
2983 {
2984         return m_sound;
2985 }
2986 MtEventManager* Client::getEventManager()
2987 {
2988         return m_event;
2989 }
2990