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