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