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