]> git.lizzy.rs Git - minetest.git/blob - src/client.cpp
plant amount fix and ravine amount setting
[minetest.git] / src / client.cpp
1 #include "client.h"
2 #include "utility.h"
3 #include <iostream>
4 #include "clientserver.h"
5 #include "jmutexautolock.h"
6 #include "main.h"
7 #include <sstream>
8
9 #ifdef _WIN32
10         #include <windows.h>
11         #define sleep_ms(x) Sleep(x)
12 #else
13         #include <unistd.h>
14         #define sleep_ms(x) usleep(x*1000)
15 #endif
16
17 void * ClientUpdateThread::Thread()
18 {
19         ThreadStarted();
20
21         DSTACK(__FUNCTION_NAME);
22
23 #if CATCH_UNHANDLED_EXCEPTIONS
24         try
25         {
26 #endif
27                 while(getRun())
28                 {
29                         m_client->asyncStep();
30
31                         bool was = m_client->AsyncProcessData();
32
33                         if(was == false)
34                                 sleep_ms(10);
35                 }
36 #if CATCH_UNHANDLED_EXCEPTIONS
37         }
38         /*
39                 This is what has to be done in threads to get suitable debug info
40         */
41         catch(std::exception &e)
42         {
43                 dstream<<std::endl<<DTIME<<"An unhandled exception occurred: "
44                                 <<e.what()<<std::endl;
45                 assert(0);
46         }
47 #endif
48
49         return NULL;
50 }
51
52 Client::Client(IrrlichtDevice *device, video::SMaterial *materials,
53                 float delete_unused_sectors_timeout,
54                 const char *playername):
55         m_thread(this),
56         m_env(new ClientMap(this, materials,
57                         device->getSceneManager()->getRootSceneNode(),
58                         device->getSceneManager(), 666),
59                         dout_client),
60         m_con(PROTOCOL_ID, 512, CONNECTION_TIMEOUT, this),
61         m_device(device),
62         camera_position(0,0,0),
63         camera_direction(0,0,1),
64         m_server_ser_ver(SER_FMT_VER_INVALID),
65         m_step_dtime(0.0),
66         m_delete_unused_sectors_timeout(delete_unused_sectors_timeout),
67         m_inventory_updated(false)
68 {
69         //m_fetchblock_mutex.Init();
70         m_incoming_queue_mutex.Init();
71         m_env_mutex.Init();
72         m_con_mutex.Init();
73         m_step_dtime_mutex.Init();
74
75         m_thread.Start();
76         
77         {
78                 JMutexAutoLock envlock(m_env_mutex);
79                 //m_env.getMap().StartUpdater();
80
81                 Player *player = new LocalPlayer();
82
83                 player->updateName(playername);
84
85                 /*f32 y = BS*2 + BS*20;
86                 player->setPosition(v3f(0, y, 0));*/
87                 //player->setPosition(v3f(0, y, 30900*BS)); // DEBUG
88                 m_env.addPlayer(player);
89         }
90 }
91
92 Client::~Client()
93 {
94         m_thread.setRun(false);
95         while(m_thread.IsRunning())
96                 sleep_ms(100);
97 }
98
99 void Client::connect(Address address)
100 {
101         DSTACK(__FUNCTION_NAME);
102         JMutexAutoLock lock(m_con_mutex);
103         m_con.setTimeoutMs(0);
104         m_con.Connect(address);
105 }
106
107 bool Client::connectedAndInitialized()
108 {
109         JMutexAutoLock lock(m_con_mutex);
110
111         if(m_con.Connected() == false)
112                 return false;
113         
114         if(m_server_ser_ver == SER_FMT_VER_INVALID)
115                 return false;
116         
117         return true;
118 }
119
120 void Client::step(float dtime)
121 {
122         DSTACK(__FUNCTION_NAME);
123         
124         // Limit a bit
125         if(dtime > 2.0)
126                 dtime = 2.0;
127         
128         //dstream<<"Client steps "<<dtime<<std::endl;
129
130         {
131                 //TimeTaker timer("ReceiveAll()", m_device);
132                 // 0ms
133                 ReceiveAll();
134         }
135         
136         {
137                 //TimeTaker timer("m_con_mutex + m_con.RunTimeouts()", m_device);
138                 // 0ms
139                 JMutexAutoLock lock(m_con_mutex);
140                 m_con.RunTimeouts(dtime);
141         }
142
143         /*
144                 Packet counter
145         */
146         {
147                 static float counter = -0.001;
148                 counter -= dtime;
149                 if(counter <= 0.0)
150                 {
151                         counter = 20.0;
152                         
153                         dout_client<<"Client packetcounter (20s):"<<std::endl;
154                         m_packetcounter.print(dout_client);
155                         m_packetcounter.clear();
156                 }
157         }
158
159         {
160                 /*
161                         Delete unused sectors
162
163                         NOTE: This jams the game for a while because deleting sectors
164                               clear caches
165                 */
166                 
167                 static float counter = -0.001;
168                 counter -= dtime;
169                 if(counter <= 0.0)
170                 {
171                         // 3 minute interval
172                         counter = 180.0;
173
174                         JMutexAutoLock lock(m_env_mutex);
175
176                         core::list<v3s16> deleted_blocks;
177         
178                         // Delete sector blocks
179                         /*u32 num = m_env.getMap().deleteUnusedSectors
180                                         (m_delete_unused_sectors_timeout,
181                                         true, &deleted_blocks);*/
182                         
183                         // Delete whole sectors
184                         u32 num = m_env.getMap().deleteUnusedSectors
185                                         (m_delete_unused_sectors_timeout,
186                                         false, &deleted_blocks);
187
188                         if(num > 0)
189                         {
190                                 /*dstream<<DTIME<<"Client: Deleted blocks of "<<num
191                                                 <<" unused sectors"<<std::endl;*/
192                                 dstream<<DTIME<<"Client: Deleted "<<num
193                                                 <<" unused sectors"<<std::endl;
194                                 
195                                 /*
196                                         Send info to server
197                                 */
198
199                                 // Env is locked so con can be locked.
200                                 JMutexAutoLock lock(m_con_mutex);
201                                 
202                                 core::list<v3s16>::Iterator i = deleted_blocks.begin();
203                                 core::list<v3s16> sendlist;
204                                 for(;;)
205                                 {
206                                         if(sendlist.size() == 255 || i == deleted_blocks.end())
207                                         {
208                                                 if(sendlist.size() == 0)
209                                                         break;
210                                                 /*
211                                                         [0] u16 command
212                                                         [2] u8 count
213                                                         [3] v3s16 pos_0
214                                                         [3+6] v3s16 pos_1
215                                                         ...
216                                                 */
217                                                 u32 replysize = 2+1+6*sendlist.size();
218                                                 SharedBuffer<u8> reply(replysize);
219                                                 writeU16(&reply[0], TOSERVER_DELETEDBLOCKS);
220                                                 reply[2] = sendlist.size();
221                                                 u32 k = 0;
222                                                 for(core::list<v3s16>::Iterator
223                                                                 j = sendlist.begin();
224                                                                 j != sendlist.end(); j++)
225                                                 {
226                                                         writeV3S16(&reply[2+1+6*k], *j);
227                                                         k++;
228                                                 }
229                                                 m_con.Send(PEER_ID_SERVER, 1, reply, true);
230
231                                                 if(i == deleted_blocks.end())
232                                                         break;
233
234                                                 sendlist.clear();
235                                         }
236
237                                         sendlist.push_back(*i);
238                                         i++;
239                                 }
240                         }
241                 }
242         }
243
244         bool connected = connectedAndInitialized();
245
246         if(connected == false)
247         {
248                 static float counter = -0.001;
249                 counter -= dtime;
250                 if(counter <= 0.0)
251                 {
252                         counter = 2.0;
253
254                         JMutexAutoLock envlock(m_env_mutex);
255                         
256                         Player *myplayer = m_env.getLocalPlayer();
257                         assert(myplayer != NULL);
258         
259                         // Send TOSERVER_INIT
260                         // [0] u16 TOSERVER_INIT
261                         // [2] u8 SER_FMT_VER_HIGHEST
262                         // [3] u8[20] player_name
263                         SharedBuffer<u8> data(2+1+20);
264                         writeU16(&data[0], TOSERVER_INIT);
265                         writeU8(&data[2], SER_FMT_VER_HIGHEST);
266                         memcpy(&data[3], myplayer->getName(), 20);
267                         // Send as unreliable
268                         Send(0, data, false);
269                 }
270
271                 // Not connected, return
272                 return;
273         }
274
275         /*
276                 Do stuff if connected
277         */
278         
279         {
280                 // 0ms
281                 JMutexAutoLock lock(m_env_mutex);
282
283                 // Control local player (0ms)
284                 LocalPlayer *player = m_env.getLocalPlayer();
285                 assert(player != NULL);
286                 player->applyControl(dtime);
287
288                 //TimeTaker envtimer("env step", m_device);
289                 // Step environment
290                 m_env.step(dtime);
291
292                 // Step active blocks
293                 for(core::map<v3s16, bool>::Iterator
294                                 i = m_active_blocks.getIterator();
295                                 i.atEnd() == false; i++)
296                 {
297                         v3s16 p = i.getNode()->getKey();
298
299                         MapBlock *block = NULL;
300                         try
301                         {
302                                 block = m_env.getMap().getBlockNoCreate(p);
303                                 block->stepObjects(dtime, false);
304                         }
305                         catch(InvalidPositionException &e)
306                         {
307                         }
308                 }
309         }
310
311         {
312                 // Fetch some nearby blocks
313                 //fetchBlocks();
314         }
315
316         {
317                 static float counter = 0.0;
318                 counter += dtime;
319                 if(counter >= 10)
320                 {
321                         counter = 0.0;
322                         JMutexAutoLock lock(m_con_mutex);
323                         // connectedAndInitialized() is true, peer exists.
324                         con::Peer *peer = m_con.GetPeer(PEER_ID_SERVER);
325                         dstream<<DTIME<<"Client: avg_rtt="<<peer->avg_rtt<<std::endl;
326                 }
327         }
328         {
329                 // Update at reasonable intervals (0.2s)
330                 static float counter = 0.0;
331                 counter += dtime;
332                 if(counter >= 0.2)
333                 {
334                         counter = 0.0;
335                         sendPlayerPos();
336                 }
337         }
338
339 #if 0
340         /*
341                 Clear old entries from fetchblock history
342         */
343         {
344                 JMutexAutoLock lock(m_fetchblock_mutex);
345                 
346                 core::list<v3s16> remove_queue;
347                 core::map<v3s16, float>::Iterator i;
348                 i = m_fetchblock_history.getIterator();
349                 for(; i.atEnd() == false; i++)
350                 {
351                         float value = i.getNode()->getValue();
352                         value += dtime;
353                         i.getNode()->setValue(value);
354                         if(value >= 60.0)
355                                 remove_queue.push_back(i.getNode()->getKey());
356                 }
357                 core::list<v3s16>::Iterator j;
358                 j = remove_queue.begin();
359                 for(; j != remove_queue.end(); j++)
360                 {
361                         m_fetchblock_history.remove(*j);
362                 }
363         }
364 #endif
365
366         /*{
367                 JMutexAutoLock lock(m_step_dtime_mutex);
368                 m_step_dtime += dtime;
369         }*/
370         
371         /*
372                 BEGIN TEST CODE
373         */
374
375         /*
376                 END OF TEST CODE
377         */
378 }
379
380 float Client::asyncStep()
381 {
382         DSTACK(__FUNCTION_NAME);
383         //dstream<<"Client::asyncStep()"<<std::endl;
384         
385         /*float dtime;
386         {
387                 JMutexAutoLock lock1(m_step_dtime_mutex);
388                 if(m_step_dtime < 0.001)
389                         return 0.0;
390                 dtime = m_step_dtime;
391                 m_step_dtime = 0.0;
392         }
393
394         return dtime;*/
395         return 0.0;
396 }
397
398 // Virtual methods from con::PeerHandler
399 void Client::peerAdded(con::Peer *peer)
400 {
401         derr_client<<"Client::peerAdded(): peer->id="
402                         <<peer->id<<std::endl;
403 }
404 void Client::deletingPeer(con::Peer *peer, bool timeout)
405 {
406         derr_client<<"Client::deletingPeer(): "
407                         "Server Peer is getting deleted "
408                         <<"(timeout="<<timeout<<")"<<std::endl;
409 }
410
411 void Client::ReceiveAll()
412 {
413         DSTACK(__FUNCTION_NAME);
414         for(;;)
415         {
416                 try{
417                         Receive();
418                 }
419                 catch(con::NoIncomingDataException &e)
420                 {
421                         break;
422                 }
423                 catch(con::InvalidIncomingDataException &e)
424                 {
425                         dout_client<<DTIME<<"Client::ReceiveAll(): "
426                                         "InvalidIncomingDataException: what()="
427                                         <<e.what()<<std::endl;
428                 }
429                 //TODO: Testing
430                 //break;
431         }
432 }
433
434 void Client::Receive()
435 {
436         DSTACK(__FUNCTION_NAME);
437         u32 data_maxsize = 10000;
438         Buffer<u8> data(data_maxsize);
439         u16 sender_peer_id;
440         u32 datasize;
441         {
442                 //TimeTaker t1("con mutex and receive", m_device);
443                 JMutexAutoLock lock(m_con_mutex);
444                 datasize = m_con.Receive(sender_peer_id, *data, data_maxsize);
445         }
446         //TimeTaker t1("ProcessData", m_device);
447         ProcessData(*data, datasize, sender_peer_id);
448 }
449
450 /*
451         sender_peer_id given to this shall be quaranteed to be a valid peer
452 */
453 void Client::ProcessData(u8 *data, u32 datasize, u16 sender_peer_id)
454 {
455         DSTACK(__FUNCTION_NAME);
456
457         // Ignore packets that don't even fit a command
458         if(datasize < 2)
459         {
460                 m_packetcounter.add(60000);
461                 return;
462         }
463
464         ToClientCommand command = (ToClientCommand)readU16(&data[0]);
465
466         //dstream<<"Client: received command="<<command<<std::endl;
467         m_packetcounter.add((u16)command);
468         
469         /*
470                 If this check is removed, be sure to change the queue
471                 system to know the ids
472         */
473         if(sender_peer_id != PEER_ID_SERVER)
474         {
475                 dout_client<<DTIME<<"Client::ProcessData(): Discarding data not "
476                                 "coming from server: peer_id="<<sender_peer_id
477                                 <<std::endl;
478                 return;
479         }
480
481         con::Peer *peer;
482         {
483                 JMutexAutoLock lock(m_con_mutex);
484                 // All data is coming from the server
485                 // PeerNotFoundException is handled by caller.
486                 peer = m_con.GetPeer(PEER_ID_SERVER);
487         }
488
489         u8 ser_version = m_server_ser_ver;
490
491         //dstream<<"Client received command="<<(int)command<<std::endl;
492
493         // Execute fast commands straight away
494
495         if(command == TOCLIENT_INIT)
496         {
497                 if(datasize < 3)
498                         return;
499
500                 u8 deployed = data[2];
501
502                 dout_client<<DTIME<<"Client: TOCLIENT_INIT received with "
503                                 "deployed="<<((int)deployed&0xff)<<std::endl;
504
505                 if(deployed < SER_FMT_VER_LOWEST
506                                 || deployed > SER_FMT_VER_HIGHEST)
507                 {
508                         derr_client<<DTIME<<"Client: TOCLIENT_INIT: Server sent "
509                                         <<"unsupported ser_fmt_ver"<<std::endl;
510                         return;
511                 }
512                 
513                 m_server_ser_ver = deployed;
514
515                 // Get player position
516                 v3s16 playerpos_s16(0, BS*2+BS*20, 0);
517                 if(datasize >= 2+1+6)
518                         playerpos_s16 = readV3S16(&data[2+1]);
519                 v3f playerpos_f = intToFloat(playerpos_s16) - v3f(0, BS/2, 0);
520
521                 { //envlock
522                         JMutexAutoLock envlock(m_env_mutex);
523                         
524                         // Set player position
525                         Player *player = m_env.getLocalPlayer();
526                         assert(player != NULL);
527                         player->setPosition(playerpos_f);
528                 }
529                 
530                 // Reply to server
531                 u32 replysize = 2;
532                 SharedBuffer<u8> reply(replysize);
533                 writeU16(&reply[0], TOSERVER_INIT2);
534                 // Send as reliable
535                 m_con.Send(PEER_ID_SERVER, 1, reply, true);
536
537                 return;
538         }
539         
540         if(ser_version == SER_FMT_VER_INVALID)
541         {
542                 dout_client<<DTIME<<"WARNING: Client: Server serialization"
543                                 " format invalid or not initialized."
544                                 " Skipping incoming command="<<command<<std::endl;
545                 return;
546         }
547         
548         // Just here to avoid putting the two if's together when
549         // making some copypasta
550         {}
551
552         if(command == TOCLIENT_PLAYERPOS)
553         {
554                 dstream<<"WARNING: Received deprecated TOCLIENT_PLAYERPOS"
555                                 <<std::endl;
556                 /*u16 our_peer_id;
557                 {
558                         JMutexAutoLock lock(m_con_mutex);
559                         our_peer_id = m_con.GetPeerID();
560                 }
561                 // Cancel if we don't have a peer id
562                 if(our_peer_id == PEER_ID_NEW){
563                         dout_client<<DTIME<<"TOCLIENT_PLAYERPOS cancelled: "
564                                         "we have no peer id"
565                                         <<std::endl;
566                         return;
567                 }*/
568
569                 { //envlock
570                         JMutexAutoLock envlock(m_env_mutex);
571                         
572                         u32 player_size = 2+12+12+4+4;
573                                 
574                         u32 player_count = (datasize-2) / player_size;
575                         u32 start = 2;
576                         for(u32 i=0; i<player_count; i++)
577                         {
578                                 u16 peer_id = readU16(&data[start]);
579
580                                 Player *player = m_env.getPlayer(peer_id);
581
582                                 // Skip if player doesn't exist
583                                 if(player == NULL)
584                                 {
585                                         start += player_size;
586                                         continue;
587                                 }
588
589                                 // Skip if player is local player
590                                 if(player->isLocal())
591                                 {
592                                         start += player_size;
593                                         continue;
594                                 }
595
596                                 v3s32 ps = readV3S32(&data[start+2]);
597                                 v3s32 ss = readV3S32(&data[start+2+12]);
598                                 s32 pitch_i = readS32(&data[start+2+12+12]);
599                                 s32 yaw_i = readS32(&data[start+2+12+12+4]);
600                                 /*dstream<<"Client: got "
601                                                 <<"pitch_i="<<pitch_i
602                                                 <<" yaw_i="<<yaw_i<<std::endl;*/
603                                 f32 pitch = (f32)pitch_i / 100.0;
604                                 f32 yaw = (f32)yaw_i / 100.0;
605                                 v3f position((f32)ps.X/100., (f32)ps.Y/100., (f32)ps.Z/100.);
606                                 v3f speed((f32)ss.X/100., (f32)ss.Y/100., (f32)ss.Z/100.);
607                                 player->setPosition(position);
608                                 player->setSpeed(speed);
609                                 player->setPitch(pitch);
610                                 player->setYaw(yaw);
611
612                                 /*dstream<<"Client: player "<<peer_id
613                                                 <<" pitch="<<pitch
614                                                 <<" yaw="<<yaw<<std::endl;*/
615
616                                 start += player_size;
617                         }
618                 } //envlock
619         }
620         else if(command == TOCLIENT_PLAYERINFO)
621         {
622                 u16 our_peer_id;
623                 {
624                         JMutexAutoLock lock(m_con_mutex);
625                         our_peer_id = m_con.GetPeerID();
626                 }
627                 // Cancel if we don't have a peer id
628                 if(our_peer_id == PEER_ID_NEW){
629                         dout_client<<DTIME<<"TOCLIENT_PLAYERINFO cancelled: "
630                                         "we have no peer id"
631                                         <<std::endl;
632                         return;
633                 }
634                 
635                 //dstream<<DTIME<<"Client: Server reports players:"<<std::endl;
636
637                 { //envlock
638                         JMutexAutoLock envlock(m_env_mutex);
639                         
640                         u32 item_size = 2+PLAYERNAME_SIZE;
641                         u32 player_count = (datasize-2) / item_size;
642                         u32 start = 2;
643                         // peer_ids
644                         core::list<u16> players_alive;
645                         for(u32 i=0; i<player_count; i++)
646                         {
647                                 // Make sure the name ends in '\0'
648                                 data[start+2+20-1] = 0;
649
650                                 u16 peer_id = readU16(&data[start]);
651
652                                 players_alive.push_back(peer_id);
653                                 
654                                 /*dstream<<DTIME<<"peer_id="<<peer_id
655                                                 <<" name="<<((char*)&data[start+2])<<std::endl;*/
656
657                                 // Don't update the info of the local player
658                                 if(peer_id == our_peer_id)
659                                 {
660                                         start += item_size;
661                                         continue;
662                                 }
663
664                                 Player *player = m_env.getPlayer(peer_id);
665
666                                 // Create a player if it doesn't exist
667                                 if(player == NULL)
668                                 {
669                                         player = new RemotePlayer(
670                                                         m_device->getSceneManager()->getRootSceneNode(),
671                                                         m_device,
672                                                         -1);
673                                         player->peer_id = peer_id;
674                                         m_env.addPlayer(player);
675                                         dout_client<<DTIME<<"Client: Adding new player "
676                                                         <<peer_id<<std::endl;
677                                 }
678                                 
679                                 player->updateName((char*)&data[start+2]);
680
681                                 start += item_size;
682                         }
683                         
684                         /*
685                                 Remove those players from the environment that
686                                 weren't listed by the server.
687                         */
688                         //dstream<<DTIME<<"Removing dead players"<<std::endl;
689                         core::list<Player*> players = m_env.getPlayers();
690                         core::list<Player*>::Iterator ip;
691                         for(ip=players.begin(); ip!=players.end(); ip++)
692                         {
693                                 // Ingore local player
694                                 if((*ip)->isLocal())
695                                         continue;
696                                 
697                                 // Warn about a special case
698                                 if((*ip)->peer_id == 0)
699                                 {
700                                         dstream<<DTIME<<"WARNING: Client: Removing "
701                                                         "dead player with id=0"<<std::endl;
702                                 }
703
704                                 bool is_alive = false;
705                                 core::list<u16>::Iterator i;
706                                 for(i=players_alive.begin(); i!=players_alive.end(); i++)
707                                 {
708                                         if((*ip)->peer_id == *i)
709                                         {
710                                                 is_alive = true;
711                                                 break;
712                                         }
713                                 }
714                                 /*dstream<<DTIME<<"peer_id="<<((*ip)->peer_id)
715                                                 <<" is_alive="<<is_alive<<std::endl;*/
716                                 if(is_alive)
717                                         continue;
718                                 dstream<<DTIME<<"Removing dead player "<<(*ip)->peer_id
719                                                 <<std::endl;
720                                 m_env.removePlayer((*ip)->peer_id);
721                         }
722                 } //envlock
723         }
724         else if(command == TOCLIENT_SECTORMETA)
725         {
726                 /*
727                         [0] u16 command
728                         [2] u8 sector count
729                         [3...] v2s16 pos + sector metadata
730                 */
731                 if(datasize < 3)
732                         return;
733
734                 //dstream<<"Client received TOCLIENT_SECTORMETA"<<std::endl;
735
736                 { //envlock
737                         JMutexAutoLock envlock(m_env_mutex);
738                         
739                         std::string datastring((char*)&data[2], datasize-2);
740                         std::istringstream is(datastring, std::ios_base::binary);
741
742                         u8 buf[4];
743
744                         is.read((char*)buf, 1);
745                         u16 sector_count = readU8(buf);
746                         
747                         //dstream<<"sector_count="<<sector_count<<std::endl;
748
749                         for(u16 i=0; i<sector_count; i++)
750                         {
751                                 // Read position
752                                 is.read((char*)buf, 4);
753                                 v2s16 pos = readV2S16(buf);
754                                 /*dstream<<"Client: deserializing sector at "
755                                                 <<"("<<pos.X<<","<<pos.Y<<")"<<std::endl;*/
756                                 // Create sector
757                                 assert(m_env.getMap().mapType() == MAPTYPE_CLIENT);
758                                 ((ClientMap&)m_env.getMap()).deSerializeSector(pos, is);
759                         }
760                 } //envlock
761         }
762         else if(command == TOCLIENT_INVENTORY)
763         {
764                 if(datasize < 3)
765                         return;
766
767                 //TimeTaker t1("Parsing TOCLIENT_INVENTORY", m_device);
768
769                 { //envlock
770                         //TimeTaker t2("mutex locking", m_device);
771                         JMutexAutoLock envlock(m_env_mutex);
772                         //t2.stop();
773                         
774                         //TimeTaker t3("istringstream init", m_device);
775                         std::string datastring((char*)&data[2], datasize-2);
776                         std::istringstream is(datastring, std::ios_base::binary);
777                         //t3.stop();
778                         
779                         //m_env.printPlayers(dstream);
780
781                         //TimeTaker t4("player get", m_device);
782                         Player *player = m_env.getLocalPlayer();
783                         assert(player != NULL);
784                         //t4.stop();
785
786                         //TimeTaker t1("inventory.deSerialize()", m_device);
787                         player->inventory.deSerialize(is);
788                         //t1.stop();
789
790                         m_inventory_updated = true;
791
792                         //dstream<<"Client got player inventory:"<<std::endl;
793                         //player->inventory.print(dstream);
794                 }
795         }
796         //DEBUG
797         else if(command == TOCLIENT_OBJECTDATA)
798         //else if(0)
799         {
800                 // Strip command word and create a stringstream
801                 std::string datastring((char*)&data[2], datasize-2);
802                 std::istringstream is(datastring, std::ios_base::binary);
803                 
804                 { //envlock
805                 
806                 JMutexAutoLock envlock(m_env_mutex);
807
808                 u8 buf[12];
809
810                 /*
811                         Read players
812                 */
813
814                 is.read((char*)buf, 2);
815                 u16 playercount = readU16(buf);
816                 
817                 for(u16 i=0; i<playercount; i++)
818                 {
819                         is.read((char*)buf, 2);
820                         u16 peer_id = readU16(buf);
821                         is.read((char*)buf, 12);
822                         v3s32 p_i = readV3S32(buf);
823                         is.read((char*)buf, 12);
824                         v3s32 s_i = readV3S32(buf);
825                         is.read((char*)buf, 4);
826                         s32 pitch_i = readS32(buf);
827                         is.read((char*)buf, 4);
828                         s32 yaw_i = readS32(buf);
829                         
830                         Player *player = m_env.getPlayer(peer_id);
831
832                         // Skip if player doesn't exist
833                         if(player == NULL)
834                         {
835                                 continue;
836                         }
837
838                         // Skip if player is local player
839                         if(player->isLocal())
840                         {
841                                 continue;
842                         }
843         
844                         f32 pitch = (f32)pitch_i / 100.0;
845                         f32 yaw = (f32)yaw_i / 100.0;
846                         v3f position((f32)p_i.X/100., (f32)p_i.Y/100., (f32)p_i.Z/100.);
847                         v3f speed((f32)s_i.X/100., (f32)s_i.Y/100., (f32)s_i.Z/100.);
848                         
849                         player->setPosition(position);
850                         player->setSpeed(speed);
851                         player->setPitch(pitch);
852                         player->setYaw(yaw);
853                 }
854
855                 /*
856                         Read block objects
857                 */
858
859                 // Read active block count
860                 is.read((char*)buf, 2);
861                 u16 blockcount = readU16(buf);
862                 
863                 // Initialize delete queue with all active blocks
864                 core::map<v3s16, bool> abs_to_delete;
865                 for(core::map<v3s16, bool>::Iterator
866                                 i = m_active_blocks.getIterator();
867                                 i.atEnd() == false; i++)
868                 {
869                         v3s16 p = i.getNode()->getKey();
870                         /*dstream<<"adding "
871                                         <<"("<<p.x<<","<<p.y<<","<<p.z<<") "
872                                         <<" to abs_to_delete"
873                                         <<std::endl;*/
874                         abs_to_delete.insert(p, true);
875                 }
876
877                 /*dstream<<"Initial delete queue size: "<<abs_to_delete.size()
878                                 <<std::endl;*/
879                 
880                 for(u16 i=0; i<blockcount; i++)
881                 {
882                         // Read blockpos
883                         is.read((char*)buf, 6);
884                         v3s16 p = readV3S16(buf);
885                         // Get block from somewhere
886                         MapBlock *block = NULL;
887                         try{
888                                 block = m_env.getMap().getBlockNoCreate(p);
889                         }
890                         catch(InvalidPositionException &e)
891                         {
892                                 //TODO: Create a dummy block?
893                         }
894                         if(block == NULL)
895                         {
896                                 dstream<<"WARNING: "
897                                                 <<"Could not get block at blockpos "
898                                                 <<"("<<p.X<<","<<p.Y<<","<<p.Z<<") "
899                                                 <<"in TOCLIENT_OBJECTDATA. Ignoring "
900                                                 <<"following block object data."
901                                                 <<std::endl;
902                                 return;
903                         }
904
905                         /*dstream<<"Client updating objects for block "
906                                         <<"("<<p.X<<","<<p.Y<<","<<p.Z<<")"
907                                         <<std::endl;*/
908
909                         // Insert to active block list
910                         m_active_blocks.insert(p, true);
911
912                         // Remove from deletion queue
913                         if(abs_to_delete.find(p) != NULL)
914                                 abs_to_delete.remove(p);
915
916                         // Update objects of block
917                         block->updateObjects(is, m_server_ser_ver,
918                                         m_device->getSceneManager());
919                 }
920                 
921                 /*dstream<<"Final delete queue size: "<<abs_to_delete.size()
922                                 <<std::endl;*/
923                 
924                 // Delete objects of blocks in delete queue
925                 for(core::map<v3s16, bool>::Iterator
926                                 i = abs_to_delete.getIterator();
927                                 i.atEnd() == false; i++)
928                 {
929                         v3s16 p = i.getNode()->getKey();
930                         try
931                         {
932                                 MapBlock *block = m_env.getMap().getBlockNoCreate(p);
933                                 
934                                 // Clear objects
935                                 block->clearObjects();
936                                 // Remove from active blocks list
937                                 m_active_blocks.remove(p);
938                         }
939                         catch(InvalidPositionException &e)
940                         {
941                                 dstream<<"WARNAING: Client: "
942                                                 <<"Couldn't clear objects of active->inactive"
943                                                 <<" block "
944                                                 <<"("<<p.X<<","<<p.Y<<","<<p.Z<<")"
945                                                 <<" because block was not found"
946                                                 <<std::endl;
947                                 // Ignore
948                         }
949                 }
950
951                 } //envlock
952         }
953         // Default to queueing it (for slow commands)
954         else
955         {
956                 JMutexAutoLock lock(m_incoming_queue_mutex);
957                 
958                 IncomingPacket packet(data, datasize);
959                 m_incoming_queue.push_back(packet);
960         }
961 }
962
963 /*
964         Returns true if there was something in queue
965 */
966 bool Client::AsyncProcessPacket(LazyMeshUpdater &mesh_updater)
967 {
968         DSTACK(__FUNCTION_NAME);
969         
970         try //for catching con::PeerNotFoundException
971         {
972
973         con::Peer *peer;
974         {
975                 JMutexAutoLock lock(m_con_mutex);
976                 // All data is coming from the server
977                 peer = m_con.GetPeer(PEER_ID_SERVER);
978         }
979         
980         u8 ser_version = m_server_ser_ver;
981
982         IncomingPacket packet = getPacket();
983         u8 *data = packet.m_data;
984         u32 datasize = packet.m_datalen;
985         
986         // An empty packet means queue is empty
987         if(data == NULL){
988                 return false;
989         }
990         
991         if(datasize < 2)
992                 return true;
993         
994         ToClientCommand command = (ToClientCommand)readU16(&data[0]);
995
996         if(command == TOCLIENT_REMOVENODE)
997         {
998                 if(datasize < 8)
999                         return true;
1000                 v3s16 p;
1001                 p.X = readS16(&data[2]);
1002                 p.Y = readS16(&data[4]);
1003                 p.Z = readS16(&data[6]);
1004                 
1005                 //TimeTaker t1("TOCLIENT_REMOVENODE", g_device);
1006
1007                 core::map<v3s16, MapBlock*> modified_blocks;
1008
1009                 try
1010                 {
1011                         JMutexAutoLock envlock(m_env_mutex);
1012                         //TimeTaker t("removeNodeAndUpdate", m_device);
1013                         m_env.getMap().removeNodeAndUpdate(p, modified_blocks);
1014                 }
1015                 catch(InvalidPositionException &e)
1016                 {
1017                 }
1018                 
1019                 for(core::map<v3s16, MapBlock * >::Iterator
1020                                 i = modified_blocks.getIterator();
1021                                 i.atEnd() == false; i++)
1022                 {
1023                         v3s16 p = i.getNode()->getKey();
1024                         //m_env.getMap().updateMeshes(p);
1025                         mesh_updater.add(p);
1026                 }
1027         }
1028         else if(command == TOCLIENT_ADDNODE)
1029         {
1030                 if(datasize < 8 + MapNode::serializedLength(ser_version))
1031                         return true;
1032
1033                 v3s16 p;
1034                 p.X = readS16(&data[2]);
1035                 p.Y = readS16(&data[4]);
1036                 p.Z = readS16(&data[6]);
1037                 
1038                 //TimeTaker t1("TOCLIENT_ADDNODE", g_device);
1039
1040                 MapNode n;
1041                 n.deSerialize(&data[8], ser_version);
1042                 
1043                 core::map<v3s16, MapBlock*> modified_blocks;
1044
1045                 try
1046                 {
1047                         JMutexAutoLock envlock(m_env_mutex);
1048                         m_env.getMap().addNodeAndUpdate(p, n, modified_blocks);
1049                 }
1050                 catch(InvalidPositionException &e)
1051                 {}
1052                 
1053                 for(core::map<v3s16, MapBlock * >::Iterator
1054                                 i = modified_blocks.getIterator();
1055                                 i.atEnd() == false; i++)
1056                 {
1057                         v3s16 p = i.getNode()->getKey();
1058                         //m_env.getMap().updateMeshes(p);
1059                         mesh_updater.add(p);
1060                 }
1061         }
1062         else if(command == TOCLIENT_BLOCKDATA)
1063         {
1064                 // Ignore too small packet
1065                 if(datasize < 8)
1066                         return true;
1067                 /*if(datasize < 8 + MapBlock::serializedLength(ser_version))
1068                         goto getdata;*/
1069                         
1070                 v3s16 p;
1071                 p.X = readS16(&data[2]);
1072                 p.Y = readS16(&data[4]);
1073                 p.Z = readS16(&data[6]);
1074                 
1075                 /*dout_client<<DTIME<<"Client: Thread: BLOCKDATA for ("
1076                                 <<p.X<<","<<p.Y<<","<<p.Z<<")"<<std::endl;*/
1077
1078                 /*dstream<<DTIME<<"Client: Thread: BLOCKDATA for ("
1079                                 <<p.X<<","<<p.Y<<","<<p.Z<<"): ";*/
1080                 
1081                 std::string datastring((char*)&data[8], datasize-8);
1082                 std::istringstream istr(datastring, std::ios_base::binary);
1083                 
1084                 MapSector *sector;
1085                 MapBlock *block;
1086                 
1087                 { //envlock
1088                         JMutexAutoLock envlock(m_env_mutex);
1089                         
1090                         v2s16 p2d(p.X, p.Z);
1091                         sector = m_env.getMap().emergeSector(p2d);
1092                         
1093                         v2s16 sp = sector->getPos();
1094                         if(sp != p2d)
1095                         {
1096                                 dstream<<"ERROR: Got sector with getPos()="
1097                                                 <<"("<<sp.X<<","<<sp.Y<<"), tried to get"
1098                                                 <<"("<<p2d.X<<","<<p2d.Y<<")"<<std::endl;
1099                         }
1100
1101                         assert(sp == p2d);
1102                         //assert(sector->getPos() == p2d);
1103                         
1104                         try{
1105                                 block = sector->getBlockNoCreate(p.Y);
1106                                 /*
1107                                         Update an existing block
1108                                 */
1109                                 //dstream<<"Updating"<<std::endl;
1110                                 block->deSerialize(istr, ser_version);
1111                                 //block->setChangedFlag();
1112                         }
1113                         catch(InvalidPositionException &e)
1114                         {
1115                                 /*
1116                                         Create a new block
1117                                 */
1118                                 //dstream<<"Creating new"<<std::endl;
1119                                 block = new MapBlock(&m_env.getMap(), p);
1120                                 block->deSerialize(istr, ser_version);
1121                                 sector->insertBlock(block);
1122                                 //block->setChangedFlag();
1123                         }
1124                 } //envlock
1125                 
1126                 
1127                 // Old version has zero lighting, update it.
1128                 if(ser_version == 0 || ser_version == 1)
1129                 {
1130                         derr_client<<"Client: Block in old format: "
1131                                         "Calculating lighting"<<std::endl;
1132                         core::map<v3s16, MapBlock*> blocks_changed;
1133                         blocks_changed.insert(block->getPos(), block);
1134                         core::map<v3s16, MapBlock*> modified_blocks;
1135                         m_env.getMap().updateLighting(blocks_changed, modified_blocks);
1136                 }
1137
1138                 /*
1139                         Update Mesh of this block and blocks at x-, y- and z-
1140                 */
1141
1142                 //m_env.getMap().updateMeshes(block->getPos());
1143                 mesh_updater.add(block->getPos());
1144                 
1145                 /*
1146                         Acknowledge block.
1147                 */
1148                 /*
1149                         [0] u16 command
1150                         [2] u8 count
1151                         [3] v3s16 pos_0
1152                         [3+6] v3s16 pos_1
1153                         ...
1154                 */
1155                 u32 replysize = 2+1+6;
1156                 SharedBuffer<u8> reply(replysize);
1157                 writeU16(&reply[0], TOSERVER_GOTBLOCKS);
1158                 reply[2] = 1;
1159                 writeV3S16(&reply[3], p);
1160                 // Send as reliable
1161                 m_con.Send(PEER_ID_SERVER, 1, reply, true);
1162
1163 #if 0
1164                 /*
1165                         Remove from history
1166                 */
1167                 {
1168                         JMutexAutoLock lock(m_fetchblock_mutex);
1169                         
1170                         if(m_fetchblock_history.find(p) != NULL)
1171                         {
1172                                 m_fetchblock_history.remove(p);
1173                         }
1174                         else
1175                         {
1176                                 /*
1177                                         Acknowledge block.
1178                                 */
1179                                 /*
1180                                         [0] u16 command
1181                                         [2] u8 count
1182                                         [3] v3s16 pos_0
1183                                         [3+6] v3s16 pos_1
1184                                         ...
1185                                 */
1186                                 u32 replysize = 2+1+6;
1187                                 SharedBuffer<u8> reply(replysize);
1188                                 writeU16(&reply[0], TOSERVER_GOTBLOCKS);
1189                                 reply[2] = 1;
1190                                 writeV3S16(&reply[3], p);
1191                                 // Send as reliable
1192                                 m_con.Send(PEER_ID_SERVER, 1, reply, true);
1193                         }
1194                 }
1195 #endif
1196         }
1197         else
1198         {
1199                 dout_client<<DTIME<<"WARNING: Client: Ignoring unknown command "
1200                                 <<command<<std::endl;
1201         }
1202
1203         return true;
1204
1205         } //try
1206         catch(con::PeerNotFoundException &e)
1207         {
1208                 dout_client<<DTIME<<"Client::AsyncProcessData(): Cancelling: The server"
1209                                 " connection doesn't exist (a timeout or not yet connected?)"<<std::endl;
1210                 return false;
1211         }
1212 }
1213
1214 bool Client::AsyncProcessData()
1215 {
1216         for(;;)
1217         {
1218                 // We want to update the meshes as soon as a single packet has
1219                 // been processed
1220                 LazyMeshUpdater mesh_updater(&m_env);
1221                 bool r = AsyncProcessPacket(mesh_updater);
1222                 if(r == false)
1223                         break;
1224         }
1225         return false;
1226
1227         /*LazyMeshUpdater mesh_updater(&m_env);
1228         for(;;)
1229         {
1230                 bool r = AsyncProcessPacket(mesh_updater);
1231                 if(r == false)
1232                         break;
1233         }
1234         return false;*/
1235
1236 }
1237
1238 void Client::Send(u16 channelnum, SharedBuffer<u8> data, bool reliable)
1239 {
1240         JMutexAutoLock lock(m_con_mutex);
1241         m_con.Send(PEER_ID_SERVER, channelnum, data, reliable);
1242 }
1243
1244 #if 0
1245 void Client::fetchBlock(v3s16 p, u8 flags)
1246 {
1247         if(connectedAndInitialized() == false)
1248                 throw ClientNotReadyException
1249                 ("ClientNotReadyException: connectedAndInitialized() == false");
1250
1251         /*dstream<<"Client::fetchBlock(): Sending GETBLOCK for ("
1252                         <<p.X<<","<<p.Y<<","<<p.Z<<")"<<std::endl;*/
1253
1254         JMutexAutoLock conlock(m_con_mutex);
1255
1256         SharedBuffer<u8> data(9);
1257         writeU16(&data[0], TOSERVER_GETBLOCK);
1258         writeS16(&data[2], p.X);
1259         writeS16(&data[4], p.Y);
1260         writeS16(&data[6], p.Z);
1261         writeU8(&data[8], flags);
1262         m_con.Send(PEER_ID_SERVER, 1, data, true);
1263 }
1264
1265 /*
1266         Calls fetchBlock() on some nearby missing blocks.
1267
1268         Returns when any of various network load indicators go over limit.
1269
1270         Does nearly the same thing as the old updateChangedVisibleArea()
1271 */
1272 void Client::fetchBlocks()
1273 {
1274         if(connectedAndInitialized() == false)
1275                 throw ClientNotReadyException
1276                 ("ClientNotReadyException: connectedAndInitialized() == false");
1277 }
1278 #endif
1279
1280 bool Client::isFetchingBlocks()
1281 {
1282         JMutexAutoLock conlock(m_con_mutex);
1283         con::Peer *peer = m_con.GetPeerNoEx(PEER_ID_SERVER);
1284         // Not really fetching but can't fetch more.
1285         if(peer == NULL) return true;
1286
1287         con::Channel *channel = &(peer->channels[1]);
1288         /*
1289                 NOTE: Channel 0 should always be used for fetching blocks,
1290                       and for nothing else.
1291         */
1292         if(channel->incoming_reliables.size() > 0)
1293                 return true;
1294         if(channel->outgoing_reliables.size() > 0)
1295                 return true;
1296         return false;
1297 }
1298
1299 IncomingPacket Client::getPacket()
1300 {
1301         JMutexAutoLock lock(m_incoming_queue_mutex);
1302         
1303         core::list<IncomingPacket>::Iterator i;
1304         // Refer to first one
1305         i = m_incoming_queue.begin();
1306
1307         // If queue is empty, return empty packet
1308         if(i == m_incoming_queue.end()){
1309                 IncomingPacket packet;
1310                 return packet;
1311         }
1312         
1313         // Pop out first packet and return it
1314         IncomingPacket packet = *i;
1315         m_incoming_queue.erase(i);
1316         return packet;
1317 }
1318
1319 #if 0
1320 void Client::removeNode(v3s16 nodepos)
1321 {
1322         if(connectedAndInitialized() == false){
1323                 dout_client<<DTIME<<"Client::removeNode() cancelled (not connected)"
1324                                 <<std::endl;
1325                 return;
1326         }
1327         
1328         // Test that the position exists
1329         try{
1330                 JMutexAutoLock envlock(m_env_mutex);
1331                 m_env.getMap().getNode(nodepos);
1332         }
1333         catch(InvalidPositionException &e)
1334         {
1335                 dout_client<<DTIME<<"Client::removeNode() cancelled (doesn't exist)"
1336                                 <<std::endl;
1337                 return;
1338         }
1339
1340         SharedBuffer<u8> data(8);
1341         writeU16(&data[0], TOSERVER_REMOVENODE);
1342         writeS16(&data[2], nodepos.X);
1343         writeS16(&data[4], nodepos.Y);
1344         writeS16(&data[6], nodepos.Z);
1345         Send(0, data, true);
1346 }
1347
1348 void Client::addNodeFromInventory(v3s16 nodepos, u16 i)
1349 {
1350         if(connectedAndInitialized() == false){
1351                 dout_client<<DTIME<<"Client::addNodeFromInventory() "
1352                                 "cancelled (not connected)"
1353                                 <<std::endl;
1354                 return;
1355         }
1356         
1357         // Test that the position exists
1358         try{
1359                 JMutexAutoLock envlock(m_env_mutex);
1360                 m_env.getMap().getNode(nodepos);
1361         }
1362         catch(InvalidPositionException &e)
1363         {
1364                 dout_client<<DTIME<<"Client::addNode() cancelled (doesn't exist)"
1365                                 <<std::endl;
1366                 return;
1367         }
1368
1369         //u8 ser_version = m_server_ser_ver;
1370
1371         // SUGGESTION: The validity of the operation could be checked here too
1372
1373         u8 datasize = 2 + 6 + 2;
1374         SharedBuffer<u8> data(datasize);
1375         writeU16(&data[0], TOSERVER_ADDNODE_FROM_INVENTORY);
1376         writeS16(&data[2], nodepos.X);
1377         writeS16(&data[4], nodepos.Y);
1378         writeS16(&data[6], nodepos.Z);
1379         writeU16(&data[8], i);
1380         Send(0, data, true);
1381 }
1382 #endif
1383
1384 void Client::clickGround(u8 button, v3s16 nodepos_undersurface,
1385                 v3s16 nodepos_oversurface, u16 item)
1386 {
1387         if(connectedAndInitialized() == false){
1388                 dout_client<<DTIME<<"Client::clickGround() "
1389                                 "cancelled (not connected)"
1390                                 <<std::endl;
1391                 return;
1392         }
1393         
1394         /*
1395                 length: 19
1396                 [0] u16 command
1397                 [2] u8 button (0=left, 1=right)
1398                 [3] v3s16 nodepos_undersurface
1399                 [9] v3s16 nodepos_abovesurface
1400                 [15] u16 item
1401         */
1402         u8 datasize = 2 + 1 + 6 + 6 + 2;
1403         SharedBuffer<u8> data(datasize);
1404         writeU16(&data[0], TOSERVER_CLICK_GROUND);
1405         writeU8(&data[2], button);
1406         writeV3S16(&data[3], nodepos_undersurface);
1407         writeV3S16(&data[9], nodepos_oversurface);
1408         writeU16(&data[15], item);
1409         Send(0, data, true);
1410 }
1411
1412 void Client::clickObject(u8 button, v3s16 blockpos, s16 id, u16 item)
1413 {
1414         if(connectedAndInitialized() == false){
1415                 dout_client<<DTIME<<"Client::clickObject() "
1416                                 "cancelled (not connected)"
1417                                 <<std::endl;
1418                 return;
1419         }
1420         
1421         /*
1422                 [0] u16 command
1423                 [2] u8 button (0=left, 1=right)
1424                 [3] v3s16 block
1425                 [9] s16 id
1426                 [11] u16 item
1427         */
1428         u8 datasize = 2 + 1 + 6 + 2 + 2;
1429         SharedBuffer<u8> data(datasize);
1430         writeU16(&data[0], TOSERVER_CLICK_OBJECT);
1431         writeU8(&data[2], button);
1432         writeV3S16(&data[3], blockpos);
1433         writeS16(&data[9], id);
1434         writeU16(&data[11], item);
1435         Send(0, data, true);
1436 }
1437
1438 void Client::release(u8 button)
1439 {
1440         //TODO
1441 }
1442
1443 void Client::sendSignText(v3s16 blockpos, s16 id, std::string text)
1444 {
1445         /*
1446                 u16 command
1447                 v3s16 blockpos
1448                 s16 id
1449                 u16 textlen
1450                 textdata
1451         */
1452         std::ostringstream os(std::ios_base::binary);
1453         u8 buf[12];
1454         
1455         // Write command
1456         writeU16(buf, TOSERVER_SIGNTEXT);
1457         os.write((char*)buf, 2);
1458         
1459         // Write blockpos
1460         writeV3S16(buf, blockpos);
1461         os.write((char*)buf, 6);
1462
1463         // Write id
1464         writeS16(buf, id);
1465         os.write((char*)buf, 2);
1466
1467         u16 textlen = text.size();
1468         // Write text length
1469         writeS16(buf, textlen);
1470         os.write((char*)buf, 2);
1471
1472         // Write text
1473         os.write((char*)text.c_str(), textlen);
1474         
1475         // Make data buffer
1476         std::string s = os.str();
1477         SharedBuffer<u8> data((u8*)s.c_str(), s.size());
1478         // Send as reliable
1479         Send(0, data, true);
1480 }
1481
1482 void Client::sendPlayerPos()
1483 {
1484         JMutexAutoLock envlock(m_env_mutex);
1485         
1486         Player *myplayer = m_env.getLocalPlayer();
1487         if(myplayer == NULL)
1488                 return;
1489         
1490         u16 our_peer_id;
1491         {
1492                 JMutexAutoLock lock(m_con_mutex);
1493                 our_peer_id = m_con.GetPeerID();
1494         }
1495         
1496         // Set peer id if not set already
1497         if(myplayer->peer_id == PEER_ID_NEW)
1498                 myplayer->peer_id = our_peer_id;
1499         // Check that an existing peer_id is the same as the connection's
1500         assert(myplayer->peer_id == our_peer_id);
1501         
1502         v3f pf = myplayer->getPosition();
1503         v3s32 position(pf.X*100, pf.Y*100, pf.Z*100);
1504         v3f sf = myplayer->getSpeed();
1505         v3s32 speed(sf.X*100, sf.Y*100, sf.Z*100);
1506         s32 pitch = myplayer->getPitch() * 100;
1507         s32 yaw = myplayer->getYaw() * 100;
1508
1509         /*
1510                 Format:
1511                 [0] u16 command
1512                 [2] v3s32 position*100
1513                 [2+12] v3s32 speed*100
1514                 [2+12+12] s32 pitch*100
1515                 [2+12+12+4] s32 yaw*100
1516         */
1517
1518         SharedBuffer<u8> data(2+12+12+4+4);
1519         writeU16(&data[0], TOSERVER_PLAYERPOS);
1520         writeV3S32(&data[2], position);
1521         writeV3S32(&data[2+12], speed);
1522         writeS32(&data[2+12+12], pitch);
1523         writeS32(&data[2+12+12+4], yaw);
1524
1525         // Send as unreliable
1526         Send(0, data, false);
1527 }
1528
1529
1530 void Client::updateCamera(v3f pos, v3f dir)
1531 {
1532         m_env.getMap().updateCamera(pos, dir);
1533         camera_position = pos;
1534         camera_direction = dir;
1535 }
1536
1537 MapNode Client::getNode(v3s16 p)
1538 {
1539         JMutexAutoLock envlock(m_env_mutex);
1540         return m_env.getMap().getNode(p);
1541 }
1542
1543 /*f32 Client::getGroundHeight(v2s16 p)
1544 {
1545         JMutexAutoLock envlock(m_env_mutex);
1546         return m_env.getMap().getGroundHeight(p);
1547 }*/
1548
1549 bool Client::isNodeUnderground(v3s16 p)
1550 {
1551         JMutexAutoLock envlock(m_env_mutex);
1552         return m_env.getMap().isNodeUnderground(p);
1553 }
1554
1555 /*Player * Client::getLocalPlayer()
1556 {
1557         JMutexAutoLock envlock(m_env_mutex);
1558         return m_env.getLocalPlayer();
1559 }*/
1560
1561 /*core::list<Player*> Client::getPlayers()
1562 {
1563         JMutexAutoLock envlock(m_env_mutex);
1564         return m_env.getPlayers();
1565 }*/
1566
1567 v3f Client::getPlayerPosition()
1568 {
1569         JMutexAutoLock envlock(m_env_mutex);
1570         LocalPlayer *player = m_env.getLocalPlayer();
1571         assert(player != NULL);
1572         return player->getPosition();
1573 }
1574
1575 void Client::setPlayerControl(PlayerControl &control)
1576 {
1577         JMutexAutoLock envlock(m_env_mutex);
1578         LocalPlayer *player = m_env.getLocalPlayer();
1579         assert(player != NULL);
1580         player->control = control;
1581 }
1582
1583 // Returns true if the inventory of the local player has been
1584 // updated from the server. If it is true, it is set to false.
1585 bool Client::getLocalInventoryUpdated()
1586 {
1587         // m_inventory_updated is behind envlock
1588         JMutexAutoLock envlock(m_env_mutex);
1589         bool updated = m_inventory_updated;
1590         m_inventory_updated = false;
1591         return updated;
1592 }
1593
1594 // Copies the inventory of the local player to parameter
1595 void Client::getLocalInventory(Inventory &dst)
1596 {
1597         JMutexAutoLock envlock(m_env_mutex);
1598         Player *player = m_env.getLocalPlayer();
1599         assert(player != NULL);
1600         dst = player->inventory;
1601 }
1602
1603 MapBlockObject * Client::getSelectedObject(
1604                 f32 max_d,
1605                 v3f from_pos_f_on_map,
1606                 core::line3d<f32> shootline_on_map
1607         )
1608 {
1609         JMutexAutoLock envlock(m_env_mutex);
1610
1611         core::array<DistanceSortedObject> objects;
1612
1613         for(core::map<v3s16, bool>::Iterator
1614                         i = m_active_blocks.getIterator();
1615                         i.atEnd() == false; i++)
1616         {
1617                 v3s16 p = i.getNode()->getKey();
1618
1619                 MapBlock *block = NULL;
1620                 try
1621                 {
1622                         block = m_env.getMap().getBlockNoCreate(p);
1623                 }
1624                 catch(InvalidPositionException &e)
1625                 {
1626                         continue;
1627                 }
1628
1629                 // Calculate from_pos relative to block
1630                 v3s16 block_pos_i_on_map = block->getPosRelative();
1631                 v3f block_pos_f_on_map = intToFloat(block_pos_i_on_map);
1632                 v3f from_pos_f_on_block = from_pos_f_on_map - block_pos_f_on_map;
1633
1634                 block->getObjects(from_pos_f_on_block, max_d, objects);
1635         }
1636
1637         //dstream<<"Collected "<<objects.size()<<" nearby objects"<<std::endl;
1638         
1639         // Sort them.
1640         // After this, the closest object is the first in the array.
1641         objects.sort();
1642
1643         for(u32 i=0; i<objects.size(); i++)
1644         {
1645                 MapBlockObject *obj = objects[i].obj;
1646                 MapBlock *block = obj->getBlock();
1647
1648                 // Calculate shootline relative to block
1649                 v3s16 block_pos_i_on_map = block->getPosRelative();
1650                 v3f block_pos_f_on_map = intToFloat(block_pos_i_on_map);
1651                 core::line3d<f32> shootline_on_block(
1652                                 shootline_on_map.start - block_pos_f_on_map,
1653                                 shootline_on_map.end - block_pos_f_on_map
1654                 );
1655
1656                 if(obj->isSelected(shootline_on_block))
1657                 {
1658                         //dstream<<"Returning selected object"<<std::endl;
1659                         return obj;
1660                 }
1661         }
1662
1663         //dstream<<"No object selected; returning NULL."<<std::endl;
1664         return NULL;
1665 }
1666
1667 void Client::printDebugInfo(std::ostream &os)
1668 {
1669         //JMutexAutoLock lock1(m_fetchblock_mutex);
1670         JMutexAutoLock lock2(m_incoming_queue_mutex);
1671
1672         os<<"m_incoming_queue.getSize()="<<m_incoming_queue.getSize()
1673                 //<<", m_fetchblock_history.size()="<<m_fetchblock_history.size()
1674                 //<<", m_opt_not_found_history.size()="<<m_opt_not_found_history.size()
1675                 <<std::endl;
1676 }
1677         
1678