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