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