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