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