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