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