Generic NodeMetadata text input
[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         SharedBuffer<u8> data;
669         u16 sender_peer_id;
670         u32 datasize;
671         {
672                 //TimeTaker t1("con mutex and receive", m_device);
673                 //JMutexAutoLock lock(m_con_mutex); //bulk comment-out
674                 datasize = m_con.Receive(sender_peer_id, data);
675         }
676         //TimeTaker t1("ProcessData", m_device);
677         ProcessData(*data, datasize, sender_peer_id);
678 }
679
680 /*
681         sender_peer_id given to this shall be quaranteed to be a valid peer
682 */
683 void Client::ProcessData(u8 *data, u32 datasize, u16 sender_peer_id)
684 {
685         DSTACK(__FUNCTION_NAME);
686
687         // Ignore packets that don't even fit a command
688         if(datasize < 2)
689         {
690                 m_packetcounter.add(60000);
691                 return;
692         }
693
694         ToClientCommand command = (ToClientCommand)readU16(&data[0]);
695
696         //infostream<<"Client: received command="<<command<<std::endl;
697         m_packetcounter.add((u16)command);
698         
699         /*
700                 If this check is removed, be sure to change the queue
701                 system to know the ids
702         */
703         if(sender_peer_id != PEER_ID_SERVER)
704         {
705                 infostream<<"Client::ProcessData(): Discarding data not "
706                                 "coming from server: peer_id="<<sender_peer_id
707                                 <<std::endl;
708                 return;
709         }
710
711         u8 ser_version = m_server_ser_ver;
712
713         //infostream<<"Client received command="<<(int)command<<std::endl;
714
715         if(command == TOCLIENT_INIT)
716         {
717                 if(datasize < 3)
718                         return;
719
720                 u8 deployed = data[2];
721
722                 infostream<<"Client: TOCLIENT_INIT received with "
723                                 "deployed="<<((int)deployed&0xff)<<std::endl;
724
725                 if(deployed < SER_FMT_VER_LOWEST
726                                 || deployed > SER_FMT_VER_HIGHEST)
727                 {
728                         infostream<<"Client: TOCLIENT_INIT: Server sent "
729                                         <<"unsupported ser_fmt_ver"<<std::endl;
730                         return;
731                 }
732                 
733                 m_server_ser_ver = deployed;
734
735                 // Get player position
736                 v3s16 playerpos_s16(0, BS*2+BS*20, 0);
737                 if(datasize >= 2+1+6)
738                         playerpos_s16 = readV3S16(&data[2+1]);
739                 v3f playerpos_f = intToFloat(playerpos_s16, BS) - v3f(0, BS/2, 0);
740
741                 { //envlock
742                         //JMutexAutoLock envlock(m_env_mutex); //bulk comment-out
743                         
744                         // Set player position
745                         Player *player = m_env.getLocalPlayer();
746                         assert(player != NULL);
747                         player->setPosition(playerpos_f);
748                 }
749                 
750                 if(datasize >= 2+1+6+8)
751                 {
752                         // Get map seed
753                         m_map_seed = readU64(&data[2+1+6]);
754                         infostream<<"Client: received map seed: "<<m_map_seed<<std::endl;
755                 }
756                 
757                 // Reply to server
758                 u32 replysize = 2;
759                 SharedBuffer<u8> reply(replysize);
760                 writeU16(&reply[0], TOSERVER_INIT2);
761                 // Send as reliable
762                 m_con.Send(PEER_ID_SERVER, 1, reply, true);
763
764                 return;
765         }
766
767         if(command == TOCLIENT_ACCESS_DENIED)
768         {
769                 // The server didn't like our password. Note, this needs
770                 // to be processed even if the serialisation format has
771                 // not been agreed yet, the same as TOCLIENT_INIT.
772                 m_access_denied = true;
773                 m_access_denied_reason = L"Unknown";
774                 if(datasize >= 4)
775                 {
776                         std::string datastring((char*)&data[2], datasize-2);
777                         std::istringstream is(datastring, std::ios_base::binary);
778                         m_access_denied_reason = deSerializeWideString(is);
779                 }
780                 return;
781         }
782
783         if(ser_version == SER_FMT_VER_INVALID)
784         {
785                 infostream<<"Client: Server serialization"
786                                 " format invalid or not initialized."
787                                 " Skipping incoming command="<<command<<std::endl;
788                 return;
789         }
790         
791         // Just here to avoid putting the two if's together when
792         // making some copypasta
793         {}
794
795         if(command == TOCLIENT_REMOVENODE)
796         {
797                 if(datasize < 8)
798                         return;
799                 v3s16 p;
800                 p.X = readS16(&data[2]);
801                 p.Y = readS16(&data[4]);
802                 p.Z = readS16(&data[6]);
803                 
804                 //TimeTaker t1("TOCLIENT_REMOVENODE");
805                 
806                 // This will clear the cracking animation after digging
807                 ((ClientMap&)m_env.getMap()).clearTempMod(p);
808
809                 removeNode(p);
810         }
811         else if(command == TOCLIENT_ADDNODE)
812         {
813                 if(datasize < 8 + MapNode::serializedLength(ser_version))
814                         return;
815
816                 v3s16 p;
817                 p.X = readS16(&data[2]);
818                 p.Y = readS16(&data[4]);
819                 p.Z = readS16(&data[6]);
820                 
821                 //TimeTaker t1("TOCLIENT_ADDNODE");
822
823                 MapNode n;
824                 n.deSerialize(&data[8], ser_version);
825                 
826                 addNode(p, n);
827         }
828         else if(command == TOCLIENT_BLOCKDATA)
829         {
830                 // Ignore too small packet
831                 if(datasize < 8)
832                         return;
833                         
834                 v3s16 p;
835                 p.X = readS16(&data[2]);
836                 p.Y = readS16(&data[4]);
837                 p.Z = readS16(&data[6]);
838                 
839                 /*infostream<<"Client: Thread: BLOCKDATA for ("
840                                 <<p.X<<","<<p.Y<<","<<p.Z<<")"<<std::endl;*/
841                 /*infostream<<"Client: Thread: BLOCKDATA for ("
842                                 <<p.X<<","<<p.Y<<","<<p.Z<<")"<<std::endl;*/
843                 
844                 std::string datastring((char*)&data[8], datasize-8);
845                 std::istringstream istr(datastring, std::ios_base::binary);
846                 
847                 MapSector *sector;
848                 MapBlock *block;
849                 
850                 v2s16 p2d(p.X, p.Z);
851                 sector = m_env.getMap().emergeSector(p2d);
852                 
853                 assert(sector->getPos() == p2d);
854
855                 //TimeTaker timer("MapBlock deSerialize");
856                 // 0ms
857                 
858                 block = sector->getBlockNoCreateNoEx(p.Y);
859                 if(block)
860                 {
861                         /*
862                                 Update an existing block
863                         */
864                         //infostream<<"Updating"<<std::endl;
865                         block->deSerialize(istr, ser_version);
866                 }
867                 else
868                 {
869                         /*
870                                 Create a new block
871                         */
872                         //infostream<<"Creating new"<<std::endl;
873                         block = new MapBlock(&m_env.getMap(), p);
874                         block->deSerialize(istr, ser_version);
875                         sector->insertBlock(block);
876
877                         //DEBUG
878                         /*NodeMod mod;
879                         mod.type = NODEMOD_CHANGECONTENT;
880                         mod.param = CONTENT_MESE;
881                         block->setTempMod(v3s16(8,10,8), mod);
882                         block->setTempMod(v3s16(8,9,8), mod);
883                         block->setTempMod(v3s16(8,8,8), mod);
884                         block->setTempMod(v3s16(8,7,8), mod);
885                         block->setTempMod(v3s16(8,6,8), mod);*/
886                 }
887
888 #if 0
889                 /*
890                         Acknowledge block
891                 */
892                 /*
893                         [0] u16 command
894                         [2] u8 count
895                         [3] v3s16 pos_0
896                         [3+6] v3s16 pos_1
897                         ...
898                 */
899                 u32 replysize = 2+1+6;
900                 SharedBuffer<u8> reply(replysize);
901                 writeU16(&reply[0], TOSERVER_GOTBLOCKS);
902                 reply[2] = 1;
903                 writeV3S16(&reply[3], p);
904                 // Send as reliable
905                 m_con.Send(PEER_ID_SERVER, 1, reply, true);
906 #endif
907
908                 /*
909                         Update Mesh of this block and blocks at x-, y- and z-.
910                         Environment should not be locked as it interlocks with the
911                         main thread, from which is will want to retrieve textures.
912                 */
913
914                 //m_env.getClientMap().updateMeshes(block->getPos(), getDayNightRatio());
915                 /*
916                         Add it to mesh update queue and set it to be acknowledged after update.
917                 */
918                 //infostream<<"Adding mesh update task for received block"<<std::endl;
919                 addUpdateMeshTaskWithEdge(p, true);
920         }
921         else if(command == TOCLIENT_PLAYERPOS)
922         {
923                 infostream<<"Received deprecated TOCLIENT_PLAYERPOS"
924                                 <<std::endl;
925                 /*u16 our_peer_id;
926                 {
927                         //JMutexAutoLock lock(m_con_mutex); //bulk comment-out
928                         our_peer_id = m_con.GetPeerID();
929                 }
930                 // Cancel if we don't have a peer id
931                 if(our_peer_id == PEER_ID_INEXISTENT){
932                         infostream<<"TOCLIENT_PLAYERPOS cancelled: "
933                                         "we have no peer id"
934                                         <<std::endl;
935                         return;
936                 }*/
937
938                 { //envlock
939                         //JMutexAutoLock envlock(m_env_mutex); //bulk comment-out
940                         
941                         u32 player_size = 2+12+12+4+4;
942                                 
943                         u32 player_count = (datasize-2) / player_size;
944                         u32 start = 2;
945                         for(u32 i=0; i<player_count; i++)
946                         {
947                                 u16 peer_id = readU16(&data[start]);
948
949                                 Player *player = m_env.getPlayer(peer_id);
950
951                                 // Skip if player doesn't exist
952                                 if(player == NULL)
953                                 {
954                                         start += player_size;
955                                         continue;
956                                 }
957
958                                 // Skip if player is local player
959                                 if(player->isLocal())
960                                 {
961                                         start += player_size;
962                                         continue;
963                                 }
964
965                                 v3s32 ps = readV3S32(&data[start+2]);
966                                 v3s32 ss = readV3S32(&data[start+2+12]);
967                                 s32 pitch_i = readS32(&data[start+2+12+12]);
968                                 s32 yaw_i = readS32(&data[start+2+12+12+4]);
969                                 /*infostream<<"Client: got "
970                                                 <<"pitch_i="<<pitch_i
971                                                 <<" yaw_i="<<yaw_i<<std::endl;*/
972                                 f32 pitch = (f32)pitch_i / 100.0;
973                                 f32 yaw = (f32)yaw_i / 100.0;
974                                 v3f position((f32)ps.X/100., (f32)ps.Y/100., (f32)ps.Z/100.);
975                                 v3f speed((f32)ss.X/100., (f32)ss.Y/100., (f32)ss.Z/100.);
976                                 player->setPosition(position);
977                                 player->setSpeed(speed);
978                                 player->setPitch(pitch);
979                                 player->setYaw(yaw);
980
981                                 /*infostream<<"Client: player "<<peer_id
982                                                 <<" pitch="<<pitch
983                                                 <<" yaw="<<yaw<<std::endl;*/
984
985                                 start += player_size;
986                         }
987                 } //envlock
988         }
989         else if(command == TOCLIENT_PLAYERINFO)
990         {
991                 u16 our_peer_id;
992                 {
993                         //JMutexAutoLock lock(m_con_mutex); //bulk comment-out
994                         our_peer_id = m_con.GetPeerID();
995                 }
996                 // Cancel if we don't have a peer id
997                 if(our_peer_id == PEER_ID_INEXISTENT){
998                         infostream<<"TOCLIENT_PLAYERINFO cancelled: "
999                                         "we have no peer id"
1000                                         <<std::endl;
1001                         return;
1002                 }
1003                 
1004                 //infostream<<"Client: Server reports players:"<<std::endl;
1005
1006                 { //envlock
1007                         //JMutexAutoLock envlock(m_env_mutex); //bulk comment-out
1008                         
1009                         u32 item_size = 2+PLAYERNAME_SIZE;
1010                         u32 player_count = (datasize-2) / item_size;
1011                         u32 start = 2;
1012                         // peer_ids
1013                         core::list<u16> players_alive;
1014                         for(u32 i=0; i<player_count; i++)
1015                         {
1016                                 // Make sure the name ends in '\0'
1017                                 data[start+2+20-1] = 0;
1018
1019                                 u16 peer_id = readU16(&data[start]);
1020
1021                                 players_alive.push_back(peer_id);
1022                                 
1023                                 /*infostream<<"peer_id="<<peer_id
1024                                                 <<" name="<<((char*)&data[start+2])<<std::endl;*/
1025
1026                                 // Don't update the info of the local player
1027                                 if(peer_id == our_peer_id)
1028                                 {
1029                                         start += item_size;
1030                                         continue;
1031                                 }
1032
1033                                 Player *player = m_env.getPlayer(peer_id);
1034
1035                                 // Create a player if it doesn't exist
1036                                 if(player == NULL)
1037                                 {
1038                                         player = new RemotePlayer(
1039                                                         m_device->getSceneManager()->getRootSceneNode(),
1040                                                         m_device,
1041                                                         -1);
1042                                         player->peer_id = peer_id;
1043                                         m_env.addPlayer(player);
1044                                         infostream<<"Client: Adding new player "
1045                                                         <<peer_id<<std::endl;
1046                                 }
1047                                 
1048                                 player->updateName((char*)&data[start+2]);
1049
1050                                 start += item_size;
1051                         }
1052                         
1053                         /*
1054                                 Remove those players from the environment that
1055                                 weren't listed by the server.
1056                         */
1057                         //infostream<<"Removing dead players"<<std::endl;
1058                         core::list<Player*> players = m_env.getPlayers();
1059                         core::list<Player*>::Iterator ip;
1060                         for(ip=players.begin(); ip!=players.end(); ip++)
1061                         {
1062                                 // Ingore local player
1063                                 if((*ip)->isLocal())
1064                                         continue;
1065                                 
1066                                 // Warn about a special case
1067                                 if((*ip)->peer_id == 0)
1068                                 {
1069                                         infostream<<"Client: Removing "
1070                                                         "dead player with id=0"<<std::endl;
1071                                 }
1072
1073                                 bool is_alive = false;
1074                                 core::list<u16>::Iterator i;
1075                                 for(i=players_alive.begin(); i!=players_alive.end(); i++)
1076                                 {
1077                                         if((*ip)->peer_id == *i)
1078                                         {
1079                                                 is_alive = true;
1080                                                 break;
1081                                         }
1082                                 }
1083                                 /*infostream<<"peer_id="<<((*ip)->peer_id)
1084                                                 <<" is_alive="<<is_alive<<std::endl;*/
1085                                 if(is_alive)
1086                                         continue;
1087                                 infostream<<"Removing dead player "<<(*ip)->peer_id
1088                                                 <<std::endl;
1089                                 m_env.removePlayer((*ip)->peer_id);
1090                         }
1091                 } //envlock
1092         }
1093         else if(command == TOCLIENT_SECTORMETA)
1094         {
1095                 infostream<<"Client received DEPRECATED TOCLIENT_SECTORMETA"<<std::endl;
1096 #if 0
1097                 /*
1098                         [0] u16 command
1099                         [2] u8 sector count
1100                         [3...] v2s16 pos + sector metadata
1101                 */
1102                 if(datasize < 3)
1103                         return;
1104
1105                 //infostream<<"Client received TOCLIENT_SECTORMETA"<<std::endl;
1106
1107                 { //envlock
1108                         //JMutexAutoLock envlock(m_env_mutex); //bulk comment-out
1109                         
1110                         std::string datastring((char*)&data[2], datasize-2);
1111                         std::istringstream is(datastring, std::ios_base::binary);
1112
1113                         u8 buf[4];
1114
1115                         is.read((char*)buf, 1);
1116                         u16 sector_count = readU8(buf);
1117                         
1118                         //infostream<<"sector_count="<<sector_count<<std::endl;
1119
1120                         for(u16 i=0; i<sector_count; i++)
1121                         {
1122                                 // Read position
1123                                 is.read((char*)buf, 4);
1124                                 v2s16 pos = readV2S16(buf);
1125                                 /*infostream<<"Client: deserializing sector at "
1126                                                 <<"("<<pos.X<<","<<pos.Y<<")"<<std::endl;*/
1127                                 // Create sector
1128                                 assert(m_env.getMap().mapType() == MAPTYPE_CLIENT);
1129                                 ((ClientMap&)m_env.getMap()).deSerializeSector(pos, is);
1130                         }
1131                 } //envlock
1132 #endif
1133         }
1134         else if(command == TOCLIENT_INVENTORY)
1135         {
1136                 if(datasize < 3)
1137                         return;
1138
1139                 //TimeTaker t1("Parsing TOCLIENT_INVENTORY", m_device);
1140
1141                 { //envlock
1142                         //TimeTaker t2("mutex locking", m_device);
1143                         //JMutexAutoLock envlock(m_env_mutex); //bulk comment-out
1144                         //t2.stop();
1145                         
1146                         //TimeTaker t3("istringstream init", m_device);
1147                         std::string datastring((char*)&data[2], datasize-2);
1148                         std::istringstream is(datastring, std::ios_base::binary);
1149                         //t3.stop();
1150                         
1151                         //m_env.printPlayers(infostream);
1152
1153                         //TimeTaker t4("player get", m_device);
1154                         Player *player = m_env.getLocalPlayer();
1155                         assert(player != NULL);
1156                         //t4.stop();
1157
1158                         //TimeTaker t1("inventory.deSerialize()", m_device);
1159                         player->inventory.deSerialize(is);
1160                         //t1.stop();
1161
1162                         m_inventory_updated = true;
1163
1164                         //infostream<<"Client got player inventory:"<<std::endl;
1165                         //player->inventory.print(infostream);
1166                 }
1167         }
1168         //DEBUG
1169         else if(command == TOCLIENT_OBJECTDATA)
1170         {
1171                 // Strip command word and create a stringstream
1172                 std::string datastring((char*)&data[2], datasize-2);
1173                 std::istringstream is(datastring, std::ios_base::binary);
1174                 
1175                 u8 buf[12];
1176
1177                 /*
1178                         Read players
1179                 */
1180
1181                 is.read((char*)buf, 2);
1182                 u16 playercount = readU16(buf);
1183                 
1184                 for(u16 i=0; i<playercount; i++)
1185                 {
1186                         is.read((char*)buf, 2);
1187                         u16 peer_id = readU16(buf);
1188                         is.read((char*)buf, 12);
1189                         v3s32 p_i = readV3S32(buf);
1190                         is.read((char*)buf, 12);
1191                         v3s32 s_i = readV3S32(buf);
1192                         is.read((char*)buf, 4);
1193                         s32 pitch_i = readS32(buf);
1194                         is.read((char*)buf, 4);
1195                         s32 yaw_i = readS32(buf);
1196                         
1197                         Player *player = m_env.getPlayer(peer_id);
1198
1199                         // Skip if player doesn't exist
1200                         if(player == NULL)
1201                         {
1202                                 continue;
1203                         }
1204
1205                         // Skip if player is local player
1206                         if(player->isLocal())
1207                         {
1208                                 continue;
1209                         }
1210         
1211                         f32 pitch = (f32)pitch_i / 100.0;
1212                         f32 yaw = (f32)yaw_i / 100.0;
1213                         v3f position((f32)p_i.X/100., (f32)p_i.Y/100., (f32)p_i.Z/100.);
1214                         v3f speed((f32)s_i.X/100., (f32)s_i.Y/100., (f32)s_i.Z/100.);
1215                         
1216                         player->setPosition(position);
1217                         player->setSpeed(speed);
1218                         player->setPitch(pitch);
1219                         player->setYaw(yaw);
1220                 }
1221
1222                 /*
1223                         Read block objects
1224                         NOTE: Deprecated stuff
1225                 */
1226
1227                 // Read active block count
1228                 u16 blockcount = readU16(is);
1229                 if(blockcount != 0){
1230                         infostream<<"TOCLIENT_OBJECTDATA: blockcount != 0 "
1231                                         "not supported"<<std::endl;
1232                         return;
1233                 }
1234         }
1235         else if(command == TOCLIENT_TIME_OF_DAY)
1236         {
1237                 if(datasize < 4)
1238                         return;
1239                 
1240                 u16 time_of_day = readU16(&data[2]);
1241                 time_of_day = time_of_day % 24000;
1242                 //infostream<<"Client: time_of_day="<<time_of_day<<std::endl;
1243                 
1244                 /*
1245                         time_of_day:
1246                         0 = midnight
1247                         12000 = midday
1248                 */
1249                 {
1250                         m_env.setTimeOfDay(time_of_day);
1251
1252                         u32 dr = m_env.getDayNightRatio();
1253
1254                         infostream<<"Client: time_of_day="<<time_of_day
1255                                         <<", dr="<<dr
1256                                         <<std::endl;
1257                 }
1258
1259         }
1260         else if(command == TOCLIENT_CHAT_MESSAGE)
1261         {
1262                 /*
1263                         u16 command
1264                         u16 length
1265                         wstring message
1266                 */
1267                 u8 buf[6];
1268                 std::string datastring((char*)&data[2], datasize-2);
1269                 std::istringstream is(datastring, std::ios_base::binary);
1270                 
1271                 // Read stuff
1272                 is.read((char*)buf, 2);
1273                 u16 len = readU16(buf);
1274                 
1275                 std::wstring message;
1276                 for(u16 i=0; i<len; i++)
1277                 {
1278                         is.read((char*)buf, 2);
1279                         message += (wchar_t)readU16(buf);
1280                 }
1281
1282                 /*infostream<<"Client received chat message: "
1283                                 <<wide_to_narrow(message)<<std::endl;*/
1284                 
1285                 m_chat_queue.push_back(message);
1286         }
1287         else if(command == TOCLIENT_ACTIVE_OBJECT_REMOVE_ADD)
1288         {
1289                 //if(g_settings->getBool("enable_experimental"))
1290                 {
1291                         /*
1292                                 u16 command
1293                                 u16 count of removed objects
1294                                 for all removed objects {
1295                                         u16 id
1296                                 }
1297                                 u16 count of added objects
1298                                 for all added objects {
1299                                         u16 id
1300                                         u8 type
1301                                         u32 initialization data length
1302                                         string initialization data
1303                                 }
1304                         */
1305
1306                         char buf[6];
1307                         // Get all data except the command number
1308                         std::string datastring((char*)&data[2], datasize-2);
1309                         // Throw them in an istringstream
1310                         std::istringstream is(datastring, std::ios_base::binary);
1311
1312                         // Read stuff
1313                         
1314                         // Read removed objects
1315                         is.read(buf, 2);
1316                         u16 removed_count = readU16((u8*)buf);
1317                         for(u16 i=0; i<removed_count; i++)
1318                         {
1319                                 is.read(buf, 2);
1320                                 u16 id = readU16((u8*)buf);
1321                                 // Remove it
1322                                 {
1323                                         //JMutexAutoLock envlock(m_env_mutex); //bulk comment-out
1324                                         m_env.removeActiveObject(id);
1325                                 }
1326                         }
1327                         
1328                         // Read added objects
1329                         is.read(buf, 2);
1330                         u16 added_count = readU16((u8*)buf);
1331                         for(u16 i=0; i<added_count; i++)
1332                         {
1333                                 is.read(buf, 2);
1334                                 u16 id = readU16((u8*)buf);
1335                                 is.read(buf, 1);
1336                                 u8 type = readU8((u8*)buf);
1337                                 std::string data = deSerializeLongString(is);
1338                                 // Add it
1339                                 {
1340                                         //JMutexAutoLock envlock(m_env_mutex); //bulk comment-out
1341                                         m_env.addActiveObject(id, type, data);
1342                                 }
1343                         }
1344                 }
1345         }
1346         else if(command == TOCLIENT_ACTIVE_OBJECT_MESSAGES)
1347         {
1348                 //if(g_settings->getBool("enable_experimental"))
1349                 {
1350                         /*
1351                                 u16 command
1352                                 for all objects
1353                                 {
1354                                         u16 id
1355                                         u16 message length
1356                                         string message
1357                                 }
1358                         */
1359                         char buf[6];
1360                         // Get all data except the command number
1361                         std::string datastring((char*)&data[2], datasize-2);
1362                         // Throw them in an istringstream
1363                         std::istringstream is(datastring, std::ios_base::binary);
1364                         
1365                         while(is.eof() == false)
1366                         {
1367                                 // Read stuff
1368                                 is.read(buf, 2);
1369                                 u16 id = readU16((u8*)buf);
1370                                 if(is.eof())
1371                                         break;
1372                                 is.read(buf, 2);
1373                                 u16 message_size = readU16((u8*)buf);
1374                                 std::string message;
1375                                 message.reserve(message_size);
1376                                 for(u16 i=0; i<message_size; i++)
1377                                 {
1378                                         is.read(buf, 1);
1379                                         message.append(buf, 1);
1380                                 }
1381                                 // Pass on to the environment
1382                                 {
1383                                         //JMutexAutoLock envlock(m_env_mutex); //bulk comment-out
1384                                         m_env.processActiveObjectMessage(id, message);
1385                                 }
1386                         }
1387                 }
1388         }
1389         else if(command == TOCLIENT_HP)
1390         {
1391                 std::string datastring((char*)&data[2], datasize-2);
1392                 std::istringstream is(datastring, std::ios_base::binary);
1393                 Player *player = m_env.getLocalPlayer();
1394                 assert(player != NULL);
1395                 u8 hp = readU8(is);
1396                 player->hp = hp;
1397         }
1398         else if(command == TOCLIENT_MOVE_PLAYER)
1399         {
1400                 std::string datastring((char*)&data[2], datasize-2);
1401                 std::istringstream is(datastring, std::ios_base::binary);
1402                 Player *player = m_env.getLocalPlayer();
1403                 assert(player != NULL);
1404                 v3f pos = readV3F1000(is);
1405                 f32 pitch = readF1000(is);
1406                 f32 yaw = readF1000(is);
1407                 player->setPosition(pos);
1408                 /*player->setPitch(pitch);
1409                 player->setYaw(yaw);*/
1410
1411                 infostream<<"Client got TOCLIENT_MOVE_PLAYER"
1412                                 <<" pos=("<<pos.X<<","<<pos.Y<<","<<pos.Z<<")"
1413                                 <<" pitch="<<pitch
1414                                 <<" yaw="<<yaw
1415                                 <<std::endl;
1416
1417                 /*
1418                         Add to ClientEvent queue.
1419                         This has to be sent to the main program because otherwise
1420                         it would just force the pitch and yaw values to whatever
1421                         the camera points to.
1422                 */
1423                 ClientEvent event;
1424                 event.type = CE_PLAYER_FORCE_MOVE;
1425                 event.player_force_move.pitch = pitch;
1426                 event.player_force_move.yaw = yaw;
1427                 m_client_event_queue.push_back(event);
1428
1429                 // Ignore damage for a few seconds, so that the player doesn't
1430                 // get damage from falling on ground
1431                 m_ignore_damage_timer = 3.0;
1432         }
1433         else if(command == TOCLIENT_PLAYERITEM)
1434         {
1435                 std::string datastring((char*)&data[2], datasize-2);
1436                 std::istringstream is(datastring, std::ios_base::binary);
1437
1438                 u16 count = readU16(is);
1439
1440                 for (u16 i = 0; i < count; ++i) {
1441                         u16 peer_id = readU16(is);
1442                         Player *player = m_env.getPlayer(peer_id);
1443
1444                         if (player == NULL)
1445                         {
1446                                 infostream<<"Client: ignoring player item "
1447                                         << deSerializeString(is)
1448                                         << " for non-existing peer id " << peer_id
1449                                         << std::endl;
1450                                 continue;
1451                         } else if (player->isLocal()) {
1452                                 infostream<<"Client: ignoring player item "
1453                                         << deSerializeString(is)
1454                                         << " for local player" << std::endl;
1455                                 continue;
1456                         } else {
1457                                 InventoryList *inv = player->inventory.getList("main");
1458                                 std::string itemstring(deSerializeString(is));
1459                                 if (itemstring.empty()) {
1460                                         inv->deleteItem(0);
1461                                         infostream
1462                                                 <<"Client: empty player item for peer "
1463                                                 << peer_id << std::endl;
1464                                 } else {
1465                                         std::istringstream iss(itemstring);
1466                                         delete inv->changeItem(0, InventoryItem::deSerialize(iss));
1467                                         infostream<<"Client: player item for peer " << peer_id << ": ";
1468                                         player->getWieldItem()->serialize(infostream);
1469                                         infostream<<std::endl;
1470                                 }
1471                         }
1472                 }
1473         }
1474         else if(command == TOCLIENT_DEATHSCREEN)
1475         {
1476                 std::string datastring((char*)&data[2], datasize-2);
1477                 std::istringstream is(datastring, std::ios_base::binary);
1478                 
1479                 bool set_camera_point_target = readU8(is);
1480                 v3f camera_point_target = readV3F1000(is);
1481                 
1482                 ClientEvent event;
1483                 event.type = CE_DEATHSCREEN;
1484                 event.deathscreen.set_camera_point_target = set_camera_point_target;
1485                 event.deathscreen.camera_point_target_x = camera_point_target.X;
1486                 event.deathscreen.camera_point_target_y = camera_point_target.Y;
1487                 event.deathscreen.camera_point_target_z = camera_point_target.Z;
1488                 m_client_event_queue.push_back(event);
1489         }
1490         else
1491         {
1492                 infostream<<"Client: Ignoring unknown command "
1493                                 <<command<<std::endl;
1494         }
1495 }
1496
1497 void Client::Send(u16 channelnum, SharedBuffer<u8> data, bool reliable)
1498 {
1499         //JMutexAutoLock lock(m_con_mutex); //bulk comment-out
1500         m_con.Send(PEER_ID_SERVER, channelnum, data, reliable);
1501 }
1502
1503 void Client::groundAction(u8 action, v3s16 nodepos_undersurface,
1504                 v3s16 nodepos_oversurface, u16 item)
1505 {
1506         if(connectedAndInitialized() == false){
1507                 infostream<<"Client::groundAction() "
1508                                 "cancelled (not connected)"
1509                                 <<std::endl;
1510                 return;
1511         }
1512         
1513         /*
1514                 length: 17
1515                 [0] u16 command
1516                 [2] u8 action
1517                 [3] v3s16 nodepos_undersurface
1518                 [9] v3s16 nodepos_abovesurface
1519                 [15] u16 item
1520                 actions:
1521                 0: start digging
1522                 1: place block
1523                 2: stop digging (all parameters ignored)
1524                 3: digging completed
1525         */
1526         u8 datasize = 2 + 1 + 6 + 6 + 2;
1527         SharedBuffer<u8> data(datasize);
1528         writeU16(&data[0], TOSERVER_GROUND_ACTION);
1529         writeU8(&data[2], action);
1530         writeV3S16(&data[3], nodepos_undersurface);
1531         writeV3S16(&data[9], nodepos_oversurface);
1532         writeU16(&data[15], item);
1533         Send(0, data, true);
1534 }
1535
1536 void Client::clickActiveObject(u8 button, u16 id, u16 item_i)
1537 {
1538         if(connectedAndInitialized() == false){
1539                 infostream<<"Client::clickActiveObject() "
1540                                 "cancelled (not connected)"
1541                                 <<std::endl;
1542                 return;
1543         }
1544
1545         Player *player = m_env.getLocalPlayer();
1546         if(player == NULL)
1547                 return;
1548
1549         ClientActiveObject *obj = m_env.getActiveObject(id);
1550         if(obj){
1551                 if(button == 0){
1552                         ToolItem *titem = NULL;
1553                         std::string toolname = "";
1554
1555                         InventoryList *mlist = player->inventory.getList("main");
1556                         if(mlist != NULL)
1557                         {
1558                                 InventoryItem *item = mlist->getItem(item_i);
1559                                 if(item && (std::string)item->getName() == "ToolItem")
1560                                 {
1561                                         titem = (ToolItem*)item;
1562                                         toolname = titem->getToolName();
1563                                 }
1564                         }
1565
1566                         v3f playerpos = player->getPosition();
1567                         v3f objpos = obj->getPosition();
1568                         v3f dir = (objpos - playerpos).normalize();
1569                         
1570                         bool disable_send = obj->directReportPunch(toolname, dir);
1571                         
1572                         if(disable_send)
1573                                 return;
1574                 }
1575         }
1576         
1577         /*
1578                 length: 7
1579                 [0] u16 command
1580                 [2] u8 button (0=left, 1=right)
1581                 [3] u16 id
1582                 [5] u16 item
1583         */
1584         u8 datasize = 2 + 1 + 6 + 2 + 2;
1585         SharedBuffer<u8> data(datasize);
1586         writeU16(&data[0], TOSERVER_CLICK_ACTIVEOBJECT);
1587         writeU8(&data[2], button);
1588         writeU16(&data[3], id);
1589         writeU16(&data[5], item_i);
1590         Send(0, data, true);
1591 }
1592
1593 void Client::sendSignNodeText(v3s16 p, std::string text)
1594 {
1595         /*
1596                 u16 command
1597                 v3s16 p
1598                 u16 textlen
1599                 textdata
1600         */
1601         std::ostringstream os(std::ios_base::binary);
1602         u8 buf[12];
1603         
1604         // Write command
1605         writeU16(buf, TOSERVER_SIGNNODETEXT);
1606         os.write((char*)buf, 2);
1607         
1608         // Write p
1609         writeV3S16(buf, p);
1610         os.write((char*)buf, 6);
1611
1612         u16 textlen = text.size();
1613         // Write text length
1614         writeS16(buf, textlen);
1615         os.write((char*)buf, 2);
1616
1617         // Write text
1618         os.write((char*)text.c_str(), textlen);
1619         
1620         // Make data buffer
1621         std::string s = os.str();
1622         SharedBuffer<u8> data((u8*)s.c_str(), s.size());
1623         // Send as reliable
1624         Send(0, data, true);
1625 }
1626         
1627 void Client::sendInventoryAction(InventoryAction *a)
1628 {
1629         std::ostringstream os(std::ios_base::binary);
1630         u8 buf[12];
1631         
1632         // Write command
1633         writeU16(buf, TOSERVER_INVENTORY_ACTION);
1634         os.write((char*)buf, 2);
1635
1636         a->serialize(os);
1637         
1638         // Make data buffer
1639         std::string s = os.str();
1640         SharedBuffer<u8> data((u8*)s.c_str(), s.size());
1641         // Send as reliable
1642         Send(0, data, true);
1643 }
1644
1645 void Client::sendChatMessage(const std::wstring &message)
1646 {
1647         std::ostringstream os(std::ios_base::binary);
1648         u8 buf[12];
1649         
1650         // Write command
1651         writeU16(buf, TOSERVER_CHAT_MESSAGE);
1652         os.write((char*)buf, 2);
1653         
1654         // Write length
1655         writeU16(buf, message.size());
1656         os.write((char*)buf, 2);
1657         
1658         // Write string
1659         for(u32 i=0; i<message.size(); i++)
1660         {
1661                 u16 w = message[i];
1662                 writeU16(buf, w);
1663                 os.write((char*)buf, 2);
1664         }
1665         
1666         // Make data buffer
1667         std::string s = os.str();
1668         SharedBuffer<u8> data((u8*)s.c_str(), s.size());
1669         // Send as reliable
1670         Send(0, data, true);
1671 }
1672
1673 void Client::sendChangePassword(const std::wstring oldpassword,
1674                 const std::wstring newpassword)
1675 {
1676         Player *player = m_env.getLocalPlayer();
1677         if(player == NULL)
1678                 return;
1679
1680         std::string playername = player->getName();
1681         std::string oldpwd = translatePassword(playername, oldpassword);
1682         std::string newpwd = translatePassword(playername, newpassword);
1683
1684         std::ostringstream os(std::ios_base::binary);
1685         u8 buf[2+PASSWORD_SIZE*2];
1686         /*
1687                 [0] u16 TOSERVER_PASSWORD
1688                 [2] u8[28] old password
1689                 [30] u8[28] new password
1690         */
1691
1692         writeU16(buf, TOSERVER_PASSWORD);
1693         for(u32 i=0;i<PASSWORD_SIZE-1;i++)
1694         {
1695                 buf[2+i] = i<oldpwd.length()?oldpwd[i]:0;
1696                 buf[30+i] = i<newpwd.length()?newpwd[i]:0;
1697         }
1698         buf[2+PASSWORD_SIZE-1] = 0;
1699         buf[30+PASSWORD_SIZE-1] = 0;
1700         os.write((char*)buf, 2+PASSWORD_SIZE*2);
1701
1702         // Make data buffer
1703         std::string s = os.str();
1704         SharedBuffer<u8> data((u8*)s.c_str(), s.size());
1705         // Send as reliable
1706         Send(0, data, true);
1707 }
1708
1709
1710 void Client::sendDamage(u8 damage)
1711 {
1712         DSTACK(__FUNCTION_NAME);
1713         std::ostringstream os(std::ios_base::binary);
1714
1715         writeU16(os, TOSERVER_DAMAGE);
1716         writeU8(os, damage);
1717
1718         // Make data buffer
1719         std::string s = os.str();
1720         SharedBuffer<u8> data((u8*)s.c_str(), s.size());
1721         // Send as reliable
1722         Send(0, data, true);
1723 }
1724
1725 void Client::sendRespawn()
1726 {
1727         DSTACK(__FUNCTION_NAME);
1728         std::ostringstream os(std::ios_base::binary);
1729
1730         writeU16(os, TOSERVER_RESPAWN);
1731
1732         // Make data buffer
1733         std::string s = os.str();
1734         SharedBuffer<u8> data((u8*)s.c_str(), s.size());
1735         // Send as reliable
1736         Send(0, data, true);
1737 }
1738
1739 void Client::sendPlayerPos()
1740 {
1741         //JMutexAutoLock envlock(m_env_mutex); //bulk comment-out
1742         
1743         Player *myplayer = m_env.getLocalPlayer();
1744         if(myplayer == NULL)
1745                 return;
1746         
1747         u16 our_peer_id;
1748         {
1749                 //JMutexAutoLock lock(m_con_mutex); //bulk comment-out
1750                 our_peer_id = m_con.GetPeerID();
1751         }
1752         
1753         // Set peer id if not set already
1754         if(myplayer->peer_id == PEER_ID_INEXISTENT)
1755                 myplayer->peer_id = our_peer_id;
1756         // Check that an existing peer_id is the same as the connection's
1757         assert(myplayer->peer_id == our_peer_id);
1758         
1759         v3f pf = myplayer->getPosition();
1760         v3s32 position(pf.X*100, pf.Y*100, pf.Z*100);
1761         v3f sf = myplayer->getSpeed();
1762         v3s32 speed(sf.X*100, sf.Y*100, sf.Z*100);
1763         s32 pitch = myplayer->getPitch() * 100;
1764         s32 yaw = myplayer->getYaw() * 100;
1765
1766         /*
1767                 Format:
1768                 [0] u16 command
1769                 [2] v3s32 position*100
1770                 [2+12] v3s32 speed*100
1771                 [2+12+12] s32 pitch*100
1772                 [2+12+12+4] s32 yaw*100
1773         */
1774
1775         SharedBuffer<u8> data(2+12+12+4+4);
1776         writeU16(&data[0], TOSERVER_PLAYERPOS);
1777         writeV3S32(&data[2], position);
1778         writeV3S32(&data[2+12], speed);
1779         writeS32(&data[2+12+12], pitch);
1780         writeS32(&data[2+12+12+4], yaw);
1781
1782         // Send as unreliable
1783         Send(0, data, false);
1784 }
1785
1786 void Client::sendPlayerItem(u16 item)
1787 {
1788         Player *myplayer = m_env.getLocalPlayer();
1789         if(myplayer == NULL)
1790                 return;
1791
1792         u16 our_peer_id = m_con.GetPeerID();
1793
1794         // Set peer id if not set already
1795         if(myplayer->peer_id == PEER_ID_INEXISTENT)
1796                 myplayer->peer_id = our_peer_id;
1797         // Check that an existing peer_id is the same as the connection's
1798         assert(myplayer->peer_id == our_peer_id);
1799
1800         SharedBuffer<u8> data(2+2);
1801         writeU16(&data[0], TOSERVER_PLAYERITEM);
1802         writeU16(&data[2], item);
1803
1804         // Send as reliable
1805         Send(0, data, true);
1806 }
1807
1808 void Client::removeNode(v3s16 p)
1809 {
1810         //JMutexAutoLock envlock(m_env_mutex); //bulk comment-out
1811         
1812         core::map<v3s16, MapBlock*> modified_blocks;
1813
1814         try
1815         {
1816                 //TimeTaker t("removeNodeAndUpdate", m_device);
1817                 m_env.getMap().removeNodeAndUpdate(p, modified_blocks);
1818         }
1819         catch(InvalidPositionException &e)
1820         {
1821         }
1822         
1823         for(core::map<v3s16, MapBlock * >::Iterator
1824                         i = modified_blocks.getIterator();
1825                         i.atEnd() == false; i++)
1826         {
1827                 v3s16 p = i.getNode()->getKey();
1828                 //m_env.getClientMap().updateMeshes(p, m_env.getDayNightRatio());
1829                 addUpdateMeshTaskWithEdge(p);
1830         }
1831 }
1832
1833 void Client::addNode(v3s16 p, MapNode n)
1834 {
1835         //JMutexAutoLock envlock(m_env_mutex); //bulk comment-out
1836
1837         TimeTaker timer1("Client::addNode()");
1838
1839         core::map<v3s16, MapBlock*> modified_blocks;
1840
1841         try
1842         {
1843                 //TimeTaker timer3("Client::addNode(): addNodeAndUpdate");
1844                 std::string st = std::string("");
1845                 m_env.getMap().addNodeAndUpdate(p, n, modified_blocks, st);
1846         }
1847         catch(InvalidPositionException &e)
1848         {}
1849         
1850         //TimeTaker timer2("Client::addNode(): updateMeshes");
1851
1852         for(core::map<v3s16, MapBlock * >::Iterator
1853                         i = modified_blocks.getIterator();
1854                         i.atEnd() == false; i++)
1855         {
1856                 v3s16 p = i.getNode()->getKey();
1857                 //m_env.getClientMap().updateMeshes(p, m_env.getDayNightRatio());
1858                 addUpdateMeshTaskWithEdge(p);
1859         }
1860 }
1861         
1862 void Client::updateCamera(v3f pos, v3f dir, f32 fov)
1863 {
1864         m_env.getClientMap().updateCamera(pos, dir, fov);
1865 }
1866
1867 void Client::renderPostFx()
1868 {
1869         m_env.getClientMap().renderPostFx();
1870 }
1871
1872 MapNode Client::getNode(v3s16 p)
1873 {
1874         //JMutexAutoLock envlock(m_env_mutex); //bulk comment-out
1875         return m_env.getMap().getNode(p);
1876 }
1877
1878 NodeMetadata* Client::getNodeMetadata(v3s16 p)
1879 {
1880         return m_env.getMap().getNodeMetadata(p);
1881 }
1882
1883 LocalPlayer* Client::getLocalPlayer()
1884 {
1885         return m_env.getLocalPlayer();
1886 }
1887
1888 void Client::setPlayerControl(PlayerControl &control)
1889 {
1890         //JMutexAutoLock envlock(m_env_mutex); //bulk comment-out
1891         LocalPlayer *player = m_env.getLocalPlayer();
1892         assert(player != NULL);
1893         player->control = control;
1894 }
1895
1896 void Client::selectPlayerItem(u16 item)
1897 {
1898         LocalPlayer *player = m_env.getLocalPlayer();
1899         assert(player != NULL);
1900
1901         player->wieldItem(item);
1902
1903         sendPlayerItem(item);
1904 }
1905
1906 // Returns true if the inventory of the local player has been
1907 // updated from the server. If it is true, it is set to false.
1908 bool Client::getLocalInventoryUpdated()
1909 {
1910         // m_inventory_updated is behind envlock
1911         //JMutexAutoLock envlock(m_env_mutex); //bulk comment-out
1912         bool updated = m_inventory_updated;
1913         m_inventory_updated = false;
1914         return updated;
1915 }
1916
1917 // Copies the inventory of the local player to parameter
1918 void Client::getLocalInventory(Inventory &dst)
1919 {
1920         //JMutexAutoLock envlock(m_env_mutex); //bulk comment-out
1921         Player *player = m_env.getLocalPlayer();
1922         assert(player != NULL);
1923         dst = player->inventory;
1924 }
1925
1926 InventoryContext *Client::getInventoryContext()
1927 {
1928         return &m_inventory_context;
1929 }
1930
1931 Inventory* Client::getInventory(InventoryContext *c, std::string id)
1932 {
1933         if(id == "current_player")
1934         {
1935                 assert(c->current_player);
1936                 return &(c->current_player->inventory);
1937         }
1938         
1939         Strfnd fn(id);
1940         std::string id0 = fn.next(":");
1941
1942         if(id0 == "nodemeta")
1943         {
1944                 v3s16 p;
1945                 p.X = stoi(fn.next(","));
1946                 p.Y = stoi(fn.next(","));
1947                 p.Z = stoi(fn.next(","));
1948                 NodeMetadata* meta = getNodeMetadata(p);
1949                 if(meta)
1950                         return meta->getInventory();
1951                 infostream<<"nodemeta at ("<<p.X<<","<<p.Y<<","<<p.Z<<"): "
1952                                 <<"no metadata found"<<std::endl;
1953                 return NULL;
1954         }
1955
1956         infostream<<__FUNCTION_NAME<<": unknown id "<<id<<std::endl;
1957         return NULL;
1958 }
1959 void Client::inventoryAction(InventoryAction *a)
1960 {
1961         sendInventoryAction(a);
1962 }
1963
1964 ClientActiveObject * Client::getSelectedActiveObject(
1965                 f32 max_d,
1966                 v3f from_pos_f_on_map,
1967                 core::line3d<f32> shootline_on_map
1968         )
1969 {
1970         core::array<DistanceSortedActiveObject> objects;
1971
1972         m_env.getActiveObjects(from_pos_f_on_map, max_d, objects);
1973
1974         //infostream<<"Collected "<<objects.size()<<" nearby objects"<<std::endl;
1975         
1976         // Sort them.
1977         // After this, the closest object is the first in the array.
1978         objects.sort();
1979
1980         for(u32 i=0; i<objects.size(); i++)
1981         {
1982                 ClientActiveObject *obj = objects[i].obj;
1983                 
1984                 core::aabbox3d<f32> *selection_box = obj->getSelectionBox();
1985                 if(selection_box == NULL)
1986                         continue;
1987
1988                 v3f pos = obj->getPosition();
1989
1990                 core::aabbox3d<f32> offsetted_box(
1991                                 selection_box->MinEdge + pos,
1992                                 selection_box->MaxEdge + pos
1993                 );
1994
1995                 if(offsetted_box.intersectsWithLine(shootline_on_map))
1996                 {
1997                         //infostream<<"Returning selected object"<<std::endl;
1998                         return obj;
1999                 }
2000         }
2001
2002         //infostream<<"No object selected; returning NULL."<<std::endl;
2003         return NULL;
2004 }
2005
2006 void Client::printDebugInfo(std::ostream &os)
2007 {
2008         //JMutexAutoLock lock1(m_fetchblock_mutex);
2009         /*JMutexAutoLock lock2(m_incoming_queue_mutex);
2010
2011         os<<"m_incoming_queue.getSize()="<<m_incoming_queue.getSize()
2012                 //<<", m_fetchblock_history.size()="<<m_fetchblock_history.size()
2013                 //<<", m_opt_not_found_history.size()="<<m_opt_not_found_history.size()
2014                 <<std::endl;*/
2015 }
2016         
2017 u32 Client::getDayNightRatio()
2018 {
2019         //JMutexAutoLock envlock(m_env_mutex); //bulk comment-out
2020         return m_env.getDayNightRatio();
2021 }
2022
2023 u16 Client::getHP()
2024 {
2025         Player *player = m_env.getLocalPlayer();
2026         assert(player != NULL);
2027         return player->hp;
2028 }
2029
2030 void Client::setTempMod(v3s16 p, NodeMod mod)
2031 {
2032         //JMutexAutoLock envlock(m_env_mutex); //bulk comment-out
2033         assert(m_env.getMap().mapType() == MAPTYPE_CLIENT);
2034
2035         core::map<v3s16, MapBlock*> affected_blocks;
2036         ((ClientMap&)m_env.getMap()).setTempMod(p, mod,
2037                         &affected_blocks);
2038
2039         for(core::map<v3s16, MapBlock*>::Iterator
2040                         i = affected_blocks.getIterator();
2041                         i.atEnd() == false; i++)
2042         {
2043                 i.getNode()->getValue()->updateMesh(m_env.getDayNightRatio());
2044         }
2045 }
2046
2047 void Client::clearTempMod(v3s16 p)
2048 {
2049         //JMutexAutoLock envlock(m_env_mutex); //bulk comment-out
2050         assert(m_env.getMap().mapType() == MAPTYPE_CLIENT);
2051
2052         core::map<v3s16, MapBlock*> affected_blocks;
2053         ((ClientMap&)m_env.getMap()).clearTempMod(p,
2054                         &affected_blocks);
2055
2056         for(core::map<v3s16, MapBlock*>::Iterator
2057                         i = affected_blocks.getIterator();
2058                         i.atEnd() == false; i++)
2059         {
2060                 i.getNode()->getValue()->updateMesh(m_env.getDayNightRatio());
2061         }
2062 }
2063
2064 void Client::addUpdateMeshTask(v3s16 p, bool ack_to_server)
2065 {
2066         /*infostream<<"Client::addUpdateMeshTask(): "
2067                         <<"("<<p.X<<","<<p.Y<<","<<p.Z<<")"
2068                         <<std::endl;*/
2069
2070         MapBlock *b = m_env.getMap().getBlockNoCreateNoEx(p);
2071         if(b == NULL)
2072                 return;
2073         
2074         /*
2075                 Create a task to update the mesh of the block
2076         */
2077         
2078         MeshMakeData *data = new MeshMakeData;
2079         
2080         {
2081                 //TimeTaker timer("data fill");
2082                 // Release: ~0ms
2083                 // Debug: 1-6ms, avg=2ms
2084                 data->fill(getDayNightRatio(), b);
2085         }
2086
2087         // Debug wait
2088         //while(m_mesh_update_thread.m_queue_in.size() > 0) sleep_ms(10);
2089         
2090         // Add task to queue
2091         m_mesh_update_thread.m_queue_in.addBlock(p, data, ack_to_server);
2092
2093         /*infostream<<"Mesh update input queue size is "
2094                         <<m_mesh_update_thread.m_queue_in.size()
2095                         <<std::endl;*/
2096         
2097 #if 0
2098         // Temporary test: make mesh directly in here
2099         {
2100                 //TimeTaker timer("make mesh");
2101                 // 10ms
2102                 scene::SMesh *mesh_new = NULL;
2103                 mesh_new = makeMapBlockMesh(data);
2104                 b->replaceMesh(mesh_new);
2105                 delete data;
2106         }
2107 #endif
2108
2109         /*
2110                 Mark mesh as non-expired at this point so that it can already
2111                 be marked as expired again if the data changes
2112         */
2113         b->setMeshExpired(false);
2114 }
2115
2116 void Client::addUpdateMeshTaskWithEdge(v3s16 blockpos, bool ack_to_server)
2117 {
2118         /*{
2119                 v3s16 p = blockpos;
2120                 infostream<<"Client::addUpdateMeshTaskWithEdge(): "
2121                                 <<"("<<p.X<<","<<p.Y<<","<<p.Z<<")"
2122                                 <<std::endl;
2123         }*/
2124
2125         try{
2126                 v3s16 p = blockpos + v3s16(0,0,0);
2127                 //MapBlock *b = m_env.getMap().getBlockNoCreate(p);
2128                 addUpdateMeshTask(p, ack_to_server);
2129         }
2130         catch(InvalidPositionException &e){}
2131         // Leading edge
2132         try{
2133                 v3s16 p = blockpos + v3s16(-1,0,0);
2134                 addUpdateMeshTask(p);
2135         }
2136         catch(InvalidPositionException &e){}
2137         try{
2138                 v3s16 p = blockpos + v3s16(0,-1,0);
2139                 addUpdateMeshTask(p);
2140         }
2141         catch(InvalidPositionException &e){}
2142         try{
2143                 v3s16 p = blockpos + v3s16(0,0,-1);
2144                 addUpdateMeshTask(p);
2145         }
2146         catch(InvalidPositionException &e){}
2147 }
2148
2149 ClientEvent Client::getClientEvent()
2150 {
2151         if(m_client_event_queue.size() == 0)
2152         {
2153                 ClientEvent event;
2154                 event.type = CE_NONE;
2155                 return event;
2156         }
2157         return m_client_event_queue.pop_front();
2158 }
2159
2160 float Client::getRTT(void)
2161 {
2162         try{
2163                 return m_con.GetPeerAvgRTT(PEER_ID_SERVER);
2164         } catch(con::PeerNotFoundException &e){
2165                 return 1337;
2166         }
2167 }
2168