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