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