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