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