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