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