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