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