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