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