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