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