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