]> git.lizzy.rs Git - dragonfireclient.git/blob - src/client.cpp
Add 'fly' and 'fast' privileges and the underlying privileges-to-client system
[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, false, gain);
1643                         break;
1644                 case 1: // positional
1645                         client_id = m_sound->playSoundAt(name, false, 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::sendSignNodeText(v3s16 p, std::string text)
1744 {
1745         /*
1746                 u16 command
1747                 v3s16 p
1748                 u16 textlen
1749                 textdata
1750         */
1751         std::ostringstream os(std::ios_base::binary);
1752         u8 buf[12];
1753         
1754         // Write command
1755         writeU16(buf, TOSERVER_SIGNNODETEXT);
1756         os.write((char*)buf, 2);
1757         
1758         // Write p
1759         writeV3S16(buf, p);
1760         os.write((char*)buf, 6);
1761
1762         u16 textlen = text.size();
1763         // Write text length
1764         writeS16(buf, textlen);
1765         os.write((char*)buf, 2);
1766
1767         // Write text
1768         os.write((char*)text.c_str(), textlen);
1769         
1770         // Make data buffer
1771         std::string s = os.str();
1772         SharedBuffer<u8> data((u8*)s.c_str(), s.size());
1773         // Send as reliable
1774         Send(0, data, true);
1775 }
1776         
1777 void Client::sendInventoryAction(InventoryAction *a)
1778 {
1779         std::ostringstream os(std::ios_base::binary);
1780         u8 buf[12];
1781         
1782         // Write command
1783         writeU16(buf, TOSERVER_INVENTORY_ACTION);
1784         os.write((char*)buf, 2);
1785
1786         a->serialize(os);
1787         
1788         // Make data buffer
1789         std::string s = os.str();
1790         SharedBuffer<u8> data((u8*)s.c_str(), s.size());
1791         // Send as reliable
1792         Send(0, data, true);
1793 }
1794
1795 void Client::sendChatMessage(const std::wstring &message)
1796 {
1797         std::ostringstream os(std::ios_base::binary);
1798         u8 buf[12];
1799         
1800         // Write command
1801         writeU16(buf, TOSERVER_CHAT_MESSAGE);
1802         os.write((char*)buf, 2);
1803         
1804         // Write length
1805         writeU16(buf, message.size());
1806         os.write((char*)buf, 2);
1807         
1808         // Write string
1809         for(u32 i=0; i<message.size(); i++)
1810         {
1811                 u16 w = message[i];
1812                 writeU16(buf, w);
1813                 os.write((char*)buf, 2);
1814         }
1815         
1816         // Make data buffer
1817         std::string s = os.str();
1818         SharedBuffer<u8> data((u8*)s.c_str(), s.size());
1819         // Send as reliable
1820         Send(0, data, true);
1821 }
1822
1823 void Client::sendChangePassword(const std::wstring oldpassword,
1824                 const std::wstring newpassword)
1825 {
1826         Player *player = m_env.getLocalPlayer();
1827         if(player == NULL)
1828                 return;
1829
1830         std::string playername = player->getName();
1831         std::string oldpwd = translatePassword(playername, oldpassword);
1832         std::string newpwd = translatePassword(playername, newpassword);
1833
1834         std::ostringstream os(std::ios_base::binary);
1835         u8 buf[2+PASSWORD_SIZE*2];
1836         /*
1837                 [0] u16 TOSERVER_PASSWORD
1838                 [2] u8[28] old password
1839                 [30] u8[28] new password
1840         */
1841
1842         writeU16(buf, TOSERVER_PASSWORD);
1843         for(u32 i=0;i<PASSWORD_SIZE-1;i++)
1844         {
1845                 buf[2+i] = i<oldpwd.length()?oldpwd[i]:0;
1846                 buf[30+i] = i<newpwd.length()?newpwd[i]:0;
1847         }
1848         buf[2+PASSWORD_SIZE-1] = 0;
1849         buf[30+PASSWORD_SIZE-1] = 0;
1850         os.write((char*)buf, 2+PASSWORD_SIZE*2);
1851
1852         // Make data buffer
1853         std::string s = os.str();
1854         SharedBuffer<u8> data((u8*)s.c_str(), s.size());
1855         // Send as reliable
1856         Send(0, data, true);
1857 }
1858
1859
1860 void Client::sendDamage(u8 damage)
1861 {
1862         DSTACK(__FUNCTION_NAME);
1863         std::ostringstream os(std::ios_base::binary);
1864
1865         writeU16(os, TOSERVER_DAMAGE);
1866         writeU8(os, damage);
1867
1868         // Make data buffer
1869         std::string s = os.str();
1870         SharedBuffer<u8> data((u8*)s.c_str(), s.size());
1871         // Send as reliable
1872         Send(0, data, true);
1873 }
1874
1875 void Client::sendRespawn()
1876 {
1877         DSTACK(__FUNCTION_NAME);
1878         std::ostringstream os(std::ios_base::binary);
1879
1880         writeU16(os, TOSERVER_RESPAWN);
1881
1882         // Make data buffer
1883         std::string s = os.str();
1884         SharedBuffer<u8> data((u8*)s.c_str(), s.size());
1885         // Send as reliable
1886         Send(0, data, true);
1887 }
1888
1889 void Client::sendPlayerPos()
1890 {
1891         //JMutexAutoLock envlock(m_env_mutex); //bulk comment-out
1892         
1893         Player *myplayer = m_env.getLocalPlayer();
1894         if(myplayer == NULL)
1895                 return;
1896         
1897         u16 our_peer_id;
1898         {
1899                 //JMutexAutoLock lock(m_con_mutex); //bulk comment-out
1900                 our_peer_id = m_con.GetPeerID();
1901         }
1902         
1903         // Set peer id if not set already
1904         if(myplayer->peer_id == PEER_ID_INEXISTENT)
1905                 myplayer->peer_id = our_peer_id;
1906         // Check that an existing peer_id is the same as the connection's
1907         assert(myplayer->peer_id == our_peer_id);
1908         
1909         v3f pf = myplayer->getPosition();
1910         v3s32 position(pf.X*100, pf.Y*100, pf.Z*100);
1911         v3f sf = myplayer->getSpeed();
1912         v3s32 speed(sf.X*100, sf.Y*100, sf.Z*100);
1913         s32 pitch = myplayer->getPitch() * 100;
1914         s32 yaw = myplayer->getYaw() * 100;
1915
1916         /*
1917                 Format:
1918                 [0] u16 command
1919                 [2] v3s32 position*100
1920                 [2+12] v3s32 speed*100
1921                 [2+12+12] s32 pitch*100
1922                 [2+12+12+4] s32 yaw*100
1923         */
1924
1925         SharedBuffer<u8> data(2+12+12+4+4);
1926         writeU16(&data[0], TOSERVER_PLAYERPOS);
1927         writeV3S32(&data[2], position);
1928         writeV3S32(&data[2+12], speed);
1929         writeS32(&data[2+12+12], pitch);
1930         writeS32(&data[2+12+12+4], yaw);
1931
1932         // Send as unreliable
1933         Send(0, data, false);
1934 }
1935
1936 void Client::sendPlayerItem(u16 item)
1937 {
1938         Player *myplayer = m_env.getLocalPlayer();
1939         if(myplayer == NULL)
1940                 return;
1941
1942         u16 our_peer_id = m_con.GetPeerID();
1943
1944         // Set peer id if not set already
1945         if(myplayer->peer_id == PEER_ID_INEXISTENT)
1946                 myplayer->peer_id = our_peer_id;
1947         // Check that an existing peer_id is the same as the connection's
1948         assert(myplayer->peer_id == our_peer_id);
1949
1950         SharedBuffer<u8> data(2+2);
1951         writeU16(&data[0], TOSERVER_PLAYERITEM);
1952         writeU16(&data[2], item);
1953
1954         // Send as reliable
1955         Send(0, data, true);
1956 }
1957
1958 void Client::removeNode(v3s16 p)
1959 {
1960         core::map<v3s16, MapBlock*> modified_blocks;
1961
1962         try
1963         {
1964                 //TimeTaker t("removeNodeAndUpdate", m_device);
1965                 m_env.getMap().removeNodeAndUpdate(p, modified_blocks);
1966         }
1967         catch(InvalidPositionException &e)
1968         {
1969         }
1970         
1971         // add urgent task to update the modified node
1972         addUpdateMeshTaskForNode(p, false, true);
1973
1974         for(core::map<v3s16, MapBlock * >::Iterator
1975                         i = modified_blocks.getIterator();
1976                         i.atEnd() == false; i++)
1977         {
1978                 v3s16 p = i.getNode()->getKey();
1979                 addUpdateMeshTaskWithEdge(p);
1980         }
1981 }
1982
1983 void Client::addNode(v3s16 p, MapNode n)
1984 {
1985         TimeTaker timer1("Client::addNode()");
1986
1987         core::map<v3s16, MapBlock*> modified_blocks;
1988
1989         try
1990         {
1991                 //TimeTaker timer3("Client::addNode(): addNodeAndUpdate");
1992                 m_env.getMap().addNodeAndUpdate(p, n, modified_blocks);
1993         }
1994         catch(InvalidPositionException &e)
1995         {}
1996         
1997         for(core::map<v3s16, MapBlock * >::Iterator
1998                         i = modified_blocks.getIterator();
1999                         i.atEnd() == false; i++)
2000         {
2001                 v3s16 p = i.getNode()->getKey();
2002                 addUpdateMeshTaskWithEdge(p);
2003         }
2004 }
2005         
2006 void Client::setPlayerControl(PlayerControl &control)
2007 {
2008         //JMutexAutoLock envlock(m_env_mutex); //bulk comment-out
2009         LocalPlayer *player = m_env.getLocalPlayer();
2010         assert(player != NULL);
2011         player->control = control;
2012 }
2013
2014 void Client::selectPlayerItem(u16 item)
2015 {
2016         //JMutexAutoLock envlock(m_env_mutex); //bulk comment-out
2017         m_playeritem = item;
2018         m_inventory_updated = true;
2019         sendPlayerItem(item);
2020 }
2021
2022 // Returns true if the inventory of the local player has been
2023 // updated from the server. If it is true, it is set to false.
2024 bool Client::getLocalInventoryUpdated()
2025 {
2026         // m_inventory_updated is behind envlock
2027         //JMutexAutoLock envlock(m_env_mutex); //bulk comment-out
2028         bool updated = m_inventory_updated;
2029         m_inventory_updated = false;
2030         return updated;
2031 }
2032
2033 // Copies the inventory of the local player to parameter
2034 void Client::getLocalInventory(Inventory &dst)
2035 {
2036         //JMutexAutoLock envlock(m_env_mutex); //bulk comment-out
2037         Player *player = m_env.getLocalPlayer();
2038         assert(player != NULL);
2039         dst = player->inventory;
2040 }
2041
2042 Inventory* Client::getInventory(const InventoryLocation &loc)
2043 {
2044         switch(loc.type){
2045         case InventoryLocation::UNDEFINED:
2046         {}
2047         break;
2048         case InventoryLocation::CURRENT_PLAYER:
2049         {
2050                 Player *player = m_env.getLocalPlayer();
2051                 assert(player != NULL);
2052                 return &player->inventory;
2053         }
2054         break;
2055         case InventoryLocation::PLAYER:
2056         {
2057                 Player *player = m_env.getPlayer(loc.name.c_str());
2058                 if(!player)
2059                         return NULL;
2060                 return &player->inventory;
2061         }
2062         break;
2063         case InventoryLocation::NODEMETA:
2064         {
2065                 NodeMetadata *meta = m_env.getMap().getNodeMetadata(loc.p);
2066                 if(!meta)
2067                         return NULL;
2068                 return meta->getInventory();
2069         }
2070         break;
2071         default:
2072                 assert(0);
2073         }
2074         return NULL;
2075 }
2076 void Client::inventoryAction(InventoryAction *a)
2077 {
2078         /*
2079                 Send it to the server
2080         */
2081         sendInventoryAction(a);
2082
2083         /*
2084                 Predict some local inventory changes
2085         */
2086         a->clientApply(this, this);
2087 }
2088
2089 ClientActiveObject * Client::getSelectedActiveObject(
2090                 f32 max_d,
2091                 v3f from_pos_f_on_map,
2092                 core::line3d<f32> shootline_on_map
2093         )
2094 {
2095         core::array<DistanceSortedActiveObject> objects;
2096
2097         m_env.getActiveObjects(from_pos_f_on_map, max_d, objects);
2098
2099         //infostream<<"Collected "<<objects.size()<<" nearby objects"<<std::endl;
2100         
2101         // Sort them.
2102         // After this, the closest object is the first in the array.
2103         objects.sort();
2104
2105         for(u32 i=0; i<objects.size(); i++)
2106         {
2107                 ClientActiveObject *obj = objects[i].obj;
2108                 
2109                 core::aabbox3d<f32> *selection_box = obj->getSelectionBox();
2110                 if(selection_box == NULL)
2111                         continue;
2112
2113                 v3f pos = obj->getPosition();
2114
2115                 core::aabbox3d<f32> offsetted_box(
2116                                 selection_box->MinEdge + pos,
2117                                 selection_box->MaxEdge + pos
2118                 );
2119
2120                 if(offsetted_box.intersectsWithLine(shootline_on_map))
2121                 {
2122                         //infostream<<"Returning selected object"<<std::endl;
2123                         return obj;
2124                 }
2125         }
2126
2127         //infostream<<"No object selected; returning NULL."<<std::endl;
2128         return NULL;
2129 }
2130
2131 void Client::printDebugInfo(std::ostream &os)
2132 {
2133         //JMutexAutoLock lock1(m_fetchblock_mutex);
2134         /*JMutexAutoLock lock2(m_incoming_queue_mutex);
2135
2136         os<<"m_incoming_queue.getSize()="<<m_incoming_queue.getSize()
2137                 //<<", m_fetchblock_history.size()="<<m_fetchblock_history.size()
2138                 //<<", m_opt_not_found_history.size()="<<m_opt_not_found_history.size()
2139                 <<std::endl;*/
2140 }
2141
2142 core::list<std::wstring> Client::getConnectedPlayerNames()
2143 {
2144         core::list<Player*> players = m_env.getPlayers(true);
2145         core::list<std::wstring> playerNames;
2146         for(core::list<Player*>::Iterator
2147                         i = players.begin();
2148                         i != players.end(); i++)
2149         {
2150                 Player *player = *i;
2151                 playerNames.push_back(narrow_to_wide(player->getName()));
2152         }
2153         return playerNames;
2154 }
2155
2156 float Client::getAnimationTime()
2157 {
2158         return m_animation_time;
2159 }
2160
2161 int Client::getCrackLevel()
2162 {
2163         return m_crack_level;
2164 }
2165
2166 void Client::setCrack(int level, v3s16 pos)
2167 {
2168         int old_crack_level = m_crack_level;
2169         v3s16 old_crack_pos = m_crack_pos;
2170
2171         m_crack_level = level;
2172         m_crack_pos = pos;
2173
2174         if(old_crack_level >= 0 && (level < 0 || pos != old_crack_pos))
2175         {
2176                 // remove old crack
2177                 addUpdateMeshTaskForNode(old_crack_pos, false, true);
2178         }
2179         if(level >= 0 && (old_crack_level < 0 || pos != old_crack_pos))
2180         {
2181                 // add new crack
2182                 addUpdateMeshTaskForNode(pos, false, true);
2183         }
2184 }
2185
2186 u16 Client::getHP()
2187 {
2188         Player *player = m_env.getLocalPlayer();
2189         assert(player != NULL);
2190         return player->hp;
2191 }
2192
2193 bool Client::getChatMessage(std::wstring &message)
2194 {
2195         if(m_chat_queue.size() == 0)
2196                 return false;
2197         message = m_chat_queue.pop_front();
2198         return true;
2199 }
2200
2201 void Client::typeChatMessage(const std::wstring &message)
2202 {
2203         // Discard empty line
2204         if(message == L"")
2205                 return;
2206
2207         // Send to others
2208         sendChatMessage(message);
2209
2210         // Show locally
2211         if (message[0] == L'/')
2212         {
2213                 m_chat_queue.push_back(
2214                                 (std::wstring)L"issued command: "+message);
2215         }
2216         else
2217         {
2218                 LocalPlayer *player = m_env.getLocalPlayer();
2219                 assert(player != NULL);
2220                 std::wstring name = narrow_to_wide(player->getName());
2221                 m_chat_queue.push_back(
2222                                 (std::wstring)L"<"+name+L"> "+message);
2223         }
2224 }
2225
2226 void Client::addUpdateMeshTask(v3s16 p, bool ack_to_server, bool urgent)
2227 {
2228         /*infostream<<"Client::addUpdateMeshTask(): "
2229                         <<"("<<p.X<<","<<p.Y<<","<<p.Z<<")"
2230                         <<" ack_to_server="<<ack_to_server
2231                         <<" urgent="<<urgent
2232                         <<std::endl;*/
2233
2234         MapBlock *b = m_env.getMap().getBlockNoCreateNoEx(p);
2235         if(b == NULL)
2236                 return;
2237         
2238         /*
2239                 Create a task to update the mesh of the block
2240         */
2241         
2242         MeshMakeData *data = new MeshMakeData(this);
2243         
2244         {
2245                 //TimeTaker timer("data fill");
2246                 // Release: ~0ms
2247                 // Debug: 1-6ms, avg=2ms
2248                 data->fill(b);
2249                 data->setCrack(m_crack_level, m_crack_pos);
2250                 data->setSmoothLighting(g_settings->getBool("smooth_lighting"));
2251         }
2252
2253         // Debug wait
2254         //while(m_mesh_update_thread.m_queue_in.size() > 0) sleep_ms(10);
2255         
2256         // Add task to queue
2257         m_mesh_update_thread.m_queue_in.addBlock(p, data, ack_to_server, urgent);
2258
2259         /*infostream<<"Mesh update input queue size is "
2260                         <<m_mesh_update_thread.m_queue_in.size()
2261                         <<std::endl;*/
2262 }
2263
2264 void Client::addUpdateMeshTaskWithEdge(v3s16 blockpos, bool ack_to_server, bool urgent)
2265 {
2266         /*{
2267                 v3s16 p = blockpos;
2268                 infostream<<"Client::addUpdateMeshTaskWithEdge(): "
2269                                 <<"("<<p.X<<","<<p.Y<<","<<p.Z<<")"
2270                                 <<std::endl;
2271         }*/
2272
2273         try{
2274                 v3s16 p = blockpos + v3s16(0,0,0);
2275                 //MapBlock *b = m_env.getMap().getBlockNoCreate(p);
2276                 addUpdateMeshTask(p, ack_to_server, urgent);
2277         }
2278         catch(InvalidPositionException &e){}
2279         // Leading edge
2280         try{
2281                 v3s16 p = blockpos + v3s16(-1,0,0);
2282                 addUpdateMeshTask(p, false, urgent);
2283         }
2284         catch(InvalidPositionException &e){}
2285         try{
2286                 v3s16 p = blockpos + v3s16(0,-1,0);
2287                 addUpdateMeshTask(p, false, urgent);
2288         }
2289         catch(InvalidPositionException &e){}
2290         try{
2291                 v3s16 p = blockpos + v3s16(0,0,-1);
2292                 addUpdateMeshTask(p, false, urgent);
2293         }
2294         catch(InvalidPositionException &e){}
2295 }
2296
2297 void Client::addUpdateMeshTaskForNode(v3s16 nodepos, bool ack_to_server, bool urgent)
2298 {
2299         {
2300                 v3s16 p = nodepos;
2301                 infostream<<"Client::addUpdateMeshTaskForNode(): "
2302                                 <<"("<<p.X<<","<<p.Y<<","<<p.Z<<")"
2303                                 <<std::endl;
2304         }
2305
2306         v3s16 blockpos = getNodeBlockPos(nodepos);
2307         v3s16 blockpos_relative = blockpos * MAP_BLOCKSIZE;
2308
2309         try{
2310                 v3s16 p = blockpos + v3s16(0,0,0);
2311                 addUpdateMeshTask(p, ack_to_server, urgent);
2312         }
2313         catch(InvalidPositionException &e){}
2314         // Leading edge
2315         if(nodepos.X == blockpos_relative.X){
2316                 try{
2317                         v3s16 p = blockpos + v3s16(-1,0,0);
2318                         addUpdateMeshTask(p, false, urgent);
2319                 }
2320                 catch(InvalidPositionException &e){}
2321         }
2322         if(nodepos.Y == blockpos_relative.Y){
2323                 try{
2324                         v3s16 p = blockpos + v3s16(0,-1,0);
2325                         addUpdateMeshTask(p, false, urgent);
2326                 }
2327                 catch(InvalidPositionException &e){}
2328         }
2329         if(nodepos.Z == blockpos_relative.Z){
2330                 try{
2331                         v3s16 p = blockpos + v3s16(0,0,-1);
2332                         addUpdateMeshTask(p, false, urgent);
2333                 }
2334                 catch(InvalidPositionException &e){}
2335         }
2336 }
2337
2338 ClientEvent Client::getClientEvent()
2339 {
2340         if(m_client_event_queue.size() == 0)
2341         {
2342                 ClientEvent event;
2343                 event.type = CE_NONE;
2344                 return event;
2345         }
2346         return m_client_event_queue.pop_front();
2347 }
2348
2349 void Client::afterContentReceived()
2350 {
2351         assert(m_itemdef_received);
2352         assert(m_nodedef_received);
2353         assert(m_media_received);
2354
2355         // remove the information about which checksum each texture
2356         // ought to have
2357         m_media_name_sha1_map.clear();
2358
2359         // Rebuild inherited images and recreate textures
2360         m_tsrc->rebuildImagesAndTextures();
2361
2362         // Update texture atlas
2363         if(g_settings->getBool("enable_texture_atlas"))
2364                 m_tsrc->buildMainAtlas(this);
2365
2366         // Update node aliases
2367         m_nodedef->updateAliases(m_itemdef);
2368
2369         // Update node textures
2370         m_nodedef->updateTextures(m_tsrc);
2371
2372         // Update item textures and meshes
2373         m_itemdef->updateTexturesAndMeshes(this);
2374
2375         // Start mesh update thread after setting up content definitions
2376         m_mesh_update_thread.Start();
2377 }
2378
2379 float Client::getRTT(void)
2380 {
2381         try{
2382                 return m_con.GetPeerAvgRTT(PEER_ID_SERVER);
2383         } catch(con::PeerNotFoundException &e){
2384                 return 1337;
2385         }
2386 }
2387
2388 // IGameDef interface
2389 // Under envlock
2390 IItemDefManager* Client::getItemDefManager()
2391 {
2392         return m_itemdef;
2393 }
2394 INodeDefManager* Client::getNodeDefManager()
2395 {
2396         return m_nodedef;
2397 }
2398 ICraftDefManager* Client::getCraftDefManager()
2399 {
2400         return NULL;
2401         //return m_craftdef;
2402 }
2403 ITextureSource* Client::getTextureSource()
2404 {
2405         return m_tsrc;
2406 }
2407 u16 Client::allocateUnknownNodeId(const std::string &name)
2408 {
2409         errorstream<<"Client::allocateUnknownNodeId(): "
2410                         <<"Client cannot allocate node IDs"<<std::endl;
2411         assert(0);
2412         return CONTENT_IGNORE;
2413 }
2414 ISoundManager* Client::getSoundManager()
2415 {
2416         return m_sound;
2417 }
2418 MtEventManager* Client::getEventManager()
2419 {
2420         return m_event;
2421 }
2422