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