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