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