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