]> git.lizzy.rs Git - dragonfireclient.git/blob - src/client.cpp
Implement sign using form field protocol
[dragonfireclient.git] / src / client.cpp
1 /*
2 Minetest-c55
3 Copyright (C) 2010 celeron55, Perttu Ahola <celeron55@gmail.com>
4
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 2 of the License, or
8 (at your option) any later version.
9
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License along
16 with this program; if not, write to the Free Software Foundation, Inc.,
17 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18 */
19
20 #include "client.h"
21 #include "utility.h"
22 #include <iostream>
23 #include "clientserver.h"
24 #include "jmutexautolock.h"
25 #include "main.h"
26 #include <sstream>
27 #include "porting.h"
28 #include "mapsector.h"
29 #include "mapblock_mesh.h"
30 #include "mapblock.h"
31 #include "settings.h"
32 #include "profiler.h"
33 #include "log.h"
34 #include "nodemetadata.h"
35 #include "nodedef.h"
36 #include "itemdef.h"
37 #include <IFileSystem.h>
38 #include "sha1.h"
39 #include "base64.h"
40 #include "clientmap.h"
41 #include "filecache.h"
42 #include "sound.h"
43 #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                 infostream<<"Client: WARNING: Ignoring TOCLIENT_PLAYERITEM"<<std::endl;
1401         }
1402         else if(command == TOCLIENT_DEATHSCREEN)
1403         {
1404                 std::string datastring((char*)&data[2], datasize-2);
1405                 std::istringstream is(datastring, std::ios_base::binary);
1406                 
1407                 bool set_camera_point_target = readU8(is);
1408                 v3f camera_point_target = readV3F1000(is);
1409                 
1410                 ClientEvent event;
1411                 event.type = CE_DEATHSCREEN;
1412                 event.deathscreen.set_camera_point_target = set_camera_point_target;
1413                 event.deathscreen.camera_point_target_x = camera_point_target.X;
1414                 event.deathscreen.camera_point_target_y = camera_point_target.Y;
1415                 event.deathscreen.camera_point_target_z = camera_point_target.Z;
1416                 m_client_event_queue.push_back(event);
1417         }
1418         else if(command == TOCLIENT_ANNOUNCE_MEDIA)
1419         {
1420                 std::string datastring((char*)&data[2], datasize-2);
1421                 std::istringstream is(datastring, std::ios_base::binary);
1422
1423                 // Mesh update thread must be stopped while
1424                 // updating content definitions
1425                 assert(!m_mesh_update_thread.IsRunning());
1426
1427                 int num_files = readU16(is);
1428                 
1429                 verbosestream<<"Client received TOCLIENT_ANNOUNCE_MEDIA ("
1430                                 <<num_files<<" files)"<<std::endl;
1431
1432                 core::list<MediaRequest> file_requests;
1433
1434                 for(int i=0; i<num_files; i++)
1435                 {
1436                         //read file from cache
1437                         std::string name = deSerializeString(is);
1438                         std::string sha1_base64 = deSerializeString(is);
1439
1440                         // if name contains illegal characters, ignore the file
1441                         if(!string_allowed(name, TEXTURENAME_ALLOWED_CHARS)){
1442                                 errorstream<<"Client: ignoring illegal file name "
1443                                                 <<"sent by server: \""<<name<<"\""<<std::endl;
1444                                 continue;
1445                         }
1446
1447                         std::string sha1_raw = base64_decode(sha1_base64);
1448                         std::string sha1_hex = hex_encode(sha1_raw);
1449                         std::ostringstream tmp_os(std::ios_base::binary);
1450                         bool found_in_cache = m_media_cache.load_sha1(sha1_raw, tmp_os);
1451                         m_media_name_sha1_map.set(name, sha1_raw);
1452
1453                         // If found in cache, try to load it from there
1454                         if(found_in_cache)
1455                         {
1456                                 bool success = loadMedia(tmp_os.str(), name);
1457                                 if(success){
1458                                         verbosestream<<"Client: Loaded cached media: "
1459                                                         <<sha1_hex<<" \""<<name<<"\""<<std::endl;
1460                                         continue;
1461                                 } else{
1462                                         infostream<<"Client: Failed to load cached media: "
1463                                                         <<sha1_hex<<" \""<<name<<"\""<<std::endl;
1464                                 }
1465                         }
1466                         // Didn't load from cache; queue it to be requested
1467                         verbosestream<<"Client: Adding file to request list: \""
1468                                         <<sha1_hex<<" \""<<name<<"\""<<std::endl;
1469                         file_requests.push_back(MediaRequest(name));
1470                 }
1471
1472                 ClientEvent event;
1473                 event.type = CE_TEXTURES_UPDATED;
1474                 m_client_event_queue.push_back(event);
1475
1476                 /*
1477                         u16 command
1478                         u16 number of files requested
1479                         for each file {
1480                                 u16 length of name
1481                                 string name
1482                         }
1483                 */
1484                 std::ostringstream os(std::ios_base::binary);
1485                 writeU16(os, TOSERVER_REQUEST_MEDIA);
1486                 writeU16(os, file_requests.size());
1487
1488                 for(core::list<MediaRequest>::Iterator i = file_requests.begin();
1489                                 i != file_requests.end(); i++) {
1490                         os<<serializeString(i->name);
1491                 }
1492
1493                 // Make data buffer
1494                 std::string s = os.str();
1495                 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
1496                 // Send as reliable
1497                 Send(0, data, true);
1498                 infostream<<"Client: Sending media request list to server ("
1499                                 <<file_requests.size()<<" files)"<<std::endl;
1500         }
1501         else if(command == TOCLIENT_MEDIA)
1502         {
1503                 std::string datastring((char*)&data[2], datasize-2);
1504                 std::istringstream is(datastring, std::ios_base::binary);
1505
1506                 // Mesh update thread must be stopped while
1507                 // updating content definitions
1508                 assert(!m_mesh_update_thread.IsRunning());
1509
1510                 /*
1511                         u16 command
1512                         u16 total number of file bunches
1513                         u16 index of this bunch
1514                         u32 number of files in this bunch
1515                         for each file {
1516                                 u16 length of name
1517                                 string name
1518                                 u32 length of data
1519                                 data
1520                         }
1521                 */
1522                 int num_bunches = readU16(is);
1523                 int bunch_i = readU16(is);
1524                 if(num_bunches >= 2)
1525                         m_media_receive_progress = (float)bunch_i / (float)(num_bunches - 1);
1526                 else
1527                         m_media_receive_progress = 1.0;
1528                 if(bunch_i == num_bunches - 1)
1529                         m_media_received = true;
1530                 int num_files = readU32(is);
1531                 infostream<<"Client: Received files: bunch "<<bunch_i<<"/"
1532                                 <<num_bunches<<" files="<<num_files
1533                                 <<" size="<<datasize<<std::endl;
1534                 for(int i=0; i<num_files; i++){
1535                         std::string name = deSerializeString(is);
1536                         std::string data = deSerializeLongString(is);
1537
1538                         // if name contains illegal characters, ignore the file
1539                         if(!string_allowed(name, TEXTURENAME_ALLOWED_CHARS)){
1540                                 errorstream<<"Client: ignoring illegal file name "
1541                                                 <<"sent by server: \""<<name<<"\""<<std::endl;
1542                                 continue;
1543                         }
1544                         
1545                         bool success = loadMedia(data, name);
1546                         if(success){
1547                                 verbosestream<<"Client: Loaded received media: "
1548                                                 <<"\""<<name<<"\". Caching."<<std::endl;
1549                         } else{
1550                                 infostream<<"Client: Failed to load received media: "
1551                                                 <<"\""<<name<<"\". Not caching."<<std::endl;
1552                                 continue;
1553                         }
1554
1555                         bool did = fs::CreateAllDirs(getMediaCacheDir());
1556                         if(!did){
1557                                 errorstream<<"Could not create media cache directory"
1558                                                 <<std::endl;
1559                         }
1560
1561                         {
1562                                 core::map<std::string, std::string>::Node *n;
1563                                 n = m_media_name_sha1_map.find(name);
1564                                 if(n == NULL)
1565                                         errorstream<<"The server sent a file that has not "
1566                                                         <<"been announced."<<std::endl;
1567                                 else
1568                                         m_media_cache.update_sha1(data);
1569                         }
1570                 }
1571
1572                 ClientEvent event;
1573                 event.type = CE_TEXTURES_UPDATED;
1574                 m_client_event_queue.push_back(event);
1575         }
1576         else if(command == TOCLIENT_TOOLDEF)
1577         {
1578                 infostream<<"Client: WARNING: Ignoring TOCLIENT_TOOLDEF"<<std::endl;
1579         }
1580         else if(command == TOCLIENT_NODEDEF)
1581         {
1582                 infostream<<"Client: Received node definitions: packet size: "
1583                                 <<datasize<<std::endl;
1584
1585                 // Mesh update thread must be stopped while
1586                 // updating content definitions
1587                 assert(!m_mesh_update_thread.IsRunning());
1588
1589                 // Decompress node definitions
1590                 std::string datastring((char*)&data[2], datasize-2);
1591                 std::istringstream is(datastring, std::ios_base::binary);
1592                 std::istringstream tmp_is(deSerializeLongString(is), std::ios::binary);
1593                 std::ostringstream tmp_os;
1594                 decompressZlib(tmp_is, tmp_os);
1595
1596                 // Deserialize node definitions
1597                 std::istringstream tmp_is2(tmp_os.str());
1598                 m_nodedef->deSerialize(tmp_is2);
1599                 m_nodedef_received = true;
1600         }
1601         else if(command == TOCLIENT_CRAFTITEMDEF)
1602         {
1603                 infostream<<"Client: WARNING: Ignoring TOCLIENT_CRAFTITEMDEF"<<std::endl;
1604         }
1605         else if(command == TOCLIENT_ITEMDEF)
1606         {
1607                 infostream<<"Client: Received item definitions: packet size: "
1608                                 <<datasize<<std::endl;
1609
1610                 // Mesh update thread must be stopped while
1611                 // updating content definitions
1612                 assert(!m_mesh_update_thread.IsRunning());
1613
1614                 // Decompress item definitions
1615                 std::string datastring((char*)&data[2], datasize-2);
1616                 std::istringstream is(datastring, std::ios_base::binary);
1617                 std::istringstream tmp_is(deSerializeLongString(is), std::ios::binary);
1618                 std::ostringstream tmp_os;
1619                 decompressZlib(tmp_is, tmp_os);
1620
1621                 // Deserialize node definitions
1622                 std::istringstream tmp_is2(tmp_os.str());
1623                 m_itemdef->deSerialize(tmp_is2);
1624                 m_itemdef_received = true;
1625         }
1626         else if(command == TOCLIENT_PLAY_SOUND)
1627         {
1628                 std::string datastring((char*)&data[2], datasize-2);
1629                 std::istringstream is(datastring, std::ios_base::binary);
1630
1631                 s32 server_id = readS32(is);
1632                 std::string name = deSerializeString(is);
1633                 float gain = readF1000(is);
1634                 int type = readU8(is); // 0=local, 1=positional, 2=object
1635                 v3f pos = readV3F1000(is);
1636                 u16 object_id = readU16(is);
1637                 bool loop = readU8(is);
1638                 // Start playing
1639                 int client_id = -1;
1640                 switch(type){
1641                 case 0: // local
1642                         client_id = m_sound->playSound(name, loop, gain);
1643                         break;
1644                 case 1: // positional
1645                         client_id = m_sound->playSoundAt(name, loop, gain, pos);
1646                         break;
1647                 case 2: { // object
1648                         ClientActiveObject *cao = m_env.getActiveObject(object_id);
1649                         if(cao)
1650                                 pos = cao->getPosition();
1651                         client_id = m_sound->playSoundAt(name, loop, gain, pos);
1652                         // TODO: Set up sound to move with object
1653                         break; }
1654                 default:
1655                         break;
1656                 }
1657                 if(client_id != -1){
1658                         m_sounds_server_to_client[server_id] = client_id;
1659                         m_sounds_client_to_server[client_id] = server_id;
1660                         if(object_id != 0)
1661                                 m_sounds_to_objects[client_id] = object_id;
1662                 }
1663         }
1664         else if(command == TOCLIENT_STOP_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::map<s32, int>::iterator i =
1671                                 m_sounds_server_to_client.find(server_id);
1672                 if(i != m_sounds_server_to_client.end()){
1673                         int client_id = i->second;
1674                         m_sound->stopSound(client_id);
1675                 }
1676         }
1677         else if(command == TOCLIENT_PRIVILEGES)
1678         {
1679                 std::string datastring((char*)&data[2], datasize-2);
1680                 std::istringstream is(datastring, std::ios_base::binary);
1681                 
1682                 m_privileges.clear();
1683                 infostream<<"Client: Privileges updated: ";
1684                 u16 num_privileges = readU16(is);
1685                 for(u16 i=0; i<num_privileges; i++){
1686                         std::string priv = deSerializeString(is);
1687                         m_privileges.insert(priv);
1688                         infostream<<priv<<" ";
1689                 }
1690                 infostream<<std::endl;
1691         }
1692         else
1693         {
1694                 infostream<<"Client: Ignoring unknown command "
1695                                 <<command<<std::endl;
1696         }
1697 }
1698
1699 void Client::Send(u16 channelnum, SharedBuffer<u8> data, bool reliable)
1700 {
1701         //JMutexAutoLock lock(m_con_mutex); //bulk comment-out
1702         m_con.Send(PEER_ID_SERVER, channelnum, data, reliable);
1703 }
1704
1705 void Client::interact(u8 action, const PointedThing& pointed)
1706 {
1707         if(connectedAndInitialized() == false){
1708                 infostream<<"Client::interact() "
1709                                 "cancelled (not connected)"
1710                                 <<std::endl;
1711                 return;
1712         }
1713
1714         std::ostringstream os(std::ios_base::binary);
1715
1716         /*
1717                 [0] u16 command
1718                 [2] u8 action
1719                 [3] u16 item
1720                 [5] u32 length of the next item
1721                 [9] serialized PointedThing
1722                 actions:
1723                 0: start digging (from undersurface) or use
1724                 1: stop digging (all parameters ignored)
1725                 2: digging completed
1726                 3: place block or item (to abovesurface)
1727                 4: use item
1728         */
1729         writeU16(os, TOSERVER_INTERACT);
1730         writeU8(os, action);
1731         writeU16(os, getPlayerItem());
1732         std::ostringstream tmp_os(std::ios::binary);
1733         pointed.serialize(tmp_os);
1734         os<<serializeLongString(tmp_os.str());
1735
1736         std::string s = os.str();
1737         SharedBuffer<u8> data((u8*)s.c_str(), s.size());
1738
1739         // Send as reliable
1740         Send(0, data, true);
1741 }
1742
1743 void Client::sendNodemetaFields(v3s16 p, const std::string &formname,
1744                 const std::map<std::string, std::string> &fields)
1745 {
1746         std::ostringstream os(std::ios_base::binary);
1747
1748         writeU16(os, TOSERVER_NODEMETA_FIELDS);
1749         writeV3S16(os, p);
1750         os<<serializeString(formname);
1751         writeU16(os, fields.size());
1752         for(std::map<std::string, std::string>::const_iterator
1753                         i = fields.begin(); i != fields.end(); i++){
1754                 const std::string &name = i->first;
1755                 const std::string &value = i->second;
1756                 os<<serializeString(name);
1757                 os<<serializeLongString(value);
1758         }
1759
1760         // Make data buffer
1761         std::string s = os.str();
1762         SharedBuffer<u8> data((u8*)s.c_str(), s.size());
1763         // Send as reliable
1764         Send(0, data, true);
1765 }
1766         
1767 void Client::sendInventoryAction(InventoryAction *a)
1768 {
1769         std::ostringstream os(std::ios_base::binary);
1770         u8 buf[12];
1771         
1772         // Write command
1773         writeU16(buf, TOSERVER_INVENTORY_ACTION);
1774         os.write((char*)buf, 2);
1775
1776         a->serialize(os);
1777         
1778         // Make data buffer
1779         std::string s = os.str();
1780         SharedBuffer<u8> data((u8*)s.c_str(), s.size());
1781         // Send as reliable
1782         Send(0, data, true);
1783 }
1784
1785 void Client::sendChatMessage(const std::wstring &message)
1786 {
1787         std::ostringstream os(std::ios_base::binary);
1788         u8 buf[12];
1789         
1790         // Write command
1791         writeU16(buf, TOSERVER_CHAT_MESSAGE);
1792         os.write((char*)buf, 2);
1793         
1794         // Write length
1795         writeU16(buf, message.size());
1796         os.write((char*)buf, 2);
1797         
1798         // Write string
1799         for(u32 i=0; i<message.size(); i++)
1800         {
1801                 u16 w = message[i];
1802                 writeU16(buf, w);
1803                 os.write((char*)buf, 2);
1804         }
1805         
1806         // Make data buffer
1807         std::string s = os.str();
1808         SharedBuffer<u8> data((u8*)s.c_str(), s.size());
1809         // Send as reliable
1810         Send(0, data, true);
1811 }
1812
1813 void Client::sendChangePassword(const std::wstring oldpassword,
1814                 const std::wstring newpassword)
1815 {
1816         Player *player = m_env.getLocalPlayer();
1817         if(player == NULL)
1818                 return;
1819
1820         std::string playername = player->getName();
1821         std::string oldpwd = translatePassword(playername, oldpassword);
1822         std::string newpwd = translatePassword(playername, newpassword);
1823
1824         std::ostringstream os(std::ios_base::binary);
1825         u8 buf[2+PASSWORD_SIZE*2];
1826         /*
1827                 [0] u16 TOSERVER_PASSWORD
1828                 [2] u8[28] old password
1829                 [30] u8[28] new password
1830         */
1831
1832         writeU16(buf, TOSERVER_PASSWORD);
1833         for(u32 i=0;i<PASSWORD_SIZE-1;i++)
1834         {
1835                 buf[2+i] = i<oldpwd.length()?oldpwd[i]:0;
1836                 buf[30+i] = i<newpwd.length()?newpwd[i]:0;
1837         }
1838         buf[2+PASSWORD_SIZE-1] = 0;
1839         buf[30+PASSWORD_SIZE-1] = 0;
1840         os.write((char*)buf, 2+PASSWORD_SIZE*2);
1841
1842         // Make data buffer
1843         std::string s = os.str();
1844         SharedBuffer<u8> data((u8*)s.c_str(), s.size());
1845         // Send as reliable
1846         Send(0, data, true);
1847 }
1848
1849
1850 void Client::sendDamage(u8 damage)
1851 {
1852         DSTACK(__FUNCTION_NAME);
1853         std::ostringstream os(std::ios_base::binary);
1854
1855         writeU16(os, TOSERVER_DAMAGE);
1856         writeU8(os, damage);
1857
1858         // Make data buffer
1859         std::string s = os.str();
1860         SharedBuffer<u8> data((u8*)s.c_str(), s.size());
1861         // Send as reliable
1862         Send(0, data, true);
1863 }
1864
1865 void Client::sendRespawn()
1866 {
1867         DSTACK(__FUNCTION_NAME);
1868         std::ostringstream os(std::ios_base::binary);
1869
1870         writeU16(os, TOSERVER_RESPAWN);
1871
1872         // Make data buffer
1873         std::string s = os.str();
1874         SharedBuffer<u8> data((u8*)s.c_str(), s.size());
1875         // Send as reliable
1876         Send(0, data, true);
1877 }
1878
1879 void Client::sendPlayerPos()
1880 {
1881         //JMutexAutoLock envlock(m_env_mutex); //bulk comment-out
1882         
1883         Player *myplayer = m_env.getLocalPlayer();
1884         if(myplayer == NULL)
1885                 return;
1886         
1887         u16 our_peer_id;
1888         {
1889                 //JMutexAutoLock lock(m_con_mutex); //bulk comment-out
1890                 our_peer_id = m_con.GetPeerID();
1891         }
1892         
1893         // Set peer id if not set already
1894         if(myplayer->peer_id == PEER_ID_INEXISTENT)
1895                 myplayer->peer_id = our_peer_id;
1896         // Check that an existing peer_id is the same as the connection's
1897         assert(myplayer->peer_id == our_peer_id);
1898         
1899         v3f pf = myplayer->getPosition();
1900         v3s32 position(pf.X*100, pf.Y*100, pf.Z*100);
1901         v3f sf = myplayer->getSpeed();
1902         v3s32 speed(sf.X*100, sf.Y*100, sf.Z*100);
1903         s32 pitch = myplayer->getPitch() * 100;
1904         s32 yaw = myplayer->getYaw() * 100;
1905
1906         /*
1907                 Format:
1908                 [0] u16 command
1909                 [2] v3s32 position*100
1910                 [2+12] v3s32 speed*100
1911                 [2+12+12] s32 pitch*100
1912                 [2+12+12+4] s32 yaw*100
1913         */
1914
1915         SharedBuffer<u8> data(2+12+12+4+4);
1916         writeU16(&data[0], TOSERVER_PLAYERPOS);
1917         writeV3S32(&data[2], position);
1918         writeV3S32(&data[2+12], speed);
1919         writeS32(&data[2+12+12], pitch);
1920         writeS32(&data[2+12+12+4], yaw);
1921
1922         // Send as unreliable
1923         Send(0, data, false);
1924 }
1925
1926 void Client::sendPlayerItem(u16 item)
1927 {
1928         Player *myplayer = m_env.getLocalPlayer();
1929         if(myplayer == NULL)
1930                 return;
1931
1932         u16 our_peer_id = m_con.GetPeerID();
1933
1934         // Set peer id if not set already
1935         if(myplayer->peer_id == PEER_ID_INEXISTENT)
1936                 myplayer->peer_id = our_peer_id;
1937         // Check that an existing peer_id is the same as the connection's
1938         assert(myplayer->peer_id == our_peer_id);
1939
1940         SharedBuffer<u8> data(2+2);
1941         writeU16(&data[0], TOSERVER_PLAYERITEM);
1942         writeU16(&data[2], item);
1943
1944         // Send as reliable
1945         Send(0, data, true);
1946 }
1947
1948 void Client::removeNode(v3s16 p)
1949 {
1950         core::map<v3s16, MapBlock*> modified_blocks;
1951
1952         try
1953         {
1954                 //TimeTaker t("removeNodeAndUpdate", m_device);
1955                 m_env.getMap().removeNodeAndUpdate(p, modified_blocks);
1956         }
1957         catch(InvalidPositionException &e)
1958         {
1959         }
1960         
1961         // add urgent task to update the modified node
1962         addUpdateMeshTaskForNode(p, false, true);
1963
1964         for(core::map<v3s16, MapBlock * >::Iterator
1965                         i = modified_blocks.getIterator();
1966                         i.atEnd() == false; i++)
1967         {
1968                 v3s16 p = i.getNode()->getKey();
1969                 addUpdateMeshTaskWithEdge(p);
1970         }
1971 }
1972
1973 void Client::addNode(v3s16 p, MapNode n)
1974 {
1975         TimeTaker timer1("Client::addNode()");
1976
1977         core::map<v3s16, MapBlock*> modified_blocks;
1978
1979         try
1980         {
1981                 //TimeTaker timer3("Client::addNode(): addNodeAndUpdate");
1982                 m_env.getMap().addNodeAndUpdate(p, n, modified_blocks);
1983         }
1984         catch(InvalidPositionException &e)
1985         {}
1986         
1987         for(core::map<v3s16, MapBlock * >::Iterator
1988                         i = modified_blocks.getIterator();
1989                         i.atEnd() == false; i++)
1990         {
1991                 v3s16 p = i.getNode()->getKey();
1992                 addUpdateMeshTaskWithEdge(p);
1993         }
1994 }
1995         
1996 void Client::setPlayerControl(PlayerControl &control)
1997 {
1998         //JMutexAutoLock envlock(m_env_mutex); //bulk comment-out
1999         LocalPlayer *player = m_env.getLocalPlayer();
2000         assert(player != NULL);
2001         player->control = control;
2002 }
2003
2004 void Client::selectPlayerItem(u16 item)
2005 {
2006         //JMutexAutoLock envlock(m_env_mutex); //bulk comment-out
2007         m_playeritem = item;
2008         m_inventory_updated = true;
2009         sendPlayerItem(item);
2010 }
2011
2012 // Returns true if the inventory of the local player has been
2013 // updated from the server. If it is true, it is set to false.
2014 bool Client::getLocalInventoryUpdated()
2015 {
2016         // m_inventory_updated is behind envlock
2017         //JMutexAutoLock envlock(m_env_mutex); //bulk comment-out
2018         bool updated = m_inventory_updated;
2019         m_inventory_updated = false;
2020         return updated;
2021 }
2022
2023 // Copies the inventory of the local player to parameter
2024 void Client::getLocalInventory(Inventory &dst)
2025 {
2026         //JMutexAutoLock envlock(m_env_mutex); //bulk comment-out
2027         Player *player = m_env.getLocalPlayer();
2028         assert(player != NULL);
2029         dst = player->inventory;
2030 }
2031
2032 Inventory* Client::getInventory(const InventoryLocation &loc)
2033 {
2034         switch(loc.type){
2035         case InventoryLocation::UNDEFINED:
2036         {}
2037         break;
2038         case InventoryLocation::CURRENT_PLAYER:
2039         {
2040                 Player *player = m_env.getLocalPlayer();
2041                 assert(player != NULL);
2042                 return &player->inventory;
2043         }
2044         break;
2045         case InventoryLocation::PLAYER:
2046         {
2047                 Player *player = m_env.getPlayer(loc.name.c_str());
2048                 if(!player)
2049                         return NULL;
2050                 return &player->inventory;
2051         }
2052         break;
2053         case InventoryLocation::NODEMETA:
2054         {
2055                 NodeMetadata *meta = m_env.getMap().getNodeMetadata(loc.p);
2056                 if(!meta)
2057                         return NULL;
2058                 return meta->getInventory();
2059         }
2060         break;
2061         default:
2062                 assert(0);
2063         }
2064         return NULL;
2065 }
2066 void Client::inventoryAction(InventoryAction *a)
2067 {
2068         /*
2069                 Send it to the server
2070         */
2071         sendInventoryAction(a);
2072
2073         /*
2074                 Predict some local inventory changes
2075         */
2076         a->clientApply(this, this);
2077 }
2078
2079 ClientActiveObject * Client::getSelectedActiveObject(
2080                 f32 max_d,
2081                 v3f from_pos_f_on_map,
2082                 core::line3d<f32> shootline_on_map
2083         )
2084 {
2085         core::array<DistanceSortedActiveObject> objects;
2086
2087         m_env.getActiveObjects(from_pos_f_on_map, max_d, objects);
2088
2089         //infostream<<"Collected "<<objects.size()<<" nearby objects"<<std::endl;
2090         
2091         // Sort them.
2092         // After this, the closest object is the first in the array.
2093         objects.sort();
2094
2095         for(u32 i=0; i<objects.size(); i++)
2096         {
2097                 ClientActiveObject *obj = objects[i].obj;
2098                 
2099                 core::aabbox3d<f32> *selection_box = obj->getSelectionBox();
2100                 if(selection_box == NULL)
2101                         continue;
2102
2103                 v3f pos = obj->getPosition();
2104
2105                 core::aabbox3d<f32> offsetted_box(
2106                                 selection_box->MinEdge + pos,
2107                                 selection_box->MaxEdge + pos
2108                 );
2109
2110                 if(offsetted_box.intersectsWithLine(shootline_on_map))
2111                 {
2112                         //infostream<<"Returning selected object"<<std::endl;
2113                         return obj;
2114                 }
2115         }
2116
2117         //infostream<<"No object selected; returning NULL."<<std::endl;
2118         return NULL;
2119 }
2120
2121 void Client::printDebugInfo(std::ostream &os)
2122 {
2123         //JMutexAutoLock lock1(m_fetchblock_mutex);
2124         /*JMutexAutoLock lock2(m_incoming_queue_mutex);
2125
2126         os<<"m_incoming_queue.getSize()="<<m_incoming_queue.getSize()
2127                 //<<", m_fetchblock_history.size()="<<m_fetchblock_history.size()
2128                 //<<", m_opt_not_found_history.size()="<<m_opt_not_found_history.size()
2129                 <<std::endl;*/
2130 }
2131
2132 core::list<std::wstring> Client::getConnectedPlayerNames()
2133 {
2134         core::list<Player*> players = m_env.getPlayers(true);
2135         core::list<std::wstring> playerNames;
2136         for(core::list<Player*>::Iterator
2137                         i = players.begin();
2138                         i != players.end(); i++)
2139         {
2140                 Player *player = *i;
2141                 playerNames.push_back(narrow_to_wide(player->getName()));
2142         }
2143         return playerNames;
2144 }
2145
2146 float Client::getAnimationTime()
2147 {
2148         return m_animation_time;
2149 }
2150
2151 int Client::getCrackLevel()
2152 {
2153         return m_crack_level;
2154 }
2155
2156 void Client::setCrack(int level, v3s16 pos)
2157 {
2158         int old_crack_level = m_crack_level;
2159         v3s16 old_crack_pos = m_crack_pos;
2160
2161         m_crack_level = level;
2162         m_crack_pos = pos;
2163
2164         if(old_crack_level >= 0 && (level < 0 || pos != old_crack_pos))
2165         {
2166                 // remove old crack
2167                 addUpdateMeshTaskForNode(old_crack_pos, false, true);
2168         }
2169         if(level >= 0 && (old_crack_level < 0 || pos != old_crack_pos))
2170         {
2171                 // add new crack
2172                 addUpdateMeshTaskForNode(pos, false, true);
2173         }
2174 }
2175
2176 u16 Client::getHP()
2177 {
2178         Player *player = m_env.getLocalPlayer();
2179         assert(player != NULL);
2180         return player->hp;
2181 }
2182
2183 bool Client::getChatMessage(std::wstring &message)
2184 {
2185         if(m_chat_queue.size() == 0)
2186                 return false;
2187         message = m_chat_queue.pop_front();
2188         return true;
2189 }
2190
2191 void Client::typeChatMessage(const std::wstring &message)
2192 {
2193         // Discard empty line
2194         if(message == L"")
2195                 return;
2196
2197         // Send to others
2198         sendChatMessage(message);
2199
2200         // Show locally
2201         if (message[0] == L'/')
2202         {
2203                 m_chat_queue.push_back(
2204                                 (std::wstring)L"issued command: "+message);
2205         }
2206         else
2207         {
2208                 LocalPlayer *player = m_env.getLocalPlayer();
2209                 assert(player != NULL);
2210                 std::wstring name = narrow_to_wide(player->getName());
2211                 m_chat_queue.push_back(
2212                                 (std::wstring)L"<"+name+L"> "+message);
2213         }
2214 }
2215
2216 void Client::addUpdateMeshTask(v3s16 p, bool ack_to_server, bool urgent)
2217 {
2218         /*infostream<<"Client::addUpdateMeshTask(): "
2219                         <<"("<<p.X<<","<<p.Y<<","<<p.Z<<")"
2220                         <<" ack_to_server="<<ack_to_server
2221                         <<" urgent="<<urgent
2222                         <<std::endl;*/
2223
2224         MapBlock *b = m_env.getMap().getBlockNoCreateNoEx(p);
2225         if(b == NULL)
2226                 return;
2227         
2228         /*
2229                 Create a task to update the mesh of the block
2230         */
2231         
2232         MeshMakeData *data = new MeshMakeData(this);
2233         
2234         {
2235                 //TimeTaker timer("data fill");
2236                 // Release: ~0ms
2237                 // Debug: 1-6ms, avg=2ms
2238                 data->fill(b);
2239                 data->setCrack(m_crack_level, m_crack_pos);
2240                 data->setSmoothLighting(g_settings->getBool("smooth_lighting"));
2241         }
2242
2243         // Debug wait
2244         //while(m_mesh_update_thread.m_queue_in.size() > 0) sleep_ms(10);
2245         
2246         // Add task to queue
2247         m_mesh_update_thread.m_queue_in.addBlock(p, data, ack_to_server, urgent);
2248
2249         /*infostream<<"Mesh update input queue size is "
2250                         <<m_mesh_update_thread.m_queue_in.size()
2251                         <<std::endl;*/
2252 }
2253
2254 void Client::addUpdateMeshTaskWithEdge(v3s16 blockpos, bool ack_to_server, bool urgent)
2255 {
2256         /*{
2257                 v3s16 p = blockpos;
2258                 infostream<<"Client::addUpdateMeshTaskWithEdge(): "
2259                                 <<"("<<p.X<<","<<p.Y<<","<<p.Z<<")"
2260                                 <<std::endl;
2261         }*/
2262
2263         try{
2264                 v3s16 p = blockpos + v3s16(0,0,0);
2265                 //MapBlock *b = m_env.getMap().getBlockNoCreate(p);
2266                 addUpdateMeshTask(p, ack_to_server, urgent);
2267         }
2268         catch(InvalidPositionException &e){}
2269         // Leading edge
2270         try{
2271                 v3s16 p = blockpos + v3s16(-1,0,0);
2272                 addUpdateMeshTask(p, false, urgent);
2273         }
2274         catch(InvalidPositionException &e){}
2275         try{
2276                 v3s16 p = blockpos + v3s16(0,-1,0);
2277                 addUpdateMeshTask(p, false, urgent);
2278         }
2279         catch(InvalidPositionException &e){}
2280         try{
2281                 v3s16 p = blockpos + v3s16(0,0,-1);
2282                 addUpdateMeshTask(p, false, urgent);
2283         }
2284         catch(InvalidPositionException &e){}
2285 }
2286
2287 void Client::addUpdateMeshTaskForNode(v3s16 nodepos, bool ack_to_server, bool urgent)
2288 {
2289         {
2290                 v3s16 p = nodepos;
2291                 infostream<<"Client::addUpdateMeshTaskForNode(): "
2292                                 <<"("<<p.X<<","<<p.Y<<","<<p.Z<<")"
2293                                 <<std::endl;
2294         }
2295
2296         v3s16 blockpos = getNodeBlockPos(nodepos);
2297         v3s16 blockpos_relative = blockpos * MAP_BLOCKSIZE;
2298
2299         try{
2300                 v3s16 p = blockpos + v3s16(0,0,0);
2301                 addUpdateMeshTask(p, ack_to_server, urgent);
2302         }
2303         catch(InvalidPositionException &e){}
2304         // Leading edge
2305         if(nodepos.X == blockpos_relative.X){
2306                 try{
2307                         v3s16 p = blockpos + v3s16(-1,0,0);
2308                         addUpdateMeshTask(p, false, urgent);
2309                 }
2310                 catch(InvalidPositionException &e){}
2311         }
2312         if(nodepos.Y == blockpos_relative.Y){
2313                 try{
2314                         v3s16 p = blockpos + v3s16(0,-1,0);
2315                         addUpdateMeshTask(p, false, urgent);
2316                 }
2317                 catch(InvalidPositionException &e){}
2318         }
2319         if(nodepos.Z == blockpos_relative.Z){
2320                 try{
2321                         v3s16 p = blockpos + v3s16(0,0,-1);
2322                         addUpdateMeshTask(p, false, urgent);
2323                 }
2324                 catch(InvalidPositionException &e){}
2325         }
2326 }
2327
2328 ClientEvent Client::getClientEvent()
2329 {
2330         if(m_client_event_queue.size() == 0)
2331         {
2332                 ClientEvent event;
2333                 event.type = CE_NONE;
2334                 return event;
2335         }
2336         return m_client_event_queue.pop_front();
2337 }
2338
2339 void Client::afterContentReceived()
2340 {
2341         verbosestream<<"Client::afterContentReceived() started"<<std::endl;
2342         assert(m_itemdef_received);
2343         assert(m_nodedef_received);
2344         assert(m_media_received);
2345         
2346         // remove the information about which checksum each texture
2347         // ought to have
2348         m_media_name_sha1_map.clear();
2349
2350         // Rebuild inherited images and recreate textures
2351         verbosestream<<"Rebuilding images and textures"<<std::endl;
2352         m_tsrc->rebuildImagesAndTextures();
2353
2354         // Update texture atlas
2355         verbosestream<<"Updating texture atlas"<<std::endl;
2356         if(g_settings->getBool("enable_texture_atlas"))
2357                 m_tsrc->buildMainAtlas(this);
2358
2359         // Update node aliases
2360         verbosestream<<"Updating node aliases"<<std::endl;
2361         m_nodedef->updateAliases(m_itemdef);
2362
2363         // Update node textures
2364         verbosestream<<"Updating node textures"<<std::endl;
2365         m_nodedef->updateTextures(m_tsrc);
2366
2367         // Update item textures and meshes
2368         verbosestream<<"Updating item textures and meshes"<<std::endl;
2369         m_itemdef->updateTexturesAndMeshes(this);
2370
2371         // Start mesh update thread after setting up content definitions
2372         verbosestream<<"Starting mesh update thread"<<std::endl;
2373         m_mesh_update_thread.Start();
2374         
2375         verbosestream<<"Client::afterContentReceived() done"<<std::endl;
2376 }
2377
2378 float Client::getRTT(void)
2379 {
2380         try{
2381                 return m_con.GetPeerAvgRTT(PEER_ID_SERVER);
2382         } catch(con::PeerNotFoundException &e){
2383                 return 1337;
2384         }
2385 }
2386
2387 // IGameDef interface
2388 // Under envlock
2389 IItemDefManager* Client::getItemDefManager()
2390 {
2391         return m_itemdef;
2392 }
2393 INodeDefManager* Client::getNodeDefManager()
2394 {
2395         return m_nodedef;
2396 }
2397 ICraftDefManager* Client::getCraftDefManager()
2398 {
2399         return NULL;
2400         //return m_craftdef;
2401 }
2402 ITextureSource* Client::getTextureSource()
2403 {
2404         return m_tsrc;
2405 }
2406 u16 Client::allocateUnknownNodeId(const std::string &name)
2407 {
2408         errorstream<<"Client::allocateUnknownNodeId(): "
2409                         <<"Client cannot allocate node IDs"<<std::endl;
2410         assert(0);
2411         return CONTENT_IGNORE;
2412 }
2413 ISoundManager* Client::getSoundManager()
2414 {
2415         return m_sound;
2416 }
2417 MtEventManager* Client::getEventManager()
2418 {
2419         return m_event;
2420 }
2421