Players stay in environment even when dead, damage flash and fall damage fixes
[oweals/minetest.git] / src / client.cpp
1 /*
2 Minetest-c55
3 Copyright (C) 2010 celeron55, Perttu Ahola <celeron55@gmail.com>
4
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 2 of the License, or
8 (at your option) any later version.
9
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License along
16 with this program; if not, write to the Free Software Foundation, Inc.,
17 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18 */
19
20 #include "client.h"
21 #include "utility.h"
22 #include <iostream>
23 #include "clientserver.h"
24 #include "jmutexautolock.h"
25 #include "main.h"
26 #include <sstream>
27 #include "porting.h"
28 #include "mapsector.h"
29 #include "mapblock_mesh.h"
30 #include "mapblock.h"
31 #include "settings.h"
32 #include "profiler.h"
33 #include "log.h"
34 #include "nodemetadata.h"
35 #include "nodedef.h"
36 #include "itemdef.h"
37 #include <IFileSystem.h>
38 #include "sha1.h"
39 #include "base64.h"
40
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 oldhp = player->hp;
1175                 u8 hp = readU8(is);
1176                 player->hp = hp;
1177
1178                 if(hp < oldhp)
1179                 {
1180                         // Add to ClientEvent queue
1181                         ClientEvent event;
1182                         event.type = CE_PLAYER_DAMAGE;
1183                         event.player_damage.amount = oldhp - hp;
1184                         m_client_event_queue.push_back(event);
1185                 }
1186         }
1187         else if(command == TOCLIENT_MOVE_PLAYER)
1188         {
1189                 std::string datastring((char*)&data[2], datasize-2);
1190                 std::istringstream is(datastring, std::ios_base::binary);
1191                 Player *player = m_env.getLocalPlayer();
1192                 assert(player != NULL);
1193                 v3f pos = readV3F1000(is);
1194                 f32 pitch = readF1000(is);
1195                 f32 yaw = readF1000(is);
1196                 player->setPosition(pos);
1197                 /*player->setPitch(pitch);
1198                 player->setYaw(yaw);*/
1199
1200                 infostream<<"Client got TOCLIENT_MOVE_PLAYER"
1201                                 <<" pos=("<<pos.X<<","<<pos.Y<<","<<pos.Z<<")"
1202                                 <<" pitch="<<pitch
1203                                 <<" yaw="<<yaw
1204                                 <<std::endl;
1205
1206                 /*
1207                         Add to ClientEvent queue.
1208                         This has to be sent to the main program because otherwise
1209                         it would just force the pitch and yaw values to whatever
1210                         the camera points to.
1211                 */
1212                 ClientEvent event;
1213                 event.type = CE_PLAYER_FORCE_MOVE;
1214                 event.player_force_move.pitch = pitch;
1215                 event.player_force_move.yaw = yaw;
1216                 m_client_event_queue.push_back(event);
1217
1218                 // Ignore damage for a few seconds, so that the player doesn't
1219                 // get damage from falling on ground
1220                 m_ignore_damage_timer = 3.0;
1221         }
1222         else if(command == TOCLIENT_PLAYERITEM)
1223         {
1224                 std::string datastring((char*)&data[2], datasize-2);
1225                 std::istringstream is(datastring, std::ios_base::binary);
1226
1227                 u16 count = readU16(is);
1228
1229                 for (u16 i = 0; i < count; ++i) {
1230                         u16 peer_id = readU16(is);
1231                         Player *player = m_env.getPlayer(peer_id);
1232
1233                         if (player == NULL)
1234                         {
1235                                 infostream<<"Client: ignoring player item "
1236                                         << deSerializeString(is)
1237                                         << " for non-existing peer id " << peer_id
1238                                         << std::endl;
1239                                 continue;
1240                         } else if (player->isLocal()) {
1241                                 infostream<<"Client: ignoring player item "
1242                                         << deSerializeString(is)
1243                                         << " for local player" << std::endl;
1244                                 continue;
1245                         } else {
1246                                 InventoryList *inv = player->inventory.getList("main");
1247                                 std::string itemstring(deSerializeString(is));
1248                                 ItemStack item;
1249                                 item.deSerialize(itemstring, m_itemdef);
1250                                 inv->changeItem(0, item);
1251                                 if(itemstring.empty())
1252                                 {
1253                                         infostream<<"Client: empty player item for peer "
1254                                                 <<peer_id<<std::endl;
1255                                 }
1256                                 else
1257                                 {
1258                                         infostream<<"Client: player item for peer "
1259                                                 <<peer_id<<": "<<itemstring<<std::endl;
1260                                 }
1261                         }
1262                 }
1263         }
1264         else if(command == TOCLIENT_DEATHSCREEN)
1265         {
1266                 std::string datastring((char*)&data[2], datasize-2);
1267                 std::istringstream is(datastring, std::ios_base::binary);
1268                 
1269                 bool set_camera_point_target = readU8(is);
1270                 v3f camera_point_target = readV3F1000(is);
1271                 
1272                 ClientEvent event;
1273                 event.type = CE_DEATHSCREEN;
1274                 event.deathscreen.set_camera_point_target = set_camera_point_target;
1275                 event.deathscreen.camera_point_target_x = camera_point_target.X;
1276                 event.deathscreen.camera_point_target_y = camera_point_target.Y;
1277                 event.deathscreen.camera_point_target_z = camera_point_target.Z;
1278                 m_client_event_queue.push_back(event);
1279         }
1280         else if(command == TOCLIENT_ANNOUNCE_TEXTURES)
1281         {
1282                 io::IFileSystem *irrfs = m_device->getFileSystem();
1283                 video::IVideoDriver *vdrv = m_device->getVideoDriver();
1284
1285                 std::string datastring((char*)&data[2], datasize-2);
1286                 std::istringstream is(datastring, std::ios_base::binary);
1287
1288                 // Mesh update thread must be stopped while
1289                 // updating content definitions
1290                 assert(!m_mesh_update_thread.IsRunning());
1291
1292                 int num_textures = readU16(is);
1293
1294                 core::list<TextureRequest> texture_requests;
1295
1296                 for(int i=0; i<num_textures; i++){
1297
1298                         bool texture_found = false;
1299
1300                         //read texture from cache
1301                         std::string name = deSerializeString(is);
1302                         std::string sha1_texture = deSerializeString(is);
1303                         
1304                         // if name contains illegal characters, ignore the texture
1305                         if(!string_allowed(name, TEXTURENAME_ALLOWED_CHARS)){
1306                                 errorstream<<"Client: ignoring illegal texture name "
1307                                                 <<"sent by server: \""<<name<<"\""<<std::endl;
1308                                 continue;
1309                         }
1310
1311                         std::string tpath = getTextureCacheDir() + DIR_DELIM + name;
1312                         // Read data
1313                         std::ifstream fis(tpath.c_str(), std::ios_base::binary);
1314
1315
1316                         if(fis.good() == false){
1317                                 infostream<<"Client::Texture not found in cache: "
1318                                                 <<name << " expected it at: "<<tpath<<std::endl;
1319                         }
1320                         else
1321                         {
1322                                 std::ostringstream tmp_os(std::ios_base::binary);
1323                                 bool bad = false;
1324                                 for(;;){
1325                                         char buf[1024];
1326                                         fis.read(buf, 1024);
1327                                         std::streamsize len = fis.gcount();
1328                                         tmp_os.write(buf, len);
1329                                         if(fis.eof())
1330                                                 break;
1331                                         if(!fis.good()){
1332                                                 bad = true;
1333                                                 break;
1334                                         }
1335                                 }
1336                                 if(bad){
1337                                         infostream<<"Client: Failed to read texture from cache\""
1338                                                         <<name<<"\""<<std::endl;
1339                                 }
1340                                 else {
1341
1342                                         SHA1 sha1;
1343                                         sha1.addBytes(tmp_os.str().c_str(), tmp_os.str().length());
1344
1345                                         unsigned char *digest = sha1.getDigest();
1346
1347                                         std::string digest_string = base64_encode(digest, 20);
1348
1349                                         if (digest_string == sha1_texture) {
1350                                                 // Silly irrlicht's const-incorrectness
1351                                                 Buffer<char> data_rw(tmp_os.str().c_str(), tmp_os.str().size());
1352
1353                                                 // Create an irrlicht memory file
1354                                                 io::IReadFile *rfile = irrfs->createMemoryReadFile(
1355                                                                 *data_rw,  tmp_os.str().size(), "_tempreadfile");
1356                                                 assert(rfile);
1357                                                 // Read image
1358                                                 video::IImage *img = vdrv->createImageFromFile(rfile);
1359                                                 if(!img){
1360                                                         infostream<<"Client: Cannot create image from data of "
1361                                                                         <<"received texture \""<<name<<"\""<<std::endl;
1362                                                         rfile->drop();
1363                                                 }
1364                                                 else {
1365                                                         m_tsrc->insertSourceImage(name, img);
1366                                                         img->drop();
1367                                                         rfile->drop();
1368
1369                                                         texture_found = true;
1370                                                 }
1371                                         }
1372                                         else {
1373                                                 infostream<<"Client::Texture cached sha1 hash not matching server hash: "
1374                                                                 <<name << ": server ->"<<sha1_texture <<" client -> "<<digest_string<<std::endl;
1375                                         }
1376
1377                                         free(digest);
1378                                 }
1379                         }
1380
1381                         //add texture request
1382                         if (!texture_found) {
1383                                 infostream<<"Client: Adding texture to request list: \""
1384                                                 <<name<<"\""<<std::endl;
1385                                 texture_requests.push_back(TextureRequest(name));
1386                         }
1387
1388                 }
1389
1390                 ClientEvent event;
1391                 event.type = CE_TEXTURES_UPDATED;
1392                 m_client_event_queue.push_back(event);
1393
1394
1395                 //send Texture request
1396                 /*
1397                                 u16 command
1398                                 u16 number of textures requested
1399                                 for each texture {
1400                                         u16 length of name
1401                                         string name
1402                                 }
1403                  */
1404                 std::ostringstream os(std::ios_base::binary);
1405                 u8 buf[12];
1406
1407
1408                 // Write command
1409                 writeU16(buf, TOSERVER_REQUEST_TEXTURES);
1410                 os.write((char*)buf, 2);
1411
1412                 writeU16(buf,texture_requests.size());
1413                 os.write((char*)buf, 2);
1414
1415
1416                 for(core::list<TextureRequest>::Iterator i = texture_requests.begin();
1417                                 i != texture_requests.end(); i++) {
1418                         os<<serializeString(i->name);
1419                 }
1420
1421                 // Make data buffer
1422                 std::string s = os.str();
1423                 SharedBuffer<u8> data((u8*)s.c_str(), s.size());
1424                 // Send as reliable
1425                 Send(0, data, true);
1426                 infostream<<"Client: Sending request list to server " <<std::endl;
1427         }
1428         else if(command == TOCLIENT_TEXTURES)
1429         {
1430                 io::IFileSystem *irrfs = m_device->getFileSystem();
1431                 video::IVideoDriver *vdrv = m_device->getVideoDriver();
1432
1433                 std::string datastring((char*)&data[2], datasize-2);
1434                 std::istringstream is(datastring, std::ios_base::binary);
1435
1436                 // Mesh update thread must be stopped while
1437                 // updating content definitions
1438                 assert(!m_mesh_update_thread.IsRunning());
1439
1440                 /*
1441                         u16 command
1442                         u16 total number of texture bunches
1443                         u16 index of this bunch
1444                         u32 number of textures in this bunch
1445                         for each texture {
1446                                 u16 length of name
1447                                 string name
1448                                 u32 length of data
1449                                 data
1450                         }
1451                 */
1452                 int num_bunches = readU16(is);
1453                 int bunch_i = readU16(is);
1454                 m_texture_receive_progress = (float)bunch_i / (float)(num_bunches - 1);
1455                 if(bunch_i == num_bunches - 1)
1456                         m_textures_received = true;
1457                 int num_textures = readU32(is);
1458                 infostream<<"Client: Received textures: bunch "<<bunch_i<<"/"
1459                                 <<num_bunches<<" textures="<<num_textures
1460                                 <<" size="<<datasize<<std::endl;
1461                 for(int i=0; i<num_textures; i++){
1462                         std::string name = deSerializeString(is);
1463                         std::string data = deSerializeLongString(is);
1464
1465                         // if name contains illegal characters, ignore the texture
1466                         if(!string_allowed(name, TEXTURENAME_ALLOWED_CHARS)){
1467                                 errorstream<<"Client: ignoring illegal texture name "
1468                                                 <<"sent by server: \""<<name<<"\""<<std::endl;
1469                                 continue;
1470                         }
1471
1472                         // Silly irrlicht's const-incorrectness
1473                         Buffer<char> data_rw(data.c_str(), data.size());
1474                         // Create an irrlicht memory file
1475                         io::IReadFile *rfile = irrfs->createMemoryReadFile(
1476                                         *data_rw, data.size(), "_tempreadfile");
1477                         assert(rfile);
1478                         // Read image
1479                         video::IImage *img = vdrv->createImageFromFile(rfile);
1480                         if(!img){
1481                                 errorstream<<"Client: Cannot create image from data of "
1482                                                 <<"received texture \""<<name<<"\""<<std::endl;
1483                                 rfile->drop();
1484                                 continue;
1485                         }
1486
1487                         fs::CreateAllDirs(getTextureCacheDir());
1488
1489                         std::string filename = getTextureCacheDir() + DIR_DELIM + name;
1490                         std::ofstream outfile(filename.c_str(), std::ios_base::binary | std::ios_base::trunc);
1491
1492                         if (outfile.good()) {
1493                                 outfile.write(data.c_str(),data.length());
1494                                 outfile.close();
1495                         }
1496                         else {
1497                                 errorstream<<"Client: Unable to open cached texture file "<< filename <<std::endl;
1498                         }
1499
1500                         m_tsrc->insertSourceImage(name, img);
1501                         img->drop();
1502                         rfile->drop();
1503                 }
1504
1505                 ClientEvent event;
1506                 event.type = CE_TEXTURES_UPDATED;
1507                 m_client_event_queue.push_back(event);
1508         }
1509         else if(command == TOCLIENT_TOOLDEF)
1510         {
1511                 infostream<<"Client: WARNING: Ignoring TOCLIENT_TOOLDEF"<<std::endl;
1512         }
1513         else if(command == TOCLIENT_NODEDEF)
1514         {
1515                 infostream<<"Client: Received node definitions: packet size: "
1516                                 <<datasize<<std::endl;
1517
1518                 // Mesh update thread must be stopped while
1519                 // updating content definitions
1520                 assert(!m_mesh_update_thread.IsRunning());
1521
1522                 // Decompress node definitions
1523                 std::string datastring((char*)&data[2], datasize-2);
1524                 std::istringstream is(datastring, std::ios_base::binary);
1525                 std::istringstream tmp_is(deSerializeLongString(is), std::ios::binary);
1526                 std::ostringstream tmp_os;
1527                 decompressZlib(tmp_is, tmp_os);
1528
1529                 // Deserialize node definitions
1530                 std::istringstream tmp_is2(tmp_os.str());
1531                 m_nodedef->deSerialize(tmp_is2);
1532                 m_nodedef_received = true;
1533         }
1534         else if(command == TOCLIENT_CRAFTITEMDEF)
1535         {
1536                 infostream<<"Client: WARNING: Ignoring TOCLIENT_CRAFTITEMDEF"<<std::endl;
1537         }
1538         else if(command == TOCLIENT_ITEMDEF)
1539         {
1540                 infostream<<"Client: Received item definitions: packet size: "
1541                                 <<datasize<<std::endl;
1542
1543                 // Mesh update thread must be stopped while
1544                 // updating content definitions
1545                 assert(!m_mesh_update_thread.IsRunning());
1546
1547                 // Decompress item definitions
1548                 std::string datastring((char*)&data[2], datasize-2);
1549                 std::istringstream is(datastring, std::ios_base::binary);
1550                 std::istringstream tmp_is(deSerializeLongString(is), std::ios::binary);
1551                 std::ostringstream tmp_os;
1552                 decompressZlib(tmp_is, tmp_os);
1553
1554                 // Deserialize node definitions
1555                 std::istringstream tmp_is2(tmp_os.str());
1556                 m_itemdef->deSerialize(tmp_is2);
1557                 m_itemdef_received = true;
1558         }
1559         else
1560         {
1561                 infostream<<"Client: Ignoring unknown command "
1562                                 <<command<<std::endl;
1563         }
1564 }
1565
1566 void Client::Send(u16 channelnum, SharedBuffer<u8> data, bool reliable)
1567 {
1568         //JMutexAutoLock lock(m_con_mutex); //bulk comment-out
1569         m_con.Send(PEER_ID_SERVER, channelnum, data, reliable);
1570 }
1571
1572 void Client::interact(u8 action, const PointedThing& pointed)
1573 {
1574         if(connectedAndInitialized() == false){
1575                 infostream<<"Client::interact() "
1576                                 "cancelled (not connected)"
1577                                 <<std::endl;
1578                 return;
1579         }
1580
1581         std::ostringstream os(std::ios_base::binary);
1582
1583         /*
1584                 [0] u16 command
1585                 [2] u8 action
1586                 [3] u16 item
1587                 [5] u32 length of the next item
1588                 [9] serialized PointedThing
1589                 actions:
1590                 0: start digging (from undersurface) or use
1591                 1: stop digging (all parameters ignored)
1592                 2: digging completed
1593                 3: place block or item (to abovesurface)
1594                 4: use item
1595         */
1596         writeU16(os, TOSERVER_INTERACT);
1597         writeU8(os, action);
1598         writeU16(os, getPlayerItem());
1599         std::ostringstream tmp_os(std::ios::binary);
1600         pointed.serialize(tmp_os);
1601         os<<serializeLongString(tmp_os.str());
1602
1603         std::string s = os.str();
1604         SharedBuffer<u8> data((u8*)s.c_str(), s.size());
1605
1606         // Send as reliable
1607         Send(0, data, true);
1608 }
1609
1610 void Client::sendSignNodeText(v3s16 p, std::string text)
1611 {
1612         /*
1613                 u16 command
1614                 v3s16 p
1615                 u16 textlen
1616                 textdata
1617         */
1618         std::ostringstream os(std::ios_base::binary);
1619         u8 buf[12];
1620         
1621         // Write command
1622         writeU16(buf, TOSERVER_SIGNNODETEXT);
1623         os.write((char*)buf, 2);
1624         
1625         // Write p
1626         writeV3S16(buf, p);
1627         os.write((char*)buf, 6);
1628
1629         u16 textlen = text.size();
1630         // Write text length
1631         writeS16(buf, textlen);
1632         os.write((char*)buf, 2);
1633
1634         // Write text
1635         os.write((char*)text.c_str(), textlen);
1636         
1637         // Make data buffer
1638         std::string s = os.str();
1639         SharedBuffer<u8> data((u8*)s.c_str(), s.size());
1640         // Send as reliable
1641         Send(0, data, true);
1642 }
1643         
1644 void Client::sendInventoryAction(InventoryAction *a)
1645 {
1646         std::ostringstream os(std::ios_base::binary);
1647         u8 buf[12];
1648         
1649         // Write command
1650         writeU16(buf, TOSERVER_INVENTORY_ACTION);
1651         os.write((char*)buf, 2);
1652
1653         a->serialize(os);
1654         
1655         // Make data buffer
1656         std::string s = os.str();
1657         SharedBuffer<u8> data((u8*)s.c_str(), s.size());
1658         // Send as reliable
1659         Send(0, data, true);
1660 }
1661
1662 void Client::sendChatMessage(const std::wstring &message)
1663 {
1664         std::ostringstream os(std::ios_base::binary);
1665         u8 buf[12];
1666         
1667         // Write command
1668         writeU16(buf, TOSERVER_CHAT_MESSAGE);
1669         os.write((char*)buf, 2);
1670         
1671         // Write length
1672         writeU16(buf, message.size());
1673         os.write((char*)buf, 2);
1674         
1675         // Write string
1676         for(u32 i=0; i<message.size(); i++)
1677         {
1678                 u16 w = message[i];
1679                 writeU16(buf, w);
1680                 os.write((char*)buf, 2);
1681         }
1682         
1683         // Make data buffer
1684         std::string s = os.str();
1685         SharedBuffer<u8> data((u8*)s.c_str(), s.size());
1686         // Send as reliable
1687         Send(0, data, true);
1688 }
1689
1690 void Client::sendChangePassword(const std::wstring oldpassword,
1691                 const std::wstring newpassword)
1692 {
1693         Player *player = m_env.getLocalPlayer();
1694         if(player == NULL)
1695                 return;
1696
1697         std::string playername = player->getName();
1698         std::string oldpwd = translatePassword(playername, oldpassword);
1699         std::string newpwd = translatePassword(playername, newpassword);
1700
1701         std::ostringstream os(std::ios_base::binary);
1702         u8 buf[2+PASSWORD_SIZE*2];
1703         /*
1704                 [0] u16 TOSERVER_PASSWORD
1705                 [2] u8[28] old password
1706                 [30] u8[28] new password
1707         */
1708
1709         writeU16(buf, TOSERVER_PASSWORD);
1710         for(u32 i=0;i<PASSWORD_SIZE-1;i++)
1711         {
1712                 buf[2+i] = i<oldpwd.length()?oldpwd[i]:0;
1713                 buf[30+i] = i<newpwd.length()?newpwd[i]:0;
1714         }
1715         buf[2+PASSWORD_SIZE-1] = 0;
1716         buf[30+PASSWORD_SIZE-1] = 0;
1717         os.write((char*)buf, 2+PASSWORD_SIZE*2);
1718
1719         // Make data buffer
1720         std::string s = os.str();
1721         SharedBuffer<u8> data((u8*)s.c_str(), s.size());
1722         // Send as reliable
1723         Send(0, data, true);
1724 }
1725
1726
1727 void Client::sendDamage(u8 damage)
1728 {
1729         DSTACK(__FUNCTION_NAME);
1730         std::ostringstream os(std::ios_base::binary);
1731
1732         writeU16(os, TOSERVER_DAMAGE);
1733         writeU8(os, damage);
1734
1735         // Make data buffer
1736         std::string s = os.str();
1737         SharedBuffer<u8> data((u8*)s.c_str(), s.size());
1738         // Send as reliable
1739         Send(0, data, true);
1740 }
1741
1742 void Client::sendRespawn()
1743 {
1744         DSTACK(__FUNCTION_NAME);
1745         std::ostringstream os(std::ios_base::binary);
1746
1747         writeU16(os, TOSERVER_RESPAWN);
1748
1749         // Make data buffer
1750         std::string s = os.str();
1751         SharedBuffer<u8> data((u8*)s.c_str(), s.size());
1752         // Send as reliable
1753         Send(0, data, true);
1754 }
1755
1756 void Client::sendPlayerPos()
1757 {
1758         //JMutexAutoLock envlock(m_env_mutex); //bulk comment-out
1759         
1760         Player *myplayer = m_env.getLocalPlayer();
1761         if(myplayer == NULL)
1762                 return;
1763         
1764         u16 our_peer_id;
1765         {
1766                 //JMutexAutoLock lock(m_con_mutex); //bulk comment-out
1767                 our_peer_id = m_con.GetPeerID();
1768         }
1769         
1770         // Set peer id if not set already
1771         if(myplayer->peer_id == PEER_ID_INEXISTENT)
1772                 myplayer->peer_id = our_peer_id;
1773         // Check that an existing peer_id is the same as the connection's
1774         assert(myplayer->peer_id == our_peer_id);
1775         
1776         v3f pf = myplayer->getPosition();
1777         v3s32 position(pf.X*100, pf.Y*100, pf.Z*100);
1778         v3f sf = myplayer->getSpeed();
1779         v3s32 speed(sf.X*100, sf.Y*100, sf.Z*100);
1780         s32 pitch = myplayer->getPitch() * 100;
1781         s32 yaw = myplayer->getYaw() * 100;
1782
1783         /*
1784                 Format:
1785                 [0] u16 command
1786                 [2] v3s32 position*100
1787                 [2+12] v3s32 speed*100
1788                 [2+12+12] s32 pitch*100
1789                 [2+12+12+4] s32 yaw*100
1790         */
1791
1792         SharedBuffer<u8> data(2+12+12+4+4);
1793         writeU16(&data[0], TOSERVER_PLAYERPOS);
1794         writeV3S32(&data[2], position);
1795         writeV3S32(&data[2+12], speed);
1796         writeS32(&data[2+12+12], pitch);
1797         writeS32(&data[2+12+12+4], yaw);
1798
1799         // Send as unreliable
1800         Send(0, data, false);
1801 }
1802
1803 void Client::sendPlayerItem(u16 item)
1804 {
1805         Player *myplayer = m_env.getLocalPlayer();
1806         if(myplayer == NULL)
1807                 return;
1808
1809         u16 our_peer_id = m_con.GetPeerID();
1810
1811         // Set peer id if not set already
1812         if(myplayer->peer_id == PEER_ID_INEXISTENT)
1813                 myplayer->peer_id = our_peer_id;
1814         // Check that an existing peer_id is the same as the connection's
1815         assert(myplayer->peer_id == our_peer_id);
1816
1817         SharedBuffer<u8> data(2+2);
1818         writeU16(&data[0], TOSERVER_PLAYERITEM);
1819         writeU16(&data[2], item);
1820
1821         // Send as reliable
1822         Send(0, data, true);
1823 }
1824
1825 void Client::removeNode(v3s16 p)
1826 {
1827         //JMutexAutoLock envlock(m_env_mutex); //bulk comment-out
1828         
1829         core::map<v3s16, MapBlock*> modified_blocks;
1830
1831         try
1832         {
1833                 //TimeTaker t("removeNodeAndUpdate", m_device);
1834                 m_env.getMap().removeNodeAndUpdate(p, modified_blocks);
1835         }
1836         catch(InvalidPositionException &e)
1837         {
1838         }
1839         
1840         for(core::map<v3s16, MapBlock * >::Iterator
1841                         i = modified_blocks.getIterator();
1842                         i.atEnd() == false; i++)
1843         {
1844                 v3s16 p = i.getNode()->getKey();
1845                 //m_env.getClientMap().updateMeshes(p, m_env.getDayNightRatio());
1846                 addUpdateMeshTaskWithEdge(p);
1847         }
1848 }
1849
1850 void Client::addNode(v3s16 p, MapNode n)
1851 {
1852         //JMutexAutoLock envlock(m_env_mutex); //bulk comment-out
1853
1854         TimeTaker timer1("Client::addNode()");
1855
1856         core::map<v3s16, MapBlock*> modified_blocks;
1857
1858         try
1859         {
1860                 //TimeTaker timer3("Client::addNode(): addNodeAndUpdate");
1861                 m_env.getMap().addNodeAndUpdate(p, n, modified_blocks);
1862         }
1863         catch(InvalidPositionException &e)
1864         {}
1865         
1866         //TimeTaker timer2("Client::addNode(): updateMeshes");
1867
1868         for(core::map<v3s16, MapBlock * >::Iterator
1869                         i = modified_blocks.getIterator();
1870                         i.atEnd() == false; i++)
1871         {
1872                 v3s16 p = i.getNode()->getKey();
1873                 //m_env.getClientMap().updateMeshes(p, m_env.getDayNightRatio());
1874                 addUpdateMeshTaskWithEdge(p);
1875         }
1876 }
1877         
1878 void Client::updateCamera(v3f pos, v3f dir, f32 fov)
1879 {
1880         m_env.getClientMap().updateCamera(pos, dir, fov);
1881 }
1882
1883 void Client::renderPostFx()
1884 {
1885         m_env.getClientMap().renderPostFx();
1886 }
1887
1888 MapNode Client::getNode(v3s16 p)
1889 {
1890         //JMutexAutoLock envlock(m_env_mutex); //bulk comment-out
1891         return m_env.getMap().getNode(p);
1892 }
1893
1894 NodeMetadata* Client::getNodeMetadata(v3s16 p)
1895 {
1896         return m_env.getMap().getNodeMetadata(p);
1897 }
1898
1899 LocalPlayer* Client::getLocalPlayer()
1900 {
1901         return m_env.getLocalPlayer();
1902 }
1903
1904 void Client::setPlayerControl(PlayerControl &control)
1905 {
1906         //JMutexAutoLock envlock(m_env_mutex); //bulk comment-out
1907         LocalPlayer *player = m_env.getLocalPlayer();
1908         assert(player != NULL);
1909         player->control = control;
1910 }
1911
1912 void Client::selectPlayerItem(u16 item)
1913 {
1914         //JMutexAutoLock envlock(m_env_mutex); //bulk comment-out
1915         m_playeritem = item;
1916         m_inventory_updated = true;
1917         sendPlayerItem(item);
1918 }
1919
1920 // Returns true if the inventory of the local player has been
1921 // updated from the server. If it is true, it is set to false.
1922 bool Client::getLocalInventoryUpdated()
1923 {
1924         // m_inventory_updated is behind envlock
1925         //JMutexAutoLock envlock(m_env_mutex); //bulk comment-out
1926         bool updated = m_inventory_updated;
1927         m_inventory_updated = false;
1928         return updated;
1929 }
1930
1931 // Copies the inventory of the local player to parameter
1932 void Client::getLocalInventory(Inventory &dst)
1933 {
1934         //JMutexAutoLock envlock(m_env_mutex); //bulk comment-out
1935         Player *player = m_env.getLocalPlayer();
1936         assert(player != NULL);
1937         dst = player->inventory;
1938 }
1939
1940 Inventory* Client::getInventory(const InventoryLocation &loc)
1941 {
1942         switch(loc.type){
1943         case InventoryLocation::UNDEFINED:
1944         {}
1945         break;
1946         case InventoryLocation::CURRENT_PLAYER:
1947         {
1948                 Player *player = m_env.getLocalPlayer();
1949                 assert(player != NULL);
1950                 return &player->inventory;
1951         }
1952         break;
1953         case InventoryLocation::PLAYER:
1954         {
1955                 Player *player = m_env.getPlayer(loc.name.c_str());
1956                 if(!player)
1957                         return NULL;
1958                 return &player->inventory;
1959         }
1960         break;
1961         case InventoryLocation::NODEMETA:
1962         {
1963                 NodeMetadata *meta = m_env.getMap().getNodeMetadata(loc.p);
1964                 if(!meta)
1965                         return NULL;
1966                 return meta->getInventory();
1967         }
1968         break;
1969         default:
1970                 assert(0);
1971         }
1972         return NULL;
1973 }
1974 void Client::inventoryAction(InventoryAction *a)
1975 {
1976         /*
1977                 Send it to the server
1978         */
1979         sendInventoryAction(a);
1980
1981         /*
1982                 Predict some local inventory changes
1983         */
1984         a->clientApply(this, this);
1985 }
1986
1987 ClientActiveObject * Client::getSelectedActiveObject(
1988                 f32 max_d,
1989                 v3f from_pos_f_on_map,
1990                 core::line3d<f32> shootline_on_map
1991         )
1992 {
1993         core::array<DistanceSortedActiveObject> objects;
1994
1995         m_env.getActiveObjects(from_pos_f_on_map, max_d, objects);
1996
1997         //infostream<<"Collected "<<objects.size()<<" nearby objects"<<std::endl;
1998         
1999         // Sort them.
2000         // After this, the closest object is the first in the array.
2001         objects.sort();
2002
2003         for(u32 i=0; i<objects.size(); i++)
2004         {
2005                 ClientActiveObject *obj = objects[i].obj;
2006                 
2007                 core::aabbox3d<f32> *selection_box = obj->getSelectionBox();
2008                 if(selection_box == NULL)
2009                         continue;
2010
2011                 v3f pos = obj->getPosition();
2012
2013                 core::aabbox3d<f32> offsetted_box(
2014                                 selection_box->MinEdge + pos,
2015                                 selection_box->MaxEdge + pos
2016                 );
2017
2018                 if(offsetted_box.intersectsWithLine(shootline_on_map))
2019                 {
2020                         //infostream<<"Returning selected object"<<std::endl;
2021                         return obj;
2022                 }
2023         }
2024
2025         //infostream<<"No object selected; returning NULL."<<std::endl;
2026         return NULL;
2027 }
2028
2029 void Client::printDebugInfo(std::ostream &os)
2030 {
2031         //JMutexAutoLock lock1(m_fetchblock_mutex);
2032         /*JMutexAutoLock lock2(m_incoming_queue_mutex);
2033
2034         os<<"m_incoming_queue.getSize()="<<m_incoming_queue.getSize()
2035                 //<<", m_fetchblock_history.size()="<<m_fetchblock_history.size()
2036                 //<<", m_opt_not_found_history.size()="<<m_opt_not_found_history.size()
2037                 <<std::endl;*/
2038 }
2039         
2040 u32 Client::getDayNightRatio()
2041 {
2042         //JMutexAutoLock envlock(m_env_mutex); //bulk comment-out
2043         return m_env.getDayNightRatio();
2044 }
2045
2046 u16 Client::getHP()
2047 {
2048         Player *player = m_env.getLocalPlayer();
2049         assert(player != NULL);
2050         return player->hp;
2051 }
2052
2053 void Client::setTempMod(v3s16 p, NodeMod mod)
2054 {
2055         //JMutexAutoLock envlock(m_env_mutex); //bulk comment-out
2056         assert(m_env.getMap().mapType() == MAPTYPE_CLIENT);
2057
2058         core::map<v3s16, MapBlock*> affected_blocks;
2059         ((ClientMap&)m_env.getMap()).setTempMod(p, mod,
2060                         &affected_blocks);
2061
2062         for(core::map<v3s16, MapBlock*>::Iterator
2063                         i = affected_blocks.getIterator();
2064                         i.atEnd() == false; i++)
2065         {
2066                 i.getNode()->getValue()->updateMesh(m_env.getDayNightRatio());
2067         }
2068 }
2069
2070 void Client::clearTempMod(v3s16 p)
2071 {
2072         //JMutexAutoLock envlock(m_env_mutex); //bulk comment-out
2073         assert(m_env.getMap().mapType() == MAPTYPE_CLIENT);
2074
2075         core::map<v3s16, MapBlock*> affected_blocks;
2076         ((ClientMap&)m_env.getMap()).clearTempMod(p,
2077                         &affected_blocks);
2078
2079         for(core::map<v3s16, MapBlock*>::Iterator
2080                         i = affected_blocks.getIterator();
2081                         i.atEnd() == false; i++)
2082         {
2083                 i.getNode()->getValue()->updateMesh(m_env.getDayNightRatio());
2084         }
2085 }
2086
2087 void Client::addUpdateMeshTask(v3s16 p, bool ack_to_server)
2088 {
2089         /*infostream<<"Client::addUpdateMeshTask(): "
2090                         <<"("<<p.X<<","<<p.Y<<","<<p.Z<<")"
2091                         <<std::endl;*/
2092
2093         MapBlock *b = m_env.getMap().getBlockNoCreateNoEx(p);
2094         if(b == NULL)
2095                 return;
2096         
2097         /*
2098                 Create a task to update the mesh of the block
2099         */
2100         
2101         MeshMakeData *data = new MeshMakeData;
2102         
2103         {
2104                 //TimeTaker timer("data fill");
2105                 // Release: ~0ms
2106                 // Debug: 1-6ms, avg=2ms
2107                 data->fill(getDayNightRatio(), b);
2108         }
2109
2110         // Debug wait
2111         //while(m_mesh_update_thread.m_queue_in.size() > 0) sleep_ms(10);
2112         
2113         // Add task to queue
2114         m_mesh_update_thread.m_queue_in.addBlock(p, data, ack_to_server);
2115
2116         /*infostream<<"Mesh update input queue size is "
2117                         <<m_mesh_update_thread.m_queue_in.size()
2118                         <<std::endl;*/
2119         
2120 #if 0
2121         // Temporary test: make mesh directly in here
2122         {
2123                 //TimeTaker timer("make mesh");
2124                 // 10ms
2125                 scene::SMesh *mesh_new = NULL;
2126                 mesh_new = makeMapBlockMesh(data);
2127                 b->replaceMesh(mesh_new);
2128                 delete data;
2129         }
2130 #endif
2131
2132         /*
2133                 Mark mesh as non-expired at this point so that it can already
2134                 be marked as expired again if the data changes
2135         */
2136         b->setMeshExpired(false);
2137 }
2138
2139 void Client::addUpdateMeshTaskWithEdge(v3s16 blockpos, bool ack_to_server)
2140 {
2141         /*{
2142                 v3s16 p = blockpos;
2143                 infostream<<"Client::addUpdateMeshTaskWithEdge(): "
2144                                 <<"("<<p.X<<","<<p.Y<<","<<p.Z<<")"
2145                                 <<std::endl;
2146         }*/
2147
2148         try{
2149                 v3s16 p = blockpos + v3s16(0,0,0);
2150                 //MapBlock *b = m_env.getMap().getBlockNoCreate(p);
2151                 addUpdateMeshTask(p, ack_to_server);
2152         }
2153         catch(InvalidPositionException &e){}
2154         // Leading edge
2155         try{
2156                 v3s16 p = blockpos + v3s16(-1,0,0);
2157                 addUpdateMeshTask(p);
2158         }
2159         catch(InvalidPositionException &e){}
2160         try{
2161                 v3s16 p = blockpos + v3s16(0,-1,0);
2162                 addUpdateMeshTask(p);
2163         }
2164         catch(InvalidPositionException &e){}
2165         try{
2166                 v3s16 p = blockpos + v3s16(0,0,-1);
2167                 addUpdateMeshTask(p);
2168         }
2169         catch(InvalidPositionException &e){}
2170 }
2171
2172 ClientEvent Client::getClientEvent()
2173 {
2174         if(m_client_event_queue.size() == 0)
2175         {
2176                 ClientEvent event;
2177                 event.type = CE_NONE;
2178                 return event;
2179         }
2180         return m_client_event_queue.pop_front();
2181 }
2182
2183 void Client::afterContentReceived()
2184 {
2185         assert(m_itemdef_received);
2186         assert(m_nodedef_received);
2187         assert(m_textures_received);
2188
2189         // Rebuild inherited images and recreate textures
2190         m_tsrc->rebuildImagesAndTextures();
2191
2192         // Update texture atlas
2193         if(g_settings->getBool("enable_texture_atlas"))
2194                 m_tsrc->buildMainAtlas(this);
2195
2196         // Update node aliases
2197         m_nodedef->updateAliases(m_itemdef);
2198
2199         // Update node textures
2200         m_nodedef->updateTextures(m_tsrc);
2201
2202         // Update item textures and meshes
2203         m_itemdef->updateTexturesAndMeshes(this);
2204
2205         // Start mesh update thread after setting up content definitions
2206         m_mesh_update_thread.Start();
2207 }
2208
2209 float Client::getRTT(void)
2210 {
2211         try{
2212                 return m_con.GetPeerAvgRTT(PEER_ID_SERVER);
2213         } catch(con::PeerNotFoundException &e){
2214                 return 1337;
2215         }
2216 }
2217
2218 // IGameDef interface
2219 // Under envlock
2220 IItemDefManager* Client::getItemDefManager()
2221 {
2222         return m_itemdef;
2223 }
2224 INodeDefManager* Client::getNodeDefManager()
2225 {
2226         return m_nodedef;
2227 }
2228 ICraftDefManager* Client::getCraftDefManager()
2229 {
2230         return NULL;
2231         //return m_craftdef;
2232 }
2233 ITextureSource* Client::getTextureSource()
2234 {
2235         return m_tsrc;
2236 }
2237 u16 Client::allocateUnknownNodeId(const std::string &name)
2238 {
2239         errorstream<<"Client::allocateUnknownNodeId(): "
2240                         <<"Client cannot allocate node IDs"<<std::endl;
2241         assert(0);
2242         return CONTENT_IGNORE;
2243 }
2244