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