]> git.lizzy.rs Git - dragonfireclient.git/blob - src/client.cpp
ShaderSource and silly example shaders
[dragonfireclient.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         Player *myplayer = m_env.getLocalPlayer();
1980         if(myplayer == NULL)
1981                 return;
1982         
1983         u16 our_peer_id;
1984         {
1985                 //JMutexAutoLock lock(m_con_mutex); //bulk comment-out
1986                 our_peer_id = m_con.GetPeerID();
1987         }
1988         
1989         // Set peer id if not set already
1990         if(myplayer->peer_id == PEER_ID_INEXISTENT)
1991                 myplayer->peer_id = our_peer_id;
1992         // Check that an existing peer_id is the same as the connection's
1993         assert(myplayer->peer_id == our_peer_id);
1994         
1995         v3f pf = myplayer->getPosition();
1996         v3s32 position(pf.X*100, pf.Y*100, pf.Z*100);
1997         v3f sf = myplayer->getSpeed();
1998         v3s32 speed(sf.X*100, sf.Y*100, sf.Z*100);
1999         s32 pitch = myplayer->getPitch() * 100;
2000         s32 yaw = myplayer->getYaw() * 100;
2001         u32 keyPressed=myplayer->keyPressed;
2002         /*
2003                 Format:
2004                 [0] u16 command
2005                 [2] v3s32 position*100
2006                 [2+12] v3s32 speed*100
2007                 [2+12+12] s32 pitch*100
2008                 [2+12+12+4] s32 yaw*100
2009                 [2+12+12+4+4] u32 keyPressed
2010         */
2011         SharedBuffer<u8> data(2+12+12+4+4+4);
2012         writeU16(&data[0], TOSERVER_PLAYERPOS);
2013         writeV3S32(&data[2], position);
2014         writeV3S32(&data[2+12], speed);
2015         writeS32(&data[2+12+12], pitch);
2016         writeS32(&data[2+12+12+4], yaw);        
2017         writeU32(&data[2+12+12+4+4], keyPressed);
2018         // Send as unreliable
2019         Send(0, data, false);
2020 }
2021
2022 void Client::sendPlayerItem(u16 item)
2023 {
2024         Player *myplayer = m_env.getLocalPlayer();
2025         if(myplayer == NULL)
2026                 return;
2027
2028         u16 our_peer_id = m_con.GetPeerID();
2029
2030         // Set peer id if not set already
2031         if(myplayer->peer_id == PEER_ID_INEXISTENT)
2032                 myplayer->peer_id = our_peer_id;
2033         // Check that an existing peer_id is the same as the connection's
2034         assert(myplayer->peer_id == our_peer_id);
2035
2036         SharedBuffer<u8> data(2+2);
2037         writeU16(&data[0], TOSERVER_PLAYERITEM);
2038         writeU16(&data[2], item);
2039
2040         // Send as reliable
2041         Send(0, data, true);
2042 }
2043
2044 void Client::removeNode(v3s16 p)
2045 {
2046         core::map<v3s16, MapBlock*> modified_blocks;
2047
2048         try
2049         {
2050                 //TimeTaker t("removeNodeAndUpdate", m_device);
2051                 m_env.getMap().removeNodeAndUpdate(p, modified_blocks);
2052         }
2053         catch(InvalidPositionException &e)
2054         {
2055         }
2056         
2057         // add urgent task to update the modified node
2058         addUpdateMeshTaskForNode(p, false, true);
2059
2060         for(core::map<v3s16, MapBlock * >::Iterator
2061                         i = modified_blocks.getIterator();
2062                         i.atEnd() == false; i++)
2063         {
2064                 v3s16 p = i.getNode()->getKey();
2065                 addUpdateMeshTaskWithEdge(p);
2066         }
2067 }
2068
2069 void Client::addNode(v3s16 p, MapNode n)
2070 {
2071         TimeTaker timer1("Client::addNode()");
2072
2073         core::map<v3s16, MapBlock*> modified_blocks;
2074
2075         try
2076         {
2077                 //TimeTaker timer3("Client::addNode(): addNodeAndUpdate");
2078                 m_env.getMap().addNodeAndUpdate(p, n, modified_blocks);
2079         }
2080         catch(InvalidPositionException &e)
2081         {}
2082         
2083         for(core::map<v3s16, MapBlock * >::Iterator
2084                         i = modified_blocks.getIterator();
2085                         i.atEnd() == false; i++)
2086         {
2087                 v3s16 p = i.getNode()->getKey();
2088                 addUpdateMeshTaskWithEdge(p);
2089         }
2090 }
2091         
2092 void Client::setPlayerControl(PlayerControl &control)
2093 {
2094         //JMutexAutoLock envlock(m_env_mutex); //bulk comment-out
2095         LocalPlayer *player = m_env.getLocalPlayer();
2096         assert(player != NULL);
2097         player->control = control;
2098 }
2099
2100 void Client::selectPlayerItem(u16 item)
2101 {
2102         //JMutexAutoLock envlock(m_env_mutex); //bulk comment-out
2103         m_playeritem = item;
2104         m_inventory_updated = true;
2105         sendPlayerItem(item);
2106 }
2107
2108 // Returns true if the inventory of the local player has been
2109 // updated from the server. If it is true, it is set to false.
2110 bool Client::getLocalInventoryUpdated()
2111 {
2112         // m_inventory_updated is behind envlock
2113         //JMutexAutoLock envlock(m_env_mutex); //bulk comment-out
2114         bool updated = m_inventory_updated;
2115         m_inventory_updated = false;
2116         return updated;
2117 }
2118
2119 // Copies the inventory of the local player to parameter
2120 void Client::getLocalInventory(Inventory &dst)
2121 {
2122         //JMutexAutoLock envlock(m_env_mutex); //bulk comment-out
2123         Player *player = m_env.getLocalPlayer();
2124         assert(player != NULL);
2125         dst = player->inventory;
2126 }
2127
2128 Inventory* Client::getInventory(const InventoryLocation &loc)
2129 {
2130         switch(loc.type){
2131         case InventoryLocation::UNDEFINED:
2132         {}
2133         break;
2134         case InventoryLocation::CURRENT_PLAYER:
2135         {
2136                 Player *player = m_env.getLocalPlayer();
2137                 assert(player != NULL);
2138                 return &player->inventory;
2139         }
2140         break;
2141         case InventoryLocation::PLAYER:
2142         {
2143                 Player *player = m_env.getPlayer(loc.name.c_str());
2144                 if(!player)
2145                         return NULL;
2146                 return &player->inventory;
2147         }
2148         break;
2149         case InventoryLocation::NODEMETA:
2150         {
2151                 NodeMetadata *meta = m_env.getMap().getNodeMetadata(loc.p);
2152                 if(!meta)
2153                         return NULL;
2154                 return meta->getInventory();
2155         }
2156         break;
2157         case InventoryLocation::DETACHED:
2158         {
2159                 if(m_detached_inventories.count(loc.name) == 0)
2160                         return NULL;
2161                 return m_detached_inventories[loc.name];
2162         }
2163         break;
2164         default:
2165                 assert(0);
2166         }
2167         return NULL;
2168 }
2169 void Client::inventoryAction(InventoryAction *a)
2170 {
2171         /*
2172                 Send it to the server
2173         */
2174         sendInventoryAction(a);
2175
2176         /*
2177                 Predict some local inventory changes
2178         */
2179         a->clientApply(this, this);
2180 }
2181
2182 ClientActiveObject * Client::getSelectedActiveObject(
2183                 f32 max_d,
2184                 v3f from_pos_f_on_map,
2185                 core::line3d<f32> shootline_on_map
2186         )
2187 {
2188         core::array<DistanceSortedActiveObject> objects;
2189
2190         m_env.getActiveObjects(from_pos_f_on_map, max_d, objects);
2191
2192         //infostream<<"Collected "<<objects.size()<<" nearby objects"<<std::endl;
2193         
2194         // Sort them.
2195         // After this, the closest object is the first in the array.
2196         objects.sort();
2197
2198         for(u32 i=0; i<objects.size(); i++)
2199         {
2200                 ClientActiveObject *obj = objects[i].obj;
2201                 
2202                 core::aabbox3d<f32> *selection_box = obj->getSelectionBox();
2203                 if(selection_box == NULL)
2204                         continue;
2205
2206                 v3f pos = obj->getPosition();
2207
2208                 core::aabbox3d<f32> offsetted_box(
2209                                 selection_box->MinEdge + pos,
2210                                 selection_box->MaxEdge + pos
2211                 );
2212
2213                 if(offsetted_box.intersectsWithLine(shootline_on_map))
2214                 {
2215                         //infostream<<"Returning selected object"<<std::endl;
2216                         return obj;
2217                 }
2218         }
2219
2220         //infostream<<"No object selected; returning NULL."<<std::endl;
2221         return NULL;
2222 }
2223
2224 void Client::printDebugInfo(std::ostream &os)
2225 {
2226         //JMutexAutoLock lock1(m_fetchblock_mutex);
2227         /*JMutexAutoLock lock2(m_incoming_queue_mutex);
2228
2229         os<<"m_incoming_queue.getSize()="<<m_incoming_queue.getSize()
2230                 //<<", m_fetchblock_history.size()="<<m_fetchblock_history.size()
2231                 //<<", m_opt_not_found_history.size()="<<m_opt_not_found_history.size()
2232                 <<std::endl;*/
2233 }
2234
2235 core::list<std::wstring> Client::getConnectedPlayerNames()
2236 {
2237         core::list<Player*> players = m_env.getPlayers(true);
2238         core::list<std::wstring> playerNames;
2239         for(core::list<Player*>::Iterator
2240                         i = players.begin();
2241                         i != players.end(); i++)
2242         {
2243                 Player *player = *i;
2244                 playerNames.push_back(narrow_to_wide(player->getName()));
2245         }
2246         return playerNames;
2247 }
2248
2249 float Client::getAnimationTime()
2250 {
2251         return m_animation_time;
2252 }
2253
2254 int Client::getCrackLevel()
2255 {
2256         return m_crack_level;
2257 }
2258
2259 void Client::setCrack(int level, v3s16 pos)
2260 {
2261         int old_crack_level = m_crack_level;
2262         v3s16 old_crack_pos = m_crack_pos;
2263
2264         m_crack_level = level;
2265         m_crack_pos = pos;
2266
2267         if(old_crack_level >= 0 && (level < 0 || pos != old_crack_pos))
2268         {
2269                 // remove old crack
2270                 addUpdateMeshTaskForNode(old_crack_pos, false, true);
2271         }
2272         if(level >= 0 && (old_crack_level < 0 || pos != old_crack_pos))
2273         {
2274                 // add new crack
2275                 addUpdateMeshTaskForNode(pos, false, true);
2276         }
2277 }
2278
2279 u16 Client::getHP()
2280 {
2281         Player *player = m_env.getLocalPlayer();
2282         assert(player != NULL);
2283         return player->hp;
2284 }
2285
2286 bool Client::getChatMessage(std::wstring &message)
2287 {
2288         if(m_chat_queue.size() == 0)
2289                 return false;
2290         message = m_chat_queue.pop_front();
2291         return true;
2292 }
2293
2294 void Client::typeChatMessage(const std::wstring &message)
2295 {
2296         // Discard empty line
2297         if(message == L"")
2298                 return;
2299
2300         // Send to others
2301         sendChatMessage(message);
2302
2303         // Show locally
2304         if (message[0] == L'/')
2305         {
2306                 m_chat_queue.push_back(
2307                                 (std::wstring)L"issued command: "+message);
2308         }
2309         else
2310         {
2311                 LocalPlayer *player = m_env.getLocalPlayer();
2312                 assert(player != NULL);
2313                 std::wstring name = narrow_to_wide(player->getName());
2314                 m_chat_queue.push_back(
2315                                 (std::wstring)L"<"+name+L"> "+message);
2316         }
2317 }
2318
2319 void Client::addUpdateMeshTask(v3s16 p, bool ack_to_server, bool urgent)
2320 {
2321         /*infostream<<"Client::addUpdateMeshTask(): "
2322                         <<"("<<p.X<<","<<p.Y<<","<<p.Z<<")"
2323                         <<" ack_to_server="<<ack_to_server
2324                         <<" urgent="<<urgent
2325                         <<std::endl;*/
2326
2327         MapBlock *b = m_env.getMap().getBlockNoCreateNoEx(p);
2328         if(b == NULL)
2329                 return;
2330         
2331         /*
2332                 Create a task to update the mesh of the block
2333         */
2334         
2335         MeshMakeData *data = new MeshMakeData(this);
2336         
2337         {
2338                 //TimeTaker timer("data fill");
2339                 // Release: ~0ms
2340                 // Debug: 1-6ms, avg=2ms
2341                 data->fill(b);
2342                 data->setCrack(m_crack_level, m_crack_pos);
2343                 data->setSmoothLighting(g_settings->getBool("smooth_lighting"));
2344         }
2345
2346         // Debug wait
2347         //while(m_mesh_update_thread.m_queue_in.size() > 0) sleep_ms(10);
2348         
2349         // Add task to queue
2350         m_mesh_update_thread.m_queue_in.addBlock(p, data, ack_to_server, urgent);
2351
2352         /*infostream<<"Mesh update input queue size is "
2353                         <<m_mesh_update_thread.m_queue_in.size()
2354                         <<std::endl;*/
2355 }
2356
2357 void Client::addUpdateMeshTaskWithEdge(v3s16 blockpos, bool ack_to_server, bool urgent)
2358 {
2359         /*{
2360                 v3s16 p = blockpos;
2361                 infostream<<"Client::addUpdateMeshTaskWithEdge(): "
2362                                 <<"("<<p.X<<","<<p.Y<<","<<p.Z<<")"
2363                                 <<std::endl;
2364         }*/
2365
2366         try{
2367                 v3s16 p = blockpos + v3s16(0,0,0);
2368                 //MapBlock *b = m_env.getMap().getBlockNoCreate(p);
2369                 addUpdateMeshTask(p, ack_to_server, urgent);
2370         }
2371         catch(InvalidPositionException &e){}
2372         // Leading edge
2373         try{
2374                 v3s16 p = blockpos + v3s16(-1,0,0);
2375                 addUpdateMeshTask(p, false, urgent);
2376         }
2377         catch(InvalidPositionException &e){}
2378         try{
2379                 v3s16 p = blockpos + v3s16(0,-1,0);
2380                 addUpdateMeshTask(p, false, urgent);
2381         }
2382         catch(InvalidPositionException &e){}
2383         try{
2384                 v3s16 p = blockpos + v3s16(0,0,-1);
2385                 addUpdateMeshTask(p, false, urgent);
2386         }
2387         catch(InvalidPositionException &e){}
2388 }
2389
2390 void Client::addUpdateMeshTaskForNode(v3s16 nodepos, bool ack_to_server, bool urgent)
2391 {
2392         {
2393                 v3s16 p = nodepos;
2394                 infostream<<"Client::addUpdateMeshTaskForNode(): "
2395                                 <<"("<<p.X<<","<<p.Y<<","<<p.Z<<")"
2396                                 <<std::endl;
2397         }
2398
2399         v3s16 blockpos = getNodeBlockPos(nodepos);
2400         v3s16 blockpos_relative = blockpos * MAP_BLOCKSIZE;
2401
2402         try{
2403                 v3s16 p = blockpos + v3s16(0,0,0);
2404                 addUpdateMeshTask(p, ack_to_server, urgent);
2405         }
2406         catch(InvalidPositionException &e){}
2407         // Leading edge
2408         if(nodepos.X == blockpos_relative.X){
2409                 try{
2410                         v3s16 p = blockpos + v3s16(-1,0,0);
2411                         addUpdateMeshTask(p, false, urgent);
2412                 }
2413                 catch(InvalidPositionException &e){}
2414         }
2415         if(nodepos.Y == blockpos_relative.Y){
2416                 try{
2417                         v3s16 p = blockpos + v3s16(0,-1,0);
2418                         addUpdateMeshTask(p, false, urgent);
2419                 }
2420                 catch(InvalidPositionException &e){}
2421         }
2422         if(nodepos.Z == blockpos_relative.Z){
2423                 try{
2424                         v3s16 p = blockpos + v3s16(0,0,-1);
2425                         addUpdateMeshTask(p, false, urgent);
2426                 }
2427                 catch(InvalidPositionException &e){}
2428         }
2429 }
2430
2431 ClientEvent Client::getClientEvent()
2432 {
2433         if(m_client_event_queue.size() == 0)
2434         {
2435                 ClientEvent event;
2436                 event.type = CE_NONE;
2437                 return event;
2438         }
2439         return m_client_event_queue.pop_front();
2440 }
2441
2442 void Client::afterContentReceived()
2443 {
2444         infostream<<"Client::afterContentReceived() started"<<std::endl;
2445         assert(m_itemdef_received);
2446         assert(m_nodedef_received);
2447         assert(m_media_received);
2448         
2449         // remove the information about which checksum each texture
2450         // ought to have
2451         m_media_name_sha1_map.clear();
2452
2453         // Rebuild inherited images and recreate textures
2454         infostream<<"- Rebuilding images and textures"<<std::endl;
2455         m_tsrc->rebuildImagesAndTextures();
2456
2457         // Update texture atlas
2458         infostream<<"- Updating texture atlas"<<std::endl;
2459         if(g_settings->getBool("enable_texture_atlas"))
2460                 m_tsrc->buildMainAtlas(this);
2461
2462         // Rebuild shaders
2463         m_shsrc->rebuildShaders();
2464
2465         // Update node aliases
2466         infostream<<"- Updating node aliases"<<std::endl;
2467         m_nodedef->updateAliases(m_itemdef);
2468
2469         // Update node textures
2470         infostream<<"- Updating node textures"<<std::endl;
2471         m_nodedef->updateTextures(m_tsrc);
2472
2473         // Preload item textures and meshes if configured to
2474         if(g_settings->getBool("preload_item_visuals"))
2475         {
2476                 verbosestream<<"Updating item textures and meshes"<<std::endl;
2477                 std::set<std::string> names = m_itemdef->getAll();
2478                 for(std::set<std::string>::const_iterator
2479                                 i = names.begin(); i != names.end(); ++i){
2480                         // Asking for these caches the result
2481                         m_itemdef->getInventoryTexture(*i, this);
2482                         m_itemdef->getWieldMesh(*i, this);
2483                 }
2484         }
2485
2486         // Start mesh update thread after setting up content definitions
2487         infostream<<"- Starting mesh update thread"<<std::endl;
2488         m_mesh_update_thread.Start();
2489         
2490         infostream<<"Client::afterContentReceived() done"<<std::endl;
2491 }
2492
2493 float Client::getRTT(void)
2494 {
2495         try{
2496                 return m_con.GetPeerAvgRTT(PEER_ID_SERVER);
2497         } catch(con::PeerNotFoundException &e){
2498                 return 1337;
2499         }
2500 }
2501
2502 // IGameDef interface
2503 // Under envlock
2504 IItemDefManager* Client::getItemDefManager()
2505 {
2506         return m_itemdef;
2507 }
2508 INodeDefManager* Client::getNodeDefManager()
2509 {
2510         return m_nodedef;
2511 }
2512 ICraftDefManager* Client::getCraftDefManager()
2513 {
2514         return NULL;
2515         //return m_craftdef;
2516 }
2517 ITextureSource* Client::getTextureSource()
2518 {
2519         return m_tsrc;
2520 }
2521 IShaderSource* Client::getShaderSource()
2522 {
2523         return m_shsrc;
2524 }
2525 u16 Client::allocateUnknownNodeId(const std::string &name)
2526 {
2527         errorstream<<"Client::allocateUnknownNodeId(): "
2528                         <<"Client cannot allocate node IDs"<<std::endl;
2529         assert(0);
2530         return CONTENT_IGNORE;
2531 }
2532 ISoundManager* Client::getSoundManager()
2533 {
2534         return m_sound;
2535 }
2536 MtEventManager* Client::getEventManager()
2537 {
2538         return m_event;
2539 }
2540