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