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