]> git.lizzy.rs Git - minetest.git/blob - src/client.cpp
Pass arguments by reference
[minetest.git] / src / client.cpp
1 /*
2 Minetest
3 Copyright (C) 2013 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 Lesser General Public License as published by
7 the Free Software Foundation; either version 2.1 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 Lesser General Public License for more details.
14
15 You should have received a copy of the GNU Lesser 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 <iostream>
22 #include <algorithm>
23 #include "clientserver.h"
24 #include "jthread/jmutexautolock.h"
25 #include "main.h"
26 #include <sstream>
27 #include "filesys.h"
28 #include "porting.h"
29 #include "mapsector.h"
30 #include "mapblock_mesh.h"
31 #include "mapblock.h"
32 #include "settings.h"
33 #include "profiler.h"
34 #include "gettext.h"
35 #include "log.h"
36 #include "nodemetadata.h"
37 #include "nodedef.h"
38 #include "itemdef.h"
39 #include "shader.h"
40 #include <IFileSystem.h>
41 #include "base64.h"
42 #include "clientmap.h"
43 #include "clientmedia.h"
44 #include "sound.h"
45 #include "util/string.h"
46 #include "IMeshCache.h"
47 #include "serialization.h"
48 #include "util/serialize.h"
49 #include "config.h"
50 #include "util/directiontables.h"
51 #include "util/pointedthing.h"
52 #include "version.h"
53
54 /*
55         QueuedMeshUpdate
56 */
57
58 QueuedMeshUpdate::QueuedMeshUpdate():
59         p(-1337,-1337,-1337),
60         data(NULL),
61         ack_block_to_server(false)
62 {
63 }
64
65 QueuedMeshUpdate::~QueuedMeshUpdate()
66 {
67         if(data)
68                 delete data;
69 }
70
71 /*
72         MeshUpdateQueue
73 */
74         
75 MeshUpdateQueue::MeshUpdateQueue()
76 {
77 }
78
79 MeshUpdateQueue::~MeshUpdateQueue()
80 {
81         JMutexAutoLock lock(m_mutex);
82
83         for(std::vector<QueuedMeshUpdate*>::iterator
84                         i = m_queue.begin();
85                         i != m_queue.end(); i++)
86         {
87                 QueuedMeshUpdate *q = *i;
88                 delete q;
89         }
90 }
91
92 /*
93         peer_id=0 adds with nobody to send to
94 */
95 void MeshUpdateQueue::addBlock(v3s16 p, MeshMakeData *data, bool ack_block_to_server, bool urgent)
96 {
97         DSTACK(__FUNCTION_NAME);
98
99         assert(data);
100
101         JMutexAutoLock lock(m_mutex);
102
103         if(urgent)
104                 m_urgents.insert(p);
105
106         /*
107                 Find if block is already in queue.
108                 If it is, update the data and quit.
109         */
110         for(std::vector<QueuedMeshUpdate*>::iterator
111                         i = m_queue.begin();
112                         i != m_queue.end(); i++)
113         {
114                 QueuedMeshUpdate *q = *i;
115                 if(q->p == p)
116                 {
117                         if(q->data)
118                                 delete q->data;
119                         q->data = data;
120                         if(ack_block_to_server)
121                                 q->ack_block_to_server = true;
122                         return;
123                 }
124         }
125         
126         /*
127                 Add the block
128         */
129         QueuedMeshUpdate *q = new QueuedMeshUpdate;
130         q->p = p;
131         q->data = data;
132         q->ack_block_to_server = ack_block_to_server;
133         m_queue.push_back(q);
134 }
135
136 // Returned pointer must be deleted
137 // Returns NULL if queue is empty
138 QueuedMeshUpdate * MeshUpdateQueue::pop()
139 {
140         JMutexAutoLock lock(m_mutex);
141
142         bool must_be_urgent = !m_urgents.empty();
143         for(std::vector<QueuedMeshUpdate*>::iterator
144                         i = m_queue.begin();
145                         i != m_queue.end(); i++)
146         {
147                 QueuedMeshUpdate *q = *i;
148                 if(must_be_urgent && m_urgents.count(q->p) == 0)
149                         continue;
150                 m_queue.erase(i);
151                 m_urgents.erase(q->p);
152                 return q;
153         }
154         return NULL;
155 }
156
157 /*
158         MeshUpdateThread
159 */
160
161 void * MeshUpdateThread::Thread()
162 {
163         ThreadStarted();
164
165         log_register_thread("MeshUpdateThread");
166
167         DSTACK(__FUNCTION_NAME);
168         
169         BEGIN_DEBUG_EXCEPTION_HANDLER
170
171         while(!StopRequested())
172         {
173                 QueuedMeshUpdate *q = m_queue_in.pop();
174                 if(q == NULL)
175                 {
176                         sleep_ms(3);
177                         continue;
178                 }
179
180                 ScopeProfiler sp(g_profiler, "Client: Mesh making");
181
182                 MapBlockMesh *mesh_new = new MapBlockMesh(q->data, m_camera_offset);
183                 if(mesh_new->getMesh()->getMeshBufferCount() == 0)
184                 {
185                         delete mesh_new;
186                         mesh_new = NULL;
187                 }
188
189                 MeshUpdateResult r;
190                 r.p = q->p;
191                 r.mesh = mesh_new;
192                 r.ack_block_to_server = q->ack_block_to_server;
193
194                 m_queue_out.push_back(r);
195
196                 delete q;
197         }
198
199         END_DEBUG_EXCEPTION_HANDLER(errorstream)
200
201         return NULL;
202 }
203
204 /*
205         Client
206 */
207
208 Client::Client(
209                 IrrlichtDevice *device,
210                 const char *playername,
211                 std::string password,
212                 MapDrawControl &control,
213                 IWritableTextureSource *tsrc,
214                 IWritableShaderSource *shsrc,
215                 IWritableItemDefManager *itemdef,
216                 IWritableNodeDefManager *nodedef,
217                 ISoundManager *sound,
218                 MtEventManager *event,
219                 bool ipv6
220 ):
221         m_tsrc(tsrc),
222         m_shsrc(shsrc),
223         m_itemdef(itemdef),
224         m_nodedef(nodedef),
225         m_sound(sound),
226         m_event(event),
227         m_mesh_update_thread(this),
228         m_env(
229                 new ClientMap(this, this, control,
230                         device->getSceneManager()->getRootSceneNode(),
231                         device->getSceneManager(), 666),
232                 device->getSceneManager(),
233                 tsrc, this, device
234         ),
235         m_con(PROTOCOL_ID, 512, CONNECTION_TIMEOUT, ipv6, this),
236         m_device(device),
237         m_server_ser_ver(SER_FMT_VER_INVALID),
238         m_playeritem(0),
239         m_inventory_updated(false),
240         m_inventory_from_server(NULL),
241         m_inventory_from_server_age(0.0),
242         m_animation_time(0),
243         m_crack_level(-1),
244         m_crack_pos(0,0,0),
245         m_map_seed(0),
246         m_password(password),
247         m_access_denied(false),
248         m_itemdef_received(false),
249         m_nodedef_received(false),
250         m_media_downloader(new ClientMediaDownloader()),
251         m_time_of_day_set(false),
252         m_last_time_of_day_f(-1),
253         m_time_of_day_update_timer(0),
254         m_recommended_send_interval(0.1),
255         m_removed_sounds_check_timer(0)
256 {
257         m_packetcounter_timer = 0.0;
258         //m_delete_unused_sectors_timer = 0.0;
259         m_connection_reinit_timer = 0.0;
260         m_avg_rtt_timer = 0.0;
261         m_playerpos_send_timer = 0.0;
262         m_ignore_damage_timer = 0.0;
263
264         /*
265                 Add local player
266         */
267         {
268                 Player *player = new LocalPlayer(this);
269
270                 player->updateName(playername);
271
272                 m_env.addPlayer(player);
273         }
274 }
275
276 void Client::Stop()
277 {
278         //request all client managed threads to stop
279         m_mesh_update_thread.Stop();
280 }
281
282 bool Client::isShutdown()
283 {
284
285         if (!m_mesh_update_thread.IsRunning()) return true;
286
287         return false;
288 }
289
290 Client::~Client()
291 {
292         m_con.Disconnect();
293
294         m_mesh_update_thread.Stop();
295         m_mesh_update_thread.Wait();
296         while(!m_mesh_update_thread.m_queue_out.empty()) {
297                 MeshUpdateResult r = m_mesh_update_thread.m_queue_out.pop_frontNoEx();
298                 delete r.mesh;
299         }
300
301
302         delete m_inventory_from_server;
303
304         // Delete detached inventories
305         for(std::map<std::string, Inventory*>::iterator
306                         i = m_detached_inventories.begin();
307                         i != m_detached_inventories.end(); i++){
308                 delete i->second;
309         }
310
311         // cleanup 3d model meshes on client shutdown
312         while (m_device->getSceneManager()->getMeshCache()->getMeshCount() != 0) {
313                 scene::IAnimatedMesh * mesh =
314                         m_device->getSceneManager()->getMeshCache()->getMeshByIndex(0);
315
316                 if (mesh != NULL)
317                         m_device->getSceneManager()->getMeshCache()->removeMesh(mesh);
318         }
319 }
320
321 void Client::connect(Address address)
322 {
323         DSTACK(__FUNCTION_NAME);
324         m_con.SetTimeoutMs(0);
325         m_con.Connect(address);
326 }
327
328 bool Client::connectedAndInitialized()
329 {
330         if(m_con.Connected() == false)
331                 return false;
332         
333         if(m_server_ser_ver == SER_FMT_VER_INVALID)
334                 return false;
335         
336         return true;
337 }
338
339 void Client::step(float dtime)
340 {
341         DSTACK(__FUNCTION_NAME);
342         
343         // Limit a bit
344         if(dtime > 2.0)
345                 dtime = 2.0;
346         
347         if(m_ignore_damage_timer > dtime)
348                 m_ignore_damage_timer -= dtime;
349         else
350                 m_ignore_damage_timer = 0.0;
351         
352         m_animation_time += dtime;
353         if(m_animation_time > 60.0)
354                 m_animation_time -= 60.0;
355
356         m_time_of_day_update_timer += dtime;
357
358         ReceiveAll();
359
360         /*
361                 Packet counter
362         */
363         {
364                 float &counter = m_packetcounter_timer;
365                 counter -= dtime;
366                 if(counter <= 0.0)
367                 {
368                         counter = 20.0;
369                         
370                         infostream<<"Client packetcounter (20s):"<<std::endl;
371                         m_packetcounter.print(infostream);
372                         m_packetcounter.clear();
373                 }
374         }
375         
376         // Get connection status
377         bool connected = connectedAndInitialized();
378
379 #if 0
380         {
381                 /*
382                         Delete unused sectors
383
384                         NOTE: This jams the game for a while because deleting sectors
385                               clear caches
386                 */
387                 
388                 float &counter = m_delete_unused_sectors_timer;
389                 counter -= dtime;
390                 if(counter <= 0.0)
391                 {
392                         // 3 minute interval
393                         //counter = 180.0;
394                         counter = 60.0;
395
396                         //JMutexAutoLock lock(m_env_mutex); //bulk comment-out
397
398                         core::list<v3s16> deleted_blocks;
399
400                         float delete_unused_sectors_timeout =
401                                 g_settings->getFloat("client_delete_unused_sectors_timeout");
402         
403                         // Delete sector blocks
404                         /*u32 num = m_env.getMap().unloadUnusedData
405                                         (delete_unused_sectors_timeout,
406                                         true, &deleted_blocks);*/
407                         
408                         // Delete whole sectors
409                         m_env.getMap().unloadUnusedData
410                                         (delete_unused_sectors_timeout,
411                                         &deleted_blocks);
412
413                         if(deleted_blocks.size() > 0)
414                         {
415                                 /*infostream<<"Client: Deleted blocks of "<<num
416                                                 <<" unused sectors"<<std::endl;*/
417                                 /*infostream<<"Client: Deleted "<<num
418                                                 <<" unused sectors"<<std::endl;*/
419                                 
420                                 /*
421                                         Send info to server
422                                 */
423
424                                 // Env is locked so con can be locked.
425                                 //JMutexAutoLock lock(m_con_mutex); //bulk comment-out
426                                 
427                                 core::list<v3s16>::Iterator i = deleted_blocks.begin();
428                                 core::list<v3s16> sendlist;
429                                 for(;;)
430                                 {
431                                         if(sendlist.size() == 255 || i == deleted_blocks.end())
432                                         {
433                                                 if(sendlist.size() == 0)
434                                                         break;
435                                                 /*
436                                                         [0] u16 command
437                                                         [2] u8 count
438                                                         [3] v3s16 pos_0
439                                                         [3+6] v3s16 pos_1
440                                                         ...
441                                                 */
442                                                 u32 replysize = 2+1+6*sendlist.size();
443                                                 SharedBuffer<u8> reply(replysize);
444                                                 writeU16(&reply[0], TOSERVER_DELETEDBLOCKS);
445                                                 reply[2] = sendlist.size();
446                                                 u32 k = 0;
447                                                 for(core::list<v3s16>::Iterator
448                                                                 j = sendlist.begin();
449                                                                 j != sendlist.end(); j++)
450                                                 {
451                                                         writeV3S16(&reply[2+1+6*k], *j);
452                                                         k++;
453                                                 }
454                                                 m_con.Send(PEER_ID_SERVER, 1, reply, true);
455
456                                                 if(i == deleted_blocks.end())
457                                                         break;
458
459                                                 sendlist.clear();
460                                         }
461
462                                         sendlist.push_back(*i);
463                                         i++;
464                                 }
465                         }
466                 }
467         }
468 #endif
469
470         if(connected == false)
471         {
472                 float &counter = m_connection_reinit_timer;
473                 counter -= dtime;
474                 if(counter <= 0.0)
475                 {
476                         counter = 2.0;
477
478                         //JMutexAutoLock envlock(m_env_mutex); //bulk comment-out
479                         
480                         Player *myplayer = m_env.getLocalPlayer();
481                         assert(myplayer != NULL);
482         
483                         // Send TOSERVER_INIT
484                         // [0] u16 TOSERVER_INIT
485                         // [2] u8 SER_FMT_VER_HIGHEST_READ
486                         // [3] u8[20] player_name
487                         // [23] u8[28] password (new in some version)
488                         // [51] u16 minimum supported network protocol version (added sometime)
489                         // [53] u16 maximum supported network protocol version (added later than the previous one)
490                         SharedBuffer<u8> data(2+1+PLAYERNAME_SIZE+PASSWORD_SIZE+2+2);
491                         writeU16(&data[0], TOSERVER_INIT);
492                         writeU8(&data[2], SER_FMT_VER_HIGHEST_READ);
493
494                         memset((char*)&data[3], 0, PLAYERNAME_SIZE);
495                         snprintf((char*)&data[3], PLAYERNAME_SIZE, "%s", myplayer->getName());
496
497                         /*infostream<<"Client: sending initial password hash: \""<<m_password<<"\""
498                                         <<std::endl;*/
499
500                         memset((char*)&data[23], 0, PASSWORD_SIZE);
501                         snprintf((char*)&data[23], PASSWORD_SIZE, "%s", m_password.c_str());
502                         
503                         writeU16(&data[51], CLIENT_PROTOCOL_VERSION_MIN);
504                         writeU16(&data[53], CLIENT_PROTOCOL_VERSION_MAX);
505
506                         // Send as unreliable
507                         Send(1, data, false);
508                 }
509
510                 // Not connected, return
511                 return;
512         }
513
514         /*
515                 Do stuff if connected
516         */
517         
518         /*
519                 Run Map's timers and unload unused data
520         */
521         const float map_timer_and_unload_dtime = 5.25;
522         if(m_map_timer_and_unload_interval.step(dtime, map_timer_and_unload_dtime))
523         {
524                 ScopeProfiler sp(g_profiler, "Client: map timer and unload");
525                 std::list<v3s16> deleted_blocks;
526                 m_env.getMap().timerUpdate(map_timer_and_unload_dtime,
527                                 g_settings->getFloat("client_unload_unused_data_timeout"),
528                                 &deleted_blocks);
529                                 
530                 /*if(deleted_blocks.size() > 0)
531                         infostream<<"Client: Unloaded "<<deleted_blocks.size()
532                                         <<" unused blocks"<<std::endl;*/
533                         
534                 /*
535                         Send info to server
536                         NOTE: This loop is intentionally iterated the way it is.
537                 */
538
539                 std::list<v3s16>::iterator i = deleted_blocks.begin();
540                 std::list<v3s16> sendlist;
541                 for(;;)
542                 {
543                         if(sendlist.size() == 255 || i == deleted_blocks.end())
544                         {
545                                 if(sendlist.size() == 0)
546                                         break;
547                                 /*
548                                         [0] u16 command
549                                         [2] u8 count
550                                         [3] v3s16 pos_0
551                                         [3+6] v3s16 pos_1
552                                         ...
553                                 */
554                                 u32 replysize = 2+1+6*sendlist.size();
555                                 SharedBuffer<u8> reply(replysize);
556                                 writeU16(&reply[0], TOSERVER_DELETEDBLOCKS);
557                                 reply[2] = sendlist.size();
558                                 u32 k = 0;
559                                 for(std::list<v3s16>::iterator
560                                                 j = sendlist.begin();
561                                                 j != sendlist.end(); ++j)
562                                 {
563                                         writeV3S16(&reply[2+1+6*k], *j);
564                                         k++;
565                                 }
566                                 m_con.Send(PEER_ID_SERVER, 2, reply, true);
567
568                                 if(i == deleted_blocks.end())
569                                         break;
570
571                                 sendlist.clear();
572                         }
573
574                         sendlist.push_back(*i);
575                         ++i;
576                 }
577         }
578
579         /*
580                 Handle environment
581         */
582         {
583                 // Control local player (0ms)
584                 LocalPlayer *player = m_env.getLocalPlayer();
585                 assert(player != NULL);
586                 player->applyControl(dtime);
587
588                 // Step environment
589                 m_env.step(dtime);
590                 
591                 /*
592                         Get events
593                 */
594                 for(;;)
595                 {
596                         ClientEnvEvent event = m_env.getClientEvent();
597                         if(event.type == CEE_NONE)
598                         {
599                                 break;
600                         }
601                         else if(event.type == CEE_PLAYER_DAMAGE)
602                         {
603                                 if(m_ignore_damage_timer <= 0)
604                                 {
605                                         u8 damage = event.player_damage.amount;
606                                         
607                                         if(event.player_damage.send_to_server)
608                                                 sendDamage(damage);
609
610                                         // Add to ClientEvent queue
611                                         ClientEvent event;
612                                         event.type = CE_PLAYER_DAMAGE;
613                                         event.player_damage.amount = damage;
614                                         m_client_event_queue.push_back(event);
615                                 }
616                         }
617                         else if(event.type == CEE_PLAYER_BREATH)
618                         {
619                                         u16 breath = event.player_breath.amount;
620                                         sendBreath(breath);
621                         }
622                 }
623         }
624
625         /*
626                 Print some info
627         */
628         {
629                 float &counter = m_avg_rtt_timer;
630                 counter += dtime;
631                 if(counter >= 10)
632                 {
633                         counter = 0.0;
634                         // connectedAndInitialized() is true, peer exists.
635                         float avg_rtt = m_con.GetPeerAvgRTT(PEER_ID_SERVER);
636                         infostream<<"Client: avg_rtt="<<avg_rtt<<std::endl;
637                 }
638         }
639
640         /*
641                 Send player position to server
642         */
643         {
644                 float &counter = m_playerpos_send_timer;
645                 counter += dtime;
646                 if(counter >= m_recommended_send_interval)
647                 {
648                         counter = 0.0;
649                         sendPlayerPos();
650                 }
651         }
652
653         /*
654                 Replace updated meshes
655         */
656         {
657                 int num_processed_meshes = 0;
658                 while(!m_mesh_update_thread.m_queue_out.empty())
659                 {
660                         num_processed_meshes++;
661                         MeshUpdateResult r = m_mesh_update_thread.m_queue_out.pop_frontNoEx();
662                         MapBlock *block = m_env.getMap().getBlockNoCreateNoEx(r.p);
663                         if(block)
664                         {
665                                 // Delete the old mesh
666                                 if(block->mesh != NULL)
667                                 {
668                                         // TODO: Remove hardware buffers of meshbuffers of block->mesh
669                                         delete block->mesh;
670                                         block->mesh = NULL;
671                                 }
672
673                                 // Replace with the new mesh
674                                 block->mesh = r.mesh;
675                         } else {
676                                 delete r.mesh;
677                         }
678                         if(r.ack_block_to_server)
679                         {
680                                 /*
681                                         Acknowledge block
682                                 */
683                                 /*
684                                         [0] u16 command
685                                         [2] u8 count
686                                         [3] v3s16 pos_0
687                                         [3+6] v3s16 pos_1
688                                         ...
689                                 */
690                                 u32 replysize = 2+1+6;
691                                 SharedBuffer<u8> reply(replysize);
692                                 writeU16(&reply[0], TOSERVER_GOTBLOCKS);
693                                 reply[2] = 1;
694                                 writeV3S16(&reply[3], r.p);
695                                 // Send as reliable
696                                 m_con.Send(PEER_ID_SERVER, 2, reply, true);
697                         }
698                 }
699                 if(num_processed_meshes > 0)
700                         g_profiler->graphAdd("num_processed_meshes", num_processed_meshes);
701         }
702
703         /*
704                 Load fetched media
705         */
706         if (m_media_downloader && m_media_downloader->isStarted()) {
707                 m_media_downloader->step(this);
708                 if (m_media_downloader->isDone()) {
709                         received_media();
710                         delete m_media_downloader;
711                         m_media_downloader = NULL;
712                 }
713         }
714
715         /*
716                 If the server didn't update the inventory in a while, revert
717                 the local inventory (so the player notices the lag problem
718                 and knows something is wrong).
719         */
720         if(m_inventory_from_server)
721         {
722                 float interval = 10.0;
723                 float count_before = floor(m_inventory_from_server_age / interval);
724
725                 m_inventory_from_server_age += dtime;
726
727                 float count_after = floor(m_inventory_from_server_age / interval);
728
729                 if(count_after != count_before)
730                 {
731                         // Do this every <interval> seconds after TOCLIENT_INVENTORY
732                         // Reset the locally changed inventory to the authoritative inventory
733                         Player *player = m_env.getLocalPlayer();
734                         player->inventory = *m_inventory_from_server;
735                         m_inventory_updated = true;
736                 }
737         }
738
739         /*
740                 Update positions of sounds attached to objects
741         */
742         {
743                 for(std::map<int, u16>::iterator
744                                 i = m_sounds_to_objects.begin();
745                                 i != m_sounds_to_objects.end(); i++)
746                 {
747                         int client_id = i->first;
748                         u16 object_id = i->second;
749                         ClientActiveObject *cao = m_env.getActiveObject(object_id);
750                         if(!cao)
751                                 continue;
752                         v3f pos = cao->getPosition();
753                         m_sound->updateSoundPosition(client_id, pos);
754                 }
755         }
756         
757         /*
758                 Handle removed remotely initiated sounds
759         */
760         m_removed_sounds_check_timer += dtime;
761         if(m_removed_sounds_check_timer >= 2.32)
762         {
763                 m_removed_sounds_check_timer = 0;
764                 // Find removed sounds and clear references to them
765                 std::set<s32> removed_server_ids;
766                 for(std::map<s32, int>::iterator
767                                 i = m_sounds_server_to_client.begin();
768                                 i != m_sounds_server_to_client.end();)
769                 {
770                         s32 server_id = i->first;
771                         int client_id = i->second;
772                         i++;
773                         if(!m_sound->soundExists(client_id)){
774                                 m_sounds_server_to_client.erase(server_id);
775                                 m_sounds_client_to_server.erase(client_id);
776                                 m_sounds_to_objects.erase(client_id);
777                                 removed_server_ids.insert(server_id);
778                         }
779                 }
780                 // Sync to server
781                 if(removed_server_ids.size() != 0)
782                 {
783                         std::ostringstream os(std::ios_base::binary);
784                         writeU16(os, TOSERVER_REMOVED_SOUNDS);
785                         size_t server_ids = removed_server_ids.size();
786                         assert(server_ids <= 0xFFFF);
787                         writeU16(os, (u16) (server_ids & 0xFFFF));
788                         for(std::set<s32>::iterator i = removed_server_ids.begin();
789                                         i != removed_server_ids.end(); i++)
790                                 writeS32(os, *i);
791                         std::string s = os.str();
792                         SharedBuffer<u8> data((u8*)s.c_str(), s.size());
793                         // Send as reliable
794                         Send(1, data, true);
795                 }
796         }
797 }
798
799 bool Client::loadMedia(const std::string &data, const std::string &filename)
800 {
801         // Silly irrlicht's const-incorrectness
802         Buffer<char> data_rw(data.c_str(), data.size());
803         
804         std::string name;
805
806         const char *image_ext[] = {
807                 ".png", ".jpg", ".bmp", ".tga",
808                 ".pcx", ".ppm", ".psd", ".wal", ".rgb",
809                 NULL
810         };
811         name = removeStringEnd(filename, image_ext);
812         if(name != "")
813         {
814                 verbosestream<<"Client: Attempting to load image "
815                 <<"file \""<<filename<<"\""<<std::endl;
816
817                 io::IFileSystem *irrfs = m_device->getFileSystem();
818                 video::IVideoDriver *vdrv = m_device->getVideoDriver();
819
820                 // Create an irrlicht memory file
821                 io::IReadFile *rfile = irrfs->createMemoryReadFile(
822                                 *data_rw, data_rw.getSize(), "_tempreadfile");
823                 assert(rfile);
824                 // Read image
825                 video::IImage *img = vdrv->createImageFromFile(rfile);
826                 if(!img){
827                         errorstream<<"Client: Cannot create image from data of "
828                                         <<"file \""<<filename<<"\""<<std::endl;
829                         rfile->drop();
830                         return false;
831                 }
832                 else {
833                         m_tsrc->insertSourceImage(filename, img);
834                         img->drop();
835                         rfile->drop();
836                         return true;
837                 }
838         }
839
840         const char *sound_ext[] = {
841                 ".0.ogg", ".1.ogg", ".2.ogg", ".3.ogg", ".4.ogg",
842                 ".5.ogg", ".6.ogg", ".7.ogg", ".8.ogg", ".9.ogg",
843                 ".ogg", NULL
844         };
845         name = removeStringEnd(filename, sound_ext);
846         if(name != "")
847         {
848                 verbosestream<<"Client: Attempting to load sound "
849                 <<"file \""<<filename<<"\""<<std::endl;
850                 m_sound->loadSoundData(name, data);
851                 return true;
852         }
853
854         const char *model_ext[] = {
855                 ".x", ".b3d", ".md2", ".obj",
856                 NULL
857         };
858         name = removeStringEnd(filename, model_ext);
859         if(name != "")
860         {
861                 verbosestream<<"Client: Storing model into memory: "
862                                 <<"\""<<filename<<"\""<<std::endl;
863                 if(m_mesh_data.count(filename))
864                         errorstream<<"Multiple models with name \""<<filename.c_str()
865                                         <<"\" found; replacing previous model"<<std::endl;
866                 m_mesh_data[filename] = data;
867                 return true;
868         }
869
870         errorstream<<"Client: Don't know how to load file \""
871                         <<filename<<"\""<<std::endl;
872         return false;
873 }
874
875 // Virtual methods from con::PeerHandler
876 void Client::peerAdded(con::Peer *peer)
877 {
878         infostream<<"Client::peerAdded(): peer->id="
879                         <<peer->id<<std::endl;
880 }
881 void Client::deletingPeer(con::Peer *peer, bool timeout)
882 {
883         infostream<<"Client::deletingPeer(): "
884                         "Server Peer is getting deleted "
885                         <<"(timeout="<<timeout<<")"<<std::endl;
886 }
887
888 /*
889         u16 command
890         u16 number of files requested
891         for each file {
892                 u16 length of name
893                 string name
894         }
895 */
896 void Client::request_media(const std::list<std::string> &file_requests)
897 {
898         std::ostringstream os(std::ios_base::binary);
899         writeU16(os, TOSERVER_REQUEST_MEDIA);
900         size_t file_requests_size = file_requests.size();
901         assert(file_requests_size <= 0xFFFF);
902         writeU16(os, (u16) (file_requests_size & 0xFFFF));
903
904         for(std::list<std::string>::const_iterator i = file_requests.begin();
905                         i != file_requests.end(); ++i) {
906                 os<<serializeString(*i);
907         }
908
909         // Make data buffer
910         std::string s = os.str();
911         SharedBuffer<u8> data((u8*)s.c_str(), s.size());
912         // Send as reliable
913         Send(1, data, true);
914         infostream<<"Client: Sending media request list to server ("
915                         <<file_requests.size()<<" files)"<<std::endl;
916 }
917
918 void Client::received_media()
919 {
920         // notify server we received everything
921         std::ostringstream os(std::ios_base::binary);
922         writeU16(os, TOSERVER_RECEIVED_MEDIA);
923         std::string s = os.str();
924         SharedBuffer<u8> data((u8*)s.c_str(), s.size());
925         // Send as reliable
926         Send(1, data, true);
927         infostream<<"Client: Notifying server that we received all media"
928                         <<std::endl;
929 }
930
931 void Client::ReceiveAll()
932 {
933         DSTACK(__FUNCTION_NAME);
934         u32 start_ms = porting::getTimeMs();
935         for(;;)
936         {
937                 // Limit time even if there would be huge amounts of data to
938                 // process
939                 if(porting::getTimeMs() > start_ms + 100)
940                         break;
941                 
942                 try{
943                         Receive();
944                         g_profiler->graphAdd("client_received_packets", 1);
945                 }
946                 catch(con::NoIncomingDataException &e)
947                 {
948                         break;
949                 }
950                 catch(con::InvalidIncomingDataException &e)
951                 {
952                         infostream<<"Client::ReceiveAll(): "
953                                         "InvalidIncomingDataException: what()="
954                                         <<e.what()<<std::endl;
955                 }
956         }
957 }
958
959 void Client::Receive()
960 {
961         DSTACK(__FUNCTION_NAME);
962         SharedBuffer<u8> data;
963         u16 sender_peer_id;
964         u32 datasize = m_con.Receive(sender_peer_id, data);
965         ProcessData(*data, datasize, sender_peer_id);
966 }
967
968 /*
969         sender_peer_id given to this shall be quaranteed to be a valid peer
970 */
971 void Client::ProcessData(u8 *data, u32 datasize, u16 sender_peer_id)
972 {
973         DSTACK(__FUNCTION_NAME);
974
975         // Ignore packets that don't even fit a command
976         if(datasize < 2)
977         {
978                 m_packetcounter.add(60000);
979                 return;
980         }
981
982         ToClientCommand command = (ToClientCommand)readU16(&data[0]);
983
984         //infostream<<"Client: received command="<<command<<std::endl;
985         m_packetcounter.add((u16)command);
986         
987         /*
988                 If this check is removed, be sure to change the queue
989                 system to know the ids
990         */
991         if(sender_peer_id != PEER_ID_SERVER)
992         {
993                 infostream<<"Client::ProcessData(): Discarding data not "
994                                 "coming from server: peer_id="<<sender_peer_id
995                                 <<std::endl;
996                 return;
997         }
998
999         u8 ser_version = m_server_ser_ver;
1000
1001         if(command == TOCLIENT_INIT)
1002         {
1003                 if(datasize < 3)
1004                         return;
1005
1006                 u8 deployed = data[2];
1007
1008                 infostream<<"Client: TOCLIENT_INIT received with "
1009                                 "deployed="<<((int)deployed&0xff)<<std::endl;
1010
1011                 if(!ser_ver_supported(deployed))
1012                 {
1013                         infostream<<"Client: TOCLIENT_INIT: Server sent "
1014                                         <<"unsupported ser_fmt_ver"<<std::endl;
1015                         return;
1016                 }
1017                 
1018                 m_server_ser_ver = deployed;
1019
1020                 // Get player position
1021                 v3s16 playerpos_s16(0, BS*2+BS*20, 0);
1022                 if(datasize >= 2+1+6)
1023                         playerpos_s16 = readV3S16(&data[2+1]);
1024                 v3f playerpos_f = intToFloat(playerpos_s16, BS) - v3f(0, BS/2, 0);
1025
1026                         
1027                 // Set player position
1028                 Player *player = m_env.getLocalPlayer();
1029                 assert(player != NULL);
1030                 player->setPosition(playerpos_f);
1031                 
1032                 if(datasize >= 2+1+6+8)
1033                 {
1034                         // Get map seed
1035                         m_map_seed = readU64(&data[2+1+6]);
1036                         infostream<<"Client: received map seed: "<<m_map_seed<<std::endl;
1037                 }
1038
1039                 if(datasize >= 2+1+6+8+4)
1040                 {
1041                         // Get map seed
1042                         m_recommended_send_interval = readF1000(&data[2+1+6+8]);
1043                         infostream<<"Client: received recommended send interval "
1044                                         <<m_recommended_send_interval<<std::endl;
1045                 }
1046                 
1047                 // Reply to server
1048                 u32 replysize = 2;
1049                 SharedBuffer<u8> reply(replysize);
1050                 writeU16(&reply[0], TOSERVER_INIT2);
1051                 // Send as reliable
1052                 m_con.Send(PEER_ID_SERVER, 1, reply, true);
1053
1054                 return;
1055         }
1056
1057         if(command == TOCLIENT_ACCESS_DENIED)
1058         {
1059                 // The server didn't like our password. Note, this needs
1060                 // to be processed even if the serialisation format has
1061                 // not been agreed yet, the same as TOCLIENT_INIT.
1062                 m_access_denied = true;
1063                 m_access_denied_reason = L"Unknown";
1064                 if(datasize >= 4)
1065                 {
1066                         std::string datastring((char*)&data[2], datasize-2);
1067                         std::istringstream is(datastring, std::ios_base::binary);
1068                         m_access_denied_reason = deSerializeWideString(is);
1069                 }
1070                 return;
1071         }
1072
1073         if(ser_version == SER_FMT_VER_INVALID)
1074         {
1075                 infostream<<"Client: Server serialization"
1076                                 " format invalid or not initialized."
1077                                 " Skipping incoming command="<<command<<std::endl;
1078                 return;
1079         }
1080         
1081         /*
1082           Handle runtime commands
1083         */
1084         // there's no sane reason why we shouldn't have a player and
1085         // almost everyone needs a player reference
1086         Player *player = m_env.getLocalPlayer();
1087         assert(player != NULL);
1088
1089         if(command == TOCLIENT_REMOVENODE)
1090         {
1091                 if(datasize < 8)
1092                         return;
1093                 v3s16 p;
1094                 p.X = readS16(&data[2]);
1095                 p.Y = readS16(&data[4]);
1096                 p.Z = readS16(&data[6]);
1097                 removeNode(p);
1098         }
1099         else if(command == TOCLIENT_ADDNODE)
1100         {
1101                 if(datasize < 8 + MapNode::serializedLength(ser_version))
1102                         return;
1103
1104                 v3s16 p;
1105                 p.X = readS16(&data[2]);
1106                 p.Y = readS16(&data[4]);
1107                 p.Z = readS16(&data[6]);
1108
1109                 MapNode n;
1110                 n.deSerialize(&data[8], ser_version);
1111                 
1112                 bool remove_metadata = true;
1113                 u32 index = 8 + MapNode::serializedLength(ser_version);
1114                 if ((datasize >= index+1) && data[index]){
1115                         remove_metadata = false;
1116                 }
1117                 
1118                 addNode(p, n, remove_metadata);
1119         }
1120         else if(command == TOCLIENT_BLOCKDATA)
1121         {
1122                 // Ignore too small packet
1123                 if(datasize < 8)
1124                         return;
1125                         
1126                 v3s16 p;
1127                 p.X = readS16(&data[2]);
1128                 p.Y = readS16(&data[4]);
1129                 p.Z = readS16(&data[6]);
1130                 
1131                 std::string datastring((char*)&data[8], datasize-8);
1132                 std::istringstream istr(datastring, std::ios_base::binary);
1133                 
1134                 MapSector *sector;
1135                 MapBlock *block;
1136                 
1137                 v2s16 p2d(p.X, p.Z);
1138                 sector = m_env.getMap().emergeSector(p2d);
1139                 
1140                 assert(sector->getPos() == p2d);
1141                 
1142                 block = sector->getBlockNoCreateNoEx(p.Y);
1143                 if(block)
1144                 {
1145                         /*
1146                                 Update an existing block
1147                         */
1148                         block->deSerialize(istr, ser_version, false);
1149                         block->deSerializeNetworkSpecific(istr);
1150                 }
1151                 else
1152                 {
1153                         /*
1154                                 Create a new block
1155                         */
1156                         block = new MapBlock(&m_env.getMap(), p, this);
1157                         block->deSerialize(istr, ser_version, false);
1158                         block->deSerializeNetworkSpecific(istr);
1159                         sector->insertBlock(block);
1160                 }
1161
1162                 /*
1163                         Add it to mesh update queue and set it to be acknowledged after update.
1164                 */
1165                 addUpdateMeshTaskWithEdge(p, true);
1166         }
1167         else if(command == TOCLIENT_INVENTORY)
1168         {
1169                 if(datasize < 3)
1170                         return;
1171
1172                 std::string datastring((char*)&data[2], datasize-2);
1173                 std::istringstream is(datastring, std::ios_base::binary);
1174
1175                 player->inventory.deSerialize(is);
1176
1177                 m_inventory_updated = true;
1178
1179                 delete m_inventory_from_server;
1180                 m_inventory_from_server = new Inventory(player->inventory);
1181                 m_inventory_from_server_age = 0.0;
1182
1183         }
1184         else if(command == TOCLIENT_TIME_OF_DAY)
1185         {
1186                 if(datasize < 4)
1187                         return;
1188                 
1189                 u16 time_of_day  = readU16(&data[2]);
1190                 time_of_day      = time_of_day % 24000;
1191                 float time_speed = 0;
1192
1193                 if(datasize >= 2 + 2 + 4)
1194                 {
1195                         time_speed = readF1000(&data[4]);
1196                 }
1197                 else {
1198                         // Old message; try to approximate speed of time by ourselves
1199                         float time_of_day_f = (float)time_of_day / 24000.0;
1200                         float tod_diff_f = 0;
1201
1202                         if(time_of_day_f < 0.2 && m_last_time_of_day_f > 0.8)
1203                                 tod_diff_f = time_of_day_f - m_last_time_of_day_f + 1.0;
1204                         else
1205                                 tod_diff_f = time_of_day_f - m_last_time_of_day_f;
1206
1207                         m_last_time_of_day_f         = time_of_day_f;
1208                         float time_diff            = m_time_of_day_update_timer;
1209                         m_time_of_day_update_timer = 0;
1210
1211                         if(m_time_of_day_set){
1212                                 time_speed = (3600.0*24.0) * tod_diff_f / time_diff;
1213                                 infostream<<"Client: Measured time_of_day speed (old format): "
1214                                                 <<time_speed<<" tod_diff_f="<<tod_diff_f
1215                                                 <<" time_diff="<<time_diff<<std::endl;
1216                         }
1217                 }
1218                 
1219                 // Update environment
1220                 m_env.setTimeOfDay(time_of_day);
1221                 m_env.setTimeOfDaySpeed(time_speed);
1222                 m_time_of_day_set = true;
1223
1224                 u32 dr = m_env.getDayNightRatio();
1225                 verbosestream<<"Client: time_of_day="<<time_of_day
1226                                 <<" time_speed="<<time_speed
1227                                 <<" dr="<<dr<<std::endl;
1228         }
1229         else if(command == TOCLIENT_CHAT_MESSAGE)
1230         {
1231                 /*
1232                         u16 command
1233                         u16 length
1234                         wstring message
1235                 */
1236                 u8 buf[6];
1237                 std::string datastring((char*)&data[2], datasize-2);
1238                 std::istringstream is(datastring, std::ios_base::binary);
1239                 
1240                 // Read stuff
1241                 is.read((char*) buf, 2);
1242                 u16 len = readU16(buf);
1243                 
1244                 std::wstring message;
1245                 for(unsigned int i=0; i<len; i++)
1246                 {
1247                         is.read((char*)buf, 2);
1248                         message += (wchar_t)readU16(buf);
1249                 }
1250                 
1251                 m_chat_queue.push_back(message);
1252         }
1253         else if(command == TOCLIENT_ACTIVE_OBJECT_REMOVE_ADD)
1254         {
1255                 /*
1256                         u16 command
1257                         u16 count of removed objects
1258                         for all removed objects {
1259                                 u16 id
1260                         }
1261                         u16 count of added objects
1262                         for all added objects {
1263                                 u16 id
1264                                 u8 type
1265                                 u32 initialization data length
1266                                 string initialization data
1267                         }
1268                 */
1269
1270                 char buf[6];
1271                 // Get all data except the command number
1272                 std::string datastring((char*)&data[2], datasize-2);
1273                 // Throw them in an istringstream
1274                 std::istringstream is(datastring, std::ios_base::binary);
1275
1276                 // Read removed objects
1277                 is.read(buf, 2);
1278                 u16 removed_count = readU16((u8*)buf);
1279                 for(unsigned int i=0; i<removed_count; i++)
1280                 {
1281                         is.read(buf, 2);
1282                         u16 id = readU16((u8*)buf);
1283                         m_env.removeActiveObject(id);
1284                 }
1285
1286                 // Read added objects
1287                 is.read(buf, 2);
1288                 u16 added_count = readU16((u8*)buf);
1289                 for(unsigned int i=0; i<added_count; i++)
1290                 {
1291                         is.read(buf, 2);
1292                         u16 id = readU16((u8*)buf);
1293                         is.read(buf, 1);
1294                         u8 type = readU8((u8*)buf);
1295                         std::string data = deSerializeLongString(is);
1296                         // Add it
1297                         m_env.addActiveObject(id, type, data);
1298                 }
1299         }
1300         else if(command == TOCLIENT_ACTIVE_OBJECT_MESSAGES)
1301         {
1302                 /*
1303                         u16 command
1304                         for all objects
1305                         {
1306                                 u16 id
1307                                 u16 message length
1308                                 string message
1309                         }
1310                 */
1311                 char buf[6];
1312                 // Get all data except the command number
1313                 std::string datastring((char*)&data[2], datasize-2);
1314                 // Throw them in an istringstream
1315                 std::istringstream is(datastring, std::ios_base::binary);
1316
1317                 while(is.eof() == false)
1318                 {
1319                         is.read(buf, 2);
1320                         u16 id = readU16((u8*)buf);
1321                         if(is.eof())
1322                                 break;
1323                         is.read(buf, 2);
1324                         size_t message_size = readU16((u8*)buf);
1325                         std::string message;
1326                         message.reserve(message_size);
1327                         for(unsigned int i=0; i<message_size; i++)
1328                         {
1329                                 is.read(buf, 1);
1330                                 message.append(buf, 1);
1331                         }
1332                         // Pass on to the environment
1333                         m_env.processActiveObjectMessage(id, message);
1334                 }
1335         }
1336         else if(command == TOCLIENT_MOVEMENT)
1337         {
1338                 std::string datastring((char*)&data[2], datasize-2);
1339                 std::istringstream is(datastring, std::ios_base::binary);
1340
1341                 player->movement_acceleration_default   = readF1000(is) * BS;
1342                 player->movement_acceleration_air       = readF1000(is) * BS;
1343                 player->movement_acceleration_fast      = readF1000(is) * BS;
1344                 player->movement_speed_walk             = readF1000(is) * BS;
1345                 player->movement_speed_crouch           = readF1000(is) * BS;
1346                 player->movement_speed_fast             = readF1000(is) * BS;
1347                 player->movement_speed_climb            = readF1000(is) * BS;
1348                 player->movement_speed_jump             = readF1000(is) * BS;
1349                 player->movement_liquid_fluidity        = readF1000(is) * BS;
1350                 player->movement_liquid_fluidity_smooth = readF1000(is) * BS;
1351                 player->movement_liquid_sink            = readF1000(is) * BS;
1352                 player->movement_gravity                = readF1000(is) * BS;
1353         }
1354         else if(command == TOCLIENT_HP)
1355         {
1356                 std::string datastring((char*)&data[2], datasize-2);
1357                 std::istringstream is(datastring, std::ios_base::binary);
1358
1359                 u8 oldhp   = player->hp;
1360                 u8 hp      = readU8(is);
1361                 player->hp = hp;
1362
1363                 if(hp < oldhp)
1364                 {
1365                         // Add to ClientEvent queue
1366                         ClientEvent event;
1367                         event.type = CE_PLAYER_DAMAGE;
1368                         event.player_damage.amount = oldhp - hp;
1369                         m_client_event_queue.push_back(event);
1370                 }
1371         }
1372         else if(command == TOCLIENT_BREATH)
1373         {
1374                 std::string datastring((char*)&data[2], datasize-2);
1375                 std::istringstream is(datastring, std::ios_base::binary);
1376
1377                 player->setBreath(readU16(is));
1378         }
1379         else if(command == TOCLIENT_MOVE_PLAYER)
1380         {
1381                 std::string datastring((char*)&data[2], datasize-2);
1382                 std::istringstream is(datastring, std::ios_base::binary);
1383
1384                 v3f pos = readV3F1000(is);
1385                 f32 pitch = readF1000(is);
1386                 f32 yaw = readF1000(is);
1387                 player->setPosition(pos);
1388
1389                 infostream<<"Client got TOCLIENT_MOVE_PLAYER"
1390                                 <<" pos=("<<pos.X<<","<<pos.Y<<","<<pos.Z<<")"
1391                                 <<" pitch="<<pitch
1392                                 <<" yaw="<<yaw
1393                                 <<std::endl;
1394
1395                 /*
1396                         Add to ClientEvent queue.
1397                         This has to be sent to the main program because otherwise
1398                         it would just force the pitch and yaw values to whatever
1399                         the camera points to.
1400                 */
1401                 ClientEvent event;
1402                 event.type = CE_PLAYER_FORCE_MOVE;
1403                 event.player_force_move.pitch = pitch;
1404                 event.player_force_move.yaw = yaw;
1405                 m_client_event_queue.push_back(event);
1406
1407                 // Ignore damage for a few seconds, so that the player doesn't
1408                 // get damage from falling on ground
1409                 m_ignore_damage_timer = 3.0;
1410         }
1411         else if(command == TOCLIENT_PLAYERITEM)
1412         {
1413                 infostream<<"Client: WARNING: Ignoring TOCLIENT_PLAYERITEM"<<std::endl;
1414         }
1415         else if(command == TOCLIENT_DEATHSCREEN)
1416         {
1417                 std::string datastring((char*)&data[2], datasize-2);
1418                 std::istringstream is(datastring, std::ios_base::binary);
1419                 
1420                 bool set_camera_point_target = readU8(is);
1421                 v3f camera_point_target = readV3F1000(is);
1422                 
1423                 ClientEvent event;
1424                 event.type                                = CE_DEATHSCREEN;
1425                 event.deathscreen.set_camera_point_target = set_camera_point_target;
1426                 event.deathscreen.camera_point_target_x   = camera_point_target.X;
1427                 event.deathscreen.camera_point_target_y   = camera_point_target.Y;
1428                 event.deathscreen.camera_point_target_z   = camera_point_target.Z;
1429                 m_client_event_queue.push_back(event);
1430         }
1431         else if(command == TOCLIENT_ANNOUNCE_MEDIA)
1432         {
1433                 std::string datastring((char*)&data[2], datasize-2);
1434                 std::istringstream is(datastring, std::ios_base::binary);
1435
1436                 int num_files = readU16(is);
1437                 
1438                 infostream<<"Client: Received media announcement: packet size: "
1439                                 <<datasize<<std::endl;
1440
1441                 if (m_media_downloader == NULL ||
1442                                 m_media_downloader->isStarted()) {
1443                         const char *problem = m_media_downloader ?
1444                                 "we already saw another announcement" :
1445                                 "all media has been received already";
1446                         errorstream<<"Client: Received media announcement but "
1447                                 <<problem<<"! "
1448                                 <<" files="<<num_files
1449                                 <<" size="<<datasize<<std::endl;
1450                         return;
1451                 }
1452
1453                 // Mesh update thread must be stopped while
1454                 // updating content definitions
1455                 assert(!m_mesh_update_thread.IsRunning());
1456
1457                 for(int i=0; i<num_files; i++)
1458                 {
1459                         std::string name = deSerializeString(is);
1460                         std::string sha1_base64 = deSerializeString(is);
1461                         std::string sha1_raw = base64_decode(sha1_base64);
1462                         m_media_downloader->addFile(name, sha1_raw);
1463                 }
1464
1465                 std::vector<std::string> remote_media;
1466                 try {
1467                         Strfnd sf(deSerializeString(is));
1468                         while(!sf.atend()) {
1469                                 std::string baseurl = trim(sf.next(","));
1470                                 if(baseurl != "")
1471                                         m_media_downloader->addRemoteServer(baseurl);
1472                         }
1473                 }
1474                 catch(SerializationError& e) {
1475                         // not supported by server or turned off
1476                 }
1477
1478                 m_media_downloader->step(this);
1479         }
1480         else if(command == TOCLIENT_MEDIA)
1481         {
1482                 std::string datastring((char*)&data[2], datasize-2);
1483                 std::istringstream is(datastring, std::ios_base::binary);
1484
1485                 /*
1486                         u16 command
1487                         u16 total number of file bunches
1488                         u16 index of this bunch
1489                         u32 number of files in this bunch
1490                         for each file {
1491                                 u16 length of name
1492                                 string name
1493                                 u32 length of data
1494                                 data
1495                         }
1496                 */
1497                 int num_bunches = readU16(is);
1498                 int bunch_i = readU16(is);
1499                 u32 num_files = readU32(is);
1500                 infostream<<"Client: Received files: bunch "<<bunch_i<<"/"
1501                                 <<num_bunches<<" files="<<num_files
1502                                 <<" size="<<datasize<<std::endl;
1503
1504                 if (num_files == 0)
1505                         return;
1506
1507                 if (m_media_downloader == NULL ||
1508                                 !m_media_downloader->isStarted()) {
1509                         const char *problem = m_media_downloader ?
1510                                 "media has not been requested" :
1511                                 "all media has been received already";
1512                         errorstream<<"Client: Received media but "
1513                                 <<problem<<"! "
1514                                 <<" bunch "<<bunch_i<<"/"<<num_bunches
1515                                 <<" files="<<num_files
1516                                 <<" size="<<datasize<<std::endl;
1517                         return;
1518                 }
1519
1520                 // Mesh update thread must be stopped while
1521                 // updating content definitions
1522                 assert(!m_mesh_update_thread.IsRunning());
1523
1524                 for(unsigned int i=0; i<num_files; i++){
1525                         std::string name = deSerializeString(is);
1526                         std::string data = deSerializeLongString(is);
1527                         m_media_downloader->conventionalTransferDone(
1528                                         name, data, this);
1529                 }
1530         }
1531         else if(command == TOCLIENT_TOOLDEF)
1532         {
1533                 infostream<<"Client: WARNING: Ignoring TOCLIENT_TOOLDEF"<<std::endl;
1534         }
1535         else if(command == TOCLIENT_NODEDEF)
1536         {
1537                 infostream<<"Client: Received node definitions: packet size: "
1538                                 <<datasize<<std::endl;
1539
1540                 // Mesh update thread must be stopped while
1541                 // updating content definitions
1542                 assert(!m_mesh_update_thread.IsRunning());
1543
1544                 // Decompress node definitions
1545                 std::string datastring((char*)&data[2], datasize-2);
1546                 std::istringstream is(datastring, std::ios_base::binary);
1547                 std::istringstream tmp_is(deSerializeLongString(is), std::ios::binary);
1548                 std::ostringstream tmp_os;
1549                 decompressZlib(tmp_is, tmp_os);
1550
1551                 // Deserialize node definitions
1552                 std::istringstream tmp_is2(tmp_os.str());
1553                 m_nodedef->deSerialize(tmp_is2);
1554                 m_nodedef_received = true;
1555         }
1556         else if(command == TOCLIENT_CRAFTITEMDEF)
1557         {
1558                 infostream<<"Client: WARNING: Ignoring TOCLIENT_CRAFTITEMDEF"<<std::endl;
1559         }
1560         else if(command == TOCLIENT_ITEMDEF)
1561         {
1562                 infostream<<"Client: Received item definitions: packet size: "
1563                                 <<datasize<<std::endl;
1564
1565                 // Mesh update thread must be stopped while
1566                 // updating content definitions
1567                 assert(!m_mesh_update_thread.IsRunning());
1568
1569                 // Decompress item definitions
1570                 std::string datastring((char*)&data[2], datasize-2);
1571                 std::istringstream is(datastring, std::ios_base::binary);
1572                 std::istringstream tmp_is(deSerializeLongString(is), std::ios::binary);
1573                 std::ostringstream tmp_os;
1574                 decompressZlib(tmp_is, tmp_os);
1575
1576                 // Deserialize node definitions
1577                 std::istringstream tmp_is2(tmp_os.str());
1578                 m_itemdef->deSerialize(tmp_is2);
1579                 m_itemdef_received = true;
1580         }
1581         else if(command == TOCLIENT_PLAY_SOUND)
1582         {
1583                 std::string datastring((char*)&data[2], datasize-2);
1584                 std::istringstream is(datastring, std::ios_base::binary);
1585
1586                 s32 server_id = readS32(is);
1587                 std::string name = deSerializeString(is);
1588                 float gain = readF1000(is);
1589                 int type = readU8(is); // 0=local, 1=positional, 2=object
1590                 v3f pos = readV3F1000(is);
1591                 u16 object_id = readU16(is);
1592                 bool loop = readU8(is);
1593                 // Start playing
1594                 int client_id = -1;
1595                 switch(type){
1596                 case 0: // local
1597                         client_id = m_sound->playSound(name, loop, gain);
1598                         break;
1599                 case 1: // positional
1600                         client_id = m_sound->playSoundAt(name, loop, gain, pos);
1601                         break;
1602                 case 2: { // object
1603                         ClientActiveObject *cao = m_env.getActiveObject(object_id);
1604                         if(cao)
1605                                 pos = cao->getPosition();
1606                         client_id = m_sound->playSoundAt(name, loop, gain, pos);
1607                         // TODO: Set up sound to move with object
1608                         break; }
1609                 default:
1610                         break;
1611                 }
1612                 if(client_id != -1){
1613                         m_sounds_server_to_client[server_id] = client_id;
1614                         m_sounds_client_to_server[client_id] = server_id;
1615                         if(object_id != 0)
1616                                 m_sounds_to_objects[client_id] = object_id;
1617                 }
1618         }
1619         else if(command == TOCLIENT_STOP_SOUND)
1620         {
1621                 std::string datastring((char*)&data[2], datasize-2);
1622                 std::istringstream is(datastring, std::ios_base::binary);
1623
1624                 s32 server_id = readS32(is);
1625                 std::map<s32, int>::iterator i =
1626                                 m_sounds_server_to_client.find(server_id);
1627                 if(i != m_sounds_server_to_client.end()){
1628                         int client_id = i->second;
1629                         m_sound->stopSound(client_id);
1630                 }
1631         }
1632         else if(command == TOCLIENT_PRIVILEGES)
1633         {
1634                 std::string datastring((char*)&data[2], datasize-2);
1635                 std::istringstream is(datastring, std::ios_base::binary);
1636                 
1637                 m_privileges.clear();
1638                 infostream<<"Client: Privileges updated: ";
1639                 u16 num_privileges = readU16(is);
1640                 for(unsigned int i=0; i<num_privileges; i++){
1641                         std::string priv = deSerializeString(is);
1642                         m_privileges.insert(priv);
1643                         infostream<<priv<<" ";
1644                 }
1645                 infostream<<std::endl;
1646         }
1647         else if(command == TOCLIENT_INVENTORY_FORMSPEC)
1648         {
1649                 std::string datastring((char*)&data[2], datasize-2);
1650                 std::istringstream is(datastring, std::ios_base::binary);
1651
1652                 // Store formspec in LocalPlayer
1653                 player->inventory_formspec = deSerializeLongString(is);
1654         }
1655         else if(command == TOCLIENT_DETACHED_INVENTORY)
1656         {
1657                 std::string datastring((char*)&data[2], datasize-2);
1658                 std::istringstream is(datastring, std::ios_base::binary);
1659
1660                 std::string name = deSerializeString(is);
1661                 
1662                 infostream<<"Client: Detached inventory update: \""<<name<<"\""<<std::endl;
1663
1664                 Inventory *inv = NULL;
1665                 if(m_detached_inventories.count(name) > 0)
1666                         inv = m_detached_inventories[name];
1667                 else{
1668                         inv = new Inventory(m_itemdef);
1669                         m_detached_inventories[name] = inv;
1670                 }
1671                 inv->deSerialize(is);
1672         }
1673         else if(command == TOCLIENT_SHOW_FORMSPEC)
1674         {
1675                 std::string datastring((char*)&data[2], datasize-2);
1676                 std::istringstream is(datastring, std::ios_base::binary);
1677
1678                 std::string formspec = deSerializeLongString(is);
1679                 std::string formname = deSerializeString(is);
1680
1681                 ClientEvent event;
1682                 event.type = CE_SHOW_FORMSPEC;
1683                 // pointer is required as event is a struct only!
1684                 // adding a std:string to a struct isn't possible
1685                 event.show_formspec.formspec = new std::string(formspec);
1686                 event.show_formspec.formname = new std::string(formname);
1687                 m_client_event_queue.push_back(event);
1688         }
1689         else if(command == TOCLIENT_SPAWN_PARTICLE)
1690         {
1691                 std::string datastring((char*)&data[2], datasize-2);
1692                 std::istringstream is(datastring, std::ios_base::binary);
1693
1694                 v3f pos                 = readV3F1000(is);
1695                 v3f vel                 = readV3F1000(is);
1696                 v3f acc                 = readV3F1000(is);
1697                 float expirationtime    = readF1000(is);
1698                 float size              = readF1000(is);
1699                 bool collisiondetection = readU8(is);
1700                 std::string texture     = deSerializeLongString(is);
1701                 bool vertical           = false;
1702                 try {
1703                         vertical = readU8(is);
1704                 } catch (...) {}
1705
1706                 ClientEvent event;
1707                 event.type                              = CE_SPAWN_PARTICLE;
1708                 event.spawn_particle.pos                = new v3f (pos);
1709                 event.spawn_particle.vel                = new v3f (vel);
1710                 event.spawn_particle.acc                = new v3f (acc);
1711                 event.spawn_particle.expirationtime     = expirationtime;
1712                 event.spawn_particle.size               = size;
1713                 event.spawn_particle.collisiondetection = collisiondetection;
1714                 event.spawn_particle.vertical           = vertical;
1715                 event.spawn_particle.texture            = new std::string(texture);
1716
1717                 m_client_event_queue.push_back(event);
1718         }
1719         else if(command == TOCLIENT_ADD_PARTICLESPAWNER)
1720         {
1721                 std::string datastring((char*)&data[2], datasize-2);
1722                 std::istringstream is(datastring, std::ios_base::binary);
1723
1724                 u16 amount              = readU16(is);
1725                 float spawntime         = readF1000(is);
1726                 v3f minpos              = readV3F1000(is);
1727                 v3f maxpos              = readV3F1000(is);
1728                 v3f minvel              = readV3F1000(is);
1729                 v3f maxvel              = readV3F1000(is);
1730                 v3f minacc              = readV3F1000(is);
1731                 v3f maxacc              = readV3F1000(is);
1732                 float minexptime        = readF1000(is);
1733                 float maxexptime        = readF1000(is);
1734                 float minsize           = readF1000(is);
1735                 float maxsize           = readF1000(is);
1736                 bool collisiondetection = readU8(is);
1737                 std::string texture     = deSerializeLongString(is);
1738                 u32 id                  = readU32(is);
1739                 bool vertical = false;
1740                 try {
1741                         vertical = readU8(is);
1742                 } catch (...) {}
1743
1744                 ClientEvent event;
1745                 event.type                                   = CE_ADD_PARTICLESPAWNER;
1746                 event.add_particlespawner.amount             = amount;
1747                 event.add_particlespawner.spawntime          = spawntime;
1748                 event.add_particlespawner.minpos             = new v3f (minpos);
1749                 event.add_particlespawner.maxpos             = new v3f (maxpos);
1750                 event.add_particlespawner.minvel             = new v3f (minvel);
1751                 event.add_particlespawner.maxvel             = new v3f (maxvel);
1752                 event.add_particlespawner.minacc             = new v3f (minacc);
1753                 event.add_particlespawner.maxacc             = new v3f (maxacc);
1754                 event.add_particlespawner.minexptime         = minexptime;
1755                 event.add_particlespawner.maxexptime         = maxexptime;
1756                 event.add_particlespawner.minsize            = minsize;
1757                 event.add_particlespawner.maxsize            = maxsize;
1758                 event.add_particlespawner.collisiondetection = collisiondetection;
1759                 event.add_particlespawner.vertical           = vertical;
1760                 event.add_particlespawner.texture            = new std::string(texture);
1761                 event.add_particlespawner.id                 = id;
1762
1763                 m_client_event_queue.push_back(event);
1764         }
1765         else if(command == TOCLIENT_DELETE_PARTICLESPAWNER)
1766         {
1767                 std::string datastring((char*)&data[2], datasize-2);
1768                 std::istringstream is(datastring, std::ios_base::binary);
1769
1770                 u32 id = readU16(is);
1771
1772                 ClientEvent event;
1773                 event.type                      = CE_DELETE_PARTICLESPAWNER;
1774                 event.delete_particlespawner.id = id;
1775
1776                 m_client_event_queue.push_back(event);
1777         }
1778         else if(command == TOCLIENT_HUDADD)
1779         {
1780                 std::string datastring((char *)&data[2], datasize - 2);
1781                 std::istringstream is(datastring, std::ios_base::binary);
1782
1783                 u32 id           = readU32(is);
1784                 u8 type          = readU8(is);
1785                 v2f pos          = readV2F1000(is);
1786                 std::string name = deSerializeString(is);
1787                 v2f scale        = readV2F1000(is);
1788                 std::string text = deSerializeString(is);
1789                 u32 number       = readU32(is);
1790                 u32 item         = readU32(is);
1791                 u32 dir          = readU32(is);
1792                 v2f align        = readV2F1000(is);
1793                 v2f offset       = readV2F1000(is);
1794                 v3f world_pos;
1795                 try{
1796                         world_pos    = readV3F1000(is);
1797                 }catch(SerializationError &e) {};
1798
1799                 ClientEvent event;
1800                 event.type             = CE_HUDADD;
1801                 event.hudadd.id        = id;
1802                 event.hudadd.type      = type;
1803                 event.hudadd.pos       = new v2f(pos);
1804                 event.hudadd.name      = new std::string(name);
1805                 event.hudadd.scale     = new v2f(scale);
1806                 event.hudadd.text      = new std::string(text);
1807                 event.hudadd.number    = number;
1808                 event.hudadd.item      = item;
1809                 event.hudadd.dir       = dir;
1810                 event.hudadd.align     = new v2f(align);
1811                 event.hudadd.offset    = new v2f(offset);
1812                 event.hudadd.world_pos = new v3f(world_pos);
1813                 m_client_event_queue.push_back(event);
1814         }
1815         else if(command == TOCLIENT_HUDRM)
1816         {
1817                 std::string datastring((char *)&data[2], datasize - 2);
1818                 std::istringstream is(datastring, std::ios_base::binary);
1819
1820                 u32 id = readU32(is);
1821
1822                 ClientEvent event;
1823                 event.type     = CE_HUDRM;
1824                 event.hudrm.id = id;
1825                 m_client_event_queue.push_back(event);
1826         }
1827         else if(command == TOCLIENT_HUDCHANGE)
1828         {
1829                 std::string sdata;
1830                 v2f v2fdata;
1831                 v3f v3fdata;
1832                 u32 intdata = 0;
1833                 
1834                 std::string datastring((char *)&data[2], datasize - 2);
1835                 std::istringstream is(datastring, std::ios_base::binary);
1836
1837                 u32 id  = readU32(is);
1838                 u8 stat = (HudElementStat)readU8(is);
1839                 
1840                 if (stat == HUD_STAT_POS || stat == HUD_STAT_SCALE ||
1841                         stat == HUD_STAT_ALIGN || stat == HUD_STAT_OFFSET)
1842                         v2fdata = readV2F1000(is);
1843                 else if (stat == HUD_STAT_NAME || stat == HUD_STAT_TEXT)
1844                         sdata = deSerializeString(is);
1845                 else if (stat == HUD_STAT_WORLD_POS)
1846                         v3fdata = readV3F1000(is);
1847                 else
1848                         intdata = readU32(is);
1849                 
1850                 ClientEvent event;
1851                 event.type              = CE_HUDCHANGE;
1852                 event.hudchange.id      = id;
1853                 event.hudchange.stat    = (HudElementStat)stat;
1854                 event.hudchange.v2fdata = new v2f(v2fdata);
1855                 event.hudchange.v3fdata = new v3f(v3fdata);
1856                 event.hudchange.sdata   = new std::string(sdata);
1857                 event.hudchange.data    = intdata;
1858                 m_client_event_queue.push_back(event);
1859         }
1860         else if(command == TOCLIENT_HUD_SET_FLAGS)
1861         {
1862                 std::string datastring((char *)&data[2], datasize - 2);
1863                 std::istringstream is(datastring, std::ios_base::binary);
1864
1865                 u32 flags = readU32(is);
1866                 u32 mask  = readU32(is);
1867                 
1868                 player->hud_flags &= ~mask;
1869                 player->hud_flags |= flags;
1870         }
1871         else if(command == TOCLIENT_HUD_SET_PARAM)
1872         {
1873                 std::string datastring((char *)&data[2], datasize - 2);
1874                 std::istringstream is(datastring, std::ios_base::binary);
1875
1876                 u16 param         = readU16(is);
1877                 std::string value = deSerializeString(is);
1878
1879                 if(param == HUD_PARAM_HOTBAR_ITEMCOUNT && value.size() == 4) {
1880                         s32 hotbar_itemcount = readS32((u8*) value.c_str());
1881                         if(hotbar_itemcount > 0 && hotbar_itemcount <= HUD_HOTBAR_ITEMCOUNT_MAX)
1882                                 player->hud_hotbar_itemcount = hotbar_itemcount;
1883                 }
1884                 else if (param == HUD_PARAM_HOTBAR_IMAGE) {
1885                         ((LocalPlayer *) player)->hotbar_image = value;
1886                 }
1887                 else if (param == HUD_PARAM_HOTBAR_SELECTED_IMAGE) {
1888                         ((LocalPlayer *) player)->hotbar_selected_image = value;
1889                 }
1890         }
1891         else if(command == TOCLIENT_SET_SKY)
1892         {
1893                 std::string datastring((char *)&data[2], datasize - 2);
1894                 std::istringstream is(datastring, std::ios_base::binary);
1895
1896                 video::SColor *bgcolor           = new video::SColor(readARGB8(is));
1897                 std::string *type                = new std::string(deSerializeString(is));
1898                 u16 count                        = readU16(is);
1899                 std::vector<std::string> *params = new std::vector<std::string>;
1900
1901                 for(size_t i=0; i<count; i++)
1902                         params->push_back(deSerializeString(is));
1903
1904                 ClientEvent event;
1905                 event.type            = CE_SET_SKY;
1906                 event.set_sky.bgcolor = bgcolor;
1907                 event.set_sky.type    = type;
1908                 event.set_sky.params  = params;
1909                 m_client_event_queue.push_back(event);
1910         }
1911         else if(command == TOCLIENT_OVERRIDE_DAY_NIGHT_RATIO)
1912         {
1913                 std::string datastring((char *)&data[2], datasize - 2);
1914                 std::istringstream is(datastring, std::ios_base::binary);
1915
1916                 bool do_override        = readU8(is);
1917                 float day_night_ratio_f = (float)readU16(is) / 65536;
1918
1919                 ClientEvent event;
1920                 event.type                                 = CE_OVERRIDE_DAY_NIGHT_RATIO;
1921                 event.override_day_night_ratio.do_override = do_override;
1922                 event.override_day_night_ratio.ratio_f     = day_night_ratio_f;
1923                 m_client_event_queue.push_back(event);
1924         }
1925         else
1926         {
1927                 infostream<<"Client: Ignoring unknown command "
1928                                 <<command<<std::endl;
1929         }
1930 }
1931
1932 void Client::Send(u16 channelnum, SharedBuffer<u8> data, bool reliable)
1933 {
1934         //JMutexAutoLock lock(m_con_mutex); //bulk comment-out
1935         m_con.Send(PEER_ID_SERVER, channelnum, data, reliable);
1936 }
1937
1938 void Client::interact(u8 action, const PointedThing& pointed)
1939 {
1940         if(connectedAndInitialized() == false){
1941                 infostream<<"Client::interact() "
1942                                 "cancelled (not connected)"
1943                                 <<std::endl;
1944                 return;
1945         }
1946
1947         std::ostringstream os(std::ios_base::binary);
1948
1949         /*
1950                 [0] u16 command
1951                 [2] u8 action
1952                 [3] u16 item
1953                 [5] u32 length of the next item
1954                 [9] serialized PointedThing
1955                 actions:
1956                 0: start digging (from undersurface) or use
1957                 1: stop digging (all parameters ignored)
1958                 2: digging completed
1959                 3: place block or item (to abovesurface)
1960                 4: use item
1961         */
1962         writeU16(os, TOSERVER_INTERACT);
1963         writeU8(os, action);
1964         writeU16(os, getPlayerItem());
1965         std::ostringstream tmp_os(std::ios::binary);
1966         pointed.serialize(tmp_os);
1967         os<<serializeLongString(tmp_os.str());
1968
1969         std::string s = os.str();
1970         SharedBuffer<u8> data((u8*)s.c_str(), s.size());
1971
1972         // Send as reliable
1973         Send(0, data, true);
1974 }
1975
1976 void Client::sendNodemetaFields(v3s16 p, const std::string &formname,
1977                 const std::map<std::string, std::string> &fields)
1978 {
1979         std::ostringstream os(std::ios_base::binary);
1980
1981         writeU16(os, TOSERVER_NODEMETA_FIELDS);
1982         writeV3S16(os, p);
1983         os<<serializeString(formname);
1984         size_t fields_size = fields.size();
1985         assert(fields_size <= 0xFFFF);
1986         writeU16(os, (u16) (fields_size & 0xFFFF));
1987         for(std::map<std::string, std::string>::const_iterator
1988                         i = fields.begin(); i != fields.end(); i++){
1989                 const std::string &name = i->first;
1990                 const std::string &value = i->second;
1991                 os<<serializeString(name);
1992                 os<<serializeLongString(value);
1993         }
1994
1995         // Make data buffer
1996         std::string s = os.str();
1997         SharedBuffer<u8> data((u8*)s.c_str(), s.size());
1998         // Send as reliable
1999         Send(0, data, true);
2000 }
2001         
2002 void Client::sendInventoryFields(const std::string &formname,
2003                 const std::map<std::string, std::string> &fields)
2004 {
2005         std::ostringstream os(std::ios_base::binary);
2006
2007         writeU16(os, TOSERVER_INVENTORY_FIELDS);
2008         os<<serializeString(formname);
2009         size_t fields_size = fields.size();
2010         assert(fields_size <= 0xFFFF);
2011         writeU16(os, (u16) (fields_size & 0xFFFF));
2012         for(std::map<std::string, std::string>::const_iterator
2013                         i = fields.begin(); i != fields.end(); i++){
2014                 const std::string &name  = i->first;
2015                 const std::string &value = i->second;
2016                 os<<serializeString(name);
2017                 os<<serializeLongString(value);
2018         }
2019
2020         // Make data buffer
2021         std::string s = os.str();
2022         SharedBuffer<u8> data((u8*)s.c_str(), s.size());
2023         // Send as reliable
2024         Send(0, data, true);
2025 }
2026
2027 void Client::sendInventoryAction(InventoryAction *a)
2028 {
2029         std::ostringstream os(std::ios_base::binary);
2030         u8 buf[12];
2031         
2032         // Write command
2033         writeU16(buf, TOSERVER_INVENTORY_ACTION);
2034         os.write((char*)buf, 2);
2035
2036         a->serialize(os);
2037         
2038         // Make data buffer
2039         std::string s = os.str();
2040         SharedBuffer<u8> data((u8*)s.c_str(), s.size());
2041         // Send as reliable
2042         Send(0, data, true);
2043 }
2044
2045 void Client::sendChatMessage(const std::wstring &message)
2046 {
2047         std::ostringstream os(std::ios_base::binary);
2048         u8 buf[12];
2049         
2050         // Write command
2051         writeU16(buf, TOSERVER_CHAT_MESSAGE);
2052         os.write((char*)buf, 2);
2053         
2054         // Write length
2055         size_t messagesize = message.size();
2056         assert(messagesize <= 0xFFFF);
2057         writeU16(buf, (u16) (messagesize & 0xFF));
2058         os.write((char*)buf, 2);
2059         
2060         // Write string
2061         for(unsigned int i=0; i<message.size(); i++)
2062         {
2063                 u16 w = message[i];
2064                 writeU16(buf, w);
2065                 os.write((char*)buf, 2);
2066         }
2067         
2068         // Make data buffer
2069         std::string s = os.str();
2070         SharedBuffer<u8> data((u8*)s.c_str(), s.size());
2071         // Send as reliable
2072         Send(0, data, true);
2073 }
2074
2075 void Client::sendChangePassword(const std::wstring &oldpassword,
2076                                 const std::wstring &newpassword)
2077 {
2078         Player *player = m_env.getLocalPlayer();
2079         if(player == NULL)
2080                 return;
2081
2082         std::string playername = player->getName();
2083         std::string oldpwd = translatePassword(playername, oldpassword);
2084         std::string newpwd = translatePassword(playername, newpassword);
2085
2086         std::ostringstream os(std::ios_base::binary);
2087         u8 buf[2+PASSWORD_SIZE*2];
2088         /*
2089                 [0] u16 TOSERVER_PASSWORD
2090                 [2] u8[28] old password
2091                 [30] u8[28] new password
2092         */
2093
2094         writeU16(buf, TOSERVER_PASSWORD);
2095         for(unsigned int i=0;i<PASSWORD_SIZE-1;i++)
2096         {
2097                 buf[2+i] = i<oldpwd.length()?oldpwd[i]:0;
2098                 buf[30+i] = i<newpwd.length()?newpwd[i]:0;
2099         }
2100         buf[2+PASSWORD_SIZE-1] = 0;
2101         buf[30+PASSWORD_SIZE-1] = 0;
2102         os.write((char*)buf, 2+PASSWORD_SIZE*2);
2103
2104         // Make data buffer
2105         std::string s = os.str();
2106         SharedBuffer<u8> data((u8*)s.c_str(), s.size());
2107         // Send as reliable
2108         Send(0, data, true);
2109 }
2110
2111
2112 void Client::sendDamage(u8 damage)
2113 {
2114         DSTACK(__FUNCTION_NAME);
2115         std::ostringstream os(std::ios_base::binary);
2116
2117         writeU16(os, TOSERVER_DAMAGE);
2118         writeU8(os, damage);
2119
2120         // Make data buffer
2121         std::string s = os.str();
2122         SharedBuffer<u8> data((u8*)s.c_str(), s.size());
2123         // Send as reliable
2124         Send(0, data, true);
2125 }
2126
2127 void Client::sendBreath(u16 breath)
2128 {
2129         DSTACK(__FUNCTION_NAME);
2130         std::ostringstream os(std::ios_base::binary);
2131
2132         writeU16(os, TOSERVER_BREATH);
2133         writeU16(os, breath);
2134         // Make data buffer
2135         std::string s = os.str();
2136         SharedBuffer<u8> data((u8*)s.c_str(), s.size());
2137         // Send as reliable
2138         Send(0, data, true);
2139 }
2140
2141 void Client::sendRespawn()
2142 {
2143         DSTACK(__FUNCTION_NAME);
2144         std::ostringstream os(std::ios_base::binary);
2145
2146         writeU16(os, TOSERVER_RESPAWN);
2147
2148         // Make data buffer
2149         std::string s = os.str();
2150         SharedBuffer<u8> data((u8*)s.c_str(), s.size());
2151         // Send as reliable
2152         Send(0, data, true);
2153 }
2154
2155 void Client::sendPlayerPos()
2156 {
2157         LocalPlayer *myplayer = m_env.getLocalPlayer();
2158         if(myplayer == NULL)
2159                 return;
2160
2161         // Save bandwidth by only updating position when something changed
2162         if(myplayer->last_position        == myplayer->getPosition() &&
2163                         myplayer->last_speed      == myplayer->getSpeed()    &&
2164                         myplayer->last_pitch      == myplayer->getPitch()    &&
2165                         myplayer->last_yaw        == myplayer->getYaw()      &&
2166                         myplayer->last_keyPressed == myplayer->keyPressed)
2167                 return;
2168
2169         myplayer->last_position   = myplayer->getPosition();
2170         myplayer->last_speed      = myplayer->getSpeed();
2171         myplayer->last_pitch      = myplayer->getPitch();
2172         myplayer->last_yaw        = myplayer->getYaw();
2173         myplayer->last_keyPressed = myplayer->keyPressed;
2174
2175         u16 our_peer_id;
2176         {
2177                 //JMutexAutoLock lock(m_con_mutex); //bulk comment-out
2178                 our_peer_id = m_con.GetPeerID();
2179         }
2180         
2181         // Set peer id if not set already
2182         if(myplayer->peer_id == PEER_ID_INEXISTENT)
2183                 myplayer->peer_id = our_peer_id;
2184         // Check that an existing peer_id is the same as the connection's
2185         assert(myplayer->peer_id == our_peer_id);
2186         
2187         v3f pf         = myplayer->getPosition();
2188         v3f sf         = myplayer->getSpeed();
2189         s32 pitch      = myplayer->getPitch() * 100;
2190         s32 yaw        = myplayer->getYaw() * 100;
2191         u32 keyPressed = myplayer->keyPressed;
2192
2193         v3s32 position(pf.X*100, pf.Y*100, pf.Z*100);
2194         v3s32 speed(sf.X*100, sf.Y*100, sf.Z*100);
2195         /*
2196                 Format:
2197                 [0] u16 command
2198                 [2] v3s32 position*100
2199                 [2+12] v3s32 speed*100
2200                 [2+12+12] s32 pitch*100
2201                 [2+12+12+4] s32 yaw*100
2202                 [2+12+12+4+4] u32 keyPressed
2203         */
2204         SharedBuffer<u8> data(2+12+12+4+4+4);
2205         writeU16(&data[0], TOSERVER_PLAYERPOS);
2206         writeV3S32(&data[2], position);
2207         writeV3S32(&data[2+12], speed);
2208         writeS32(&data[2+12+12], pitch);
2209         writeS32(&data[2+12+12+4], yaw);
2210         writeU32(&data[2+12+12+4+4], keyPressed);
2211         // Send as unreliable
2212         Send(0, data, false);
2213 }
2214
2215 void Client::sendPlayerItem(u16 item)
2216 {
2217         Player *myplayer = m_env.getLocalPlayer();
2218         if(myplayer == NULL)
2219                 return;
2220
2221         u16 our_peer_id = m_con.GetPeerID();
2222
2223         // Set peer id if not set already
2224         if(myplayer->peer_id == PEER_ID_INEXISTENT)
2225                 myplayer->peer_id = our_peer_id;
2226         // Check that an existing peer_id is the same as the connection's
2227         assert(myplayer->peer_id == our_peer_id);
2228
2229         SharedBuffer<u8> data(2+2);
2230         writeU16(&data[0], TOSERVER_PLAYERITEM);
2231         writeU16(&data[2], item);
2232
2233         // Send as reliable
2234         Send(0, data, true);
2235 }
2236
2237 void Client::removeNode(v3s16 p)
2238 {
2239         std::map<v3s16, MapBlock*> modified_blocks;
2240
2241         try
2242         {
2243                 m_env.getMap().removeNodeAndUpdate(p, modified_blocks);
2244         }
2245         catch(InvalidPositionException &e)
2246         {
2247         }
2248         
2249         // add urgent task to update the modified node
2250         addUpdateMeshTaskForNode(p, false, true);
2251
2252         for(std::map<v3s16, MapBlock * >::iterator
2253                         i = modified_blocks.begin();
2254                         i != modified_blocks.end(); ++i)
2255         {
2256                 addUpdateMeshTaskWithEdge(i->first);
2257         }
2258 }
2259
2260 void Client::addNode(v3s16 p, MapNode n, bool remove_metadata)
2261 {
2262         TimeTaker timer1("Client::addNode()");
2263
2264         std::map<v3s16, MapBlock*> modified_blocks;
2265
2266         try
2267         {
2268                 //TimeTaker timer3("Client::addNode(): addNodeAndUpdate");
2269                 m_env.getMap().addNodeAndUpdate(p, n, modified_blocks, remove_metadata);
2270         }
2271         catch(InvalidPositionException &e)
2272         {}
2273         
2274         for(std::map<v3s16, MapBlock * >::iterator
2275                         i = modified_blocks.begin();
2276                         i != modified_blocks.end(); ++i)
2277         {
2278                 addUpdateMeshTaskWithEdge(i->first);
2279         }
2280 }
2281         
2282 void Client::setPlayerControl(PlayerControl &control)
2283 {
2284         LocalPlayer *player = m_env.getLocalPlayer();
2285         assert(player != NULL);
2286         player->control = control;
2287 }
2288
2289 void Client::selectPlayerItem(u16 item)
2290 {
2291         m_playeritem = item;
2292         m_inventory_updated = true;
2293         sendPlayerItem(item);
2294 }
2295
2296 // Returns true if the inventory of the local player has been
2297 // updated from the server. If it is true, it is set to false.
2298 bool Client::getLocalInventoryUpdated()
2299 {
2300         bool updated = m_inventory_updated;
2301         m_inventory_updated = false;
2302         return updated;
2303 }
2304
2305 // Copies the inventory of the local player to parameter
2306 void Client::getLocalInventory(Inventory &dst)
2307 {
2308         Player *player = m_env.getLocalPlayer();
2309         assert(player != NULL);
2310         dst = player->inventory;
2311 }
2312
2313 Inventory* Client::getInventory(const InventoryLocation &loc)
2314 {
2315         switch(loc.type){
2316         case InventoryLocation::UNDEFINED:
2317         {}
2318         break;
2319         case InventoryLocation::CURRENT_PLAYER:
2320         {
2321                 Player *player = m_env.getLocalPlayer();
2322                 assert(player != NULL);
2323                 return &player->inventory;
2324         }
2325         break;
2326         case InventoryLocation::PLAYER:
2327         {
2328                 Player *player = m_env.getPlayer(loc.name.c_str());
2329                 if(!player)
2330                         return NULL;
2331                 return &player->inventory;
2332         }
2333         break;
2334         case InventoryLocation::NODEMETA:
2335         {
2336                 NodeMetadata *meta = m_env.getMap().getNodeMetadata(loc.p);
2337                 if(!meta)
2338                         return NULL;
2339                 return meta->getInventory();
2340         }
2341         break;
2342         case InventoryLocation::DETACHED:
2343         {
2344                 if(m_detached_inventories.count(loc.name) == 0)
2345                         return NULL;
2346                 return m_detached_inventories[loc.name];
2347         }
2348         break;
2349         default:
2350                 assert(0);
2351         }
2352         return NULL;
2353 }
2354
2355 void Client::inventoryAction(InventoryAction *a)
2356 {
2357         /*
2358                 Send it to the server
2359         */
2360         sendInventoryAction(a);
2361
2362         /*
2363                 Predict some local inventory changes
2364         */
2365         a->clientApply(this, this);
2366
2367         // Remove it
2368         delete a;
2369 }
2370
2371 ClientActiveObject * Client::getSelectedActiveObject(
2372                 f32 max_d,
2373                 v3f from_pos_f_on_map,
2374                 core::line3d<f32> shootline_on_map
2375         )
2376 {
2377         std::vector<DistanceSortedActiveObject> objects;
2378
2379         m_env.getActiveObjects(from_pos_f_on_map, max_d, objects);
2380         
2381         // Sort them.
2382         // After this, the closest object is the first in the array.
2383         std::sort(objects.begin(), objects.end());
2384
2385         for(unsigned int i=0; i<objects.size(); i++)
2386         {
2387                 ClientActiveObject *obj = objects[i].obj;
2388                 
2389                 core::aabbox3d<f32> *selection_box = obj->getSelectionBox();
2390                 if(selection_box == NULL)
2391                         continue;
2392
2393                 v3f pos = obj->getPosition();
2394
2395                 core::aabbox3d<f32> offsetted_box(
2396                                 selection_box->MinEdge + pos,
2397                                 selection_box->MaxEdge + pos
2398                 );
2399
2400                 if(offsetted_box.intersectsWithLine(shootline_on_map))
2401                 {
2402                         return obj;
2403                 }
2404         }
2405
2406         return NULL;
2407 }
2408
2409 std::list<std::string> Client::getConnectedPlayerNames()
2410 {
2411         return m_env.getPlayerNames();
2412 }
2413
2414 float Client::getAnimationTime()
2415 {
2416         return m_animation_time;
2417 }
2418
2419 int Client::getCrackLevel()
2420 {
2421         return m_crack_level;
2422 }
2423
2424 void Client::setCrack(int level, v3s16 pos)
2425 {
2426         int old_crack_level = m_crack_level;
2427         v3s16 old_crack_pos = m_crack_pos;
2428
2429         m_crack_level = level;
2430         m_crack_pos = pos;
2431
2432         if(old_crack_level >= 0 && (level < 0 || pos != old_crack_pos))
2433         {
2434                 // remove old crack
2435                 addUpdateMeshTaskForNode(old_crack_pos, false, true);
2436         }
2437         if(level >= 0 && (old_crack_level < 0 || pos != old_crack_pos))
2438         {
2439                 // add new crack
2440                 addUpdateMeshTaskForNode(pos, false, true);
2441         }
2442 }
2443
2444 u16 Client::getHP()
2445 {
2446         Player *player = m_env.getLocalPlayer();
2447         assert(player != NULL);
2448         return player->hp;
2449 }
2450
2451 u16 Client::getBreath()
2452 {
2453         Player *player = m_env.getLocalPlayer();
2454         assert(player != NULL);
2455         return player->getBreath();
2456 }
2457
2458 bool Client::getChatMessage(std::wstring &message)
2459 {
2460         if(m_chat_queue.size() == 0)
2461                 return false;
2462         message = m_chat_queue.pop_front();
2463         return true;
2464 }
2465
2466 void Client::typeChatMessage(const std::wstring &message)
2467 {
2468         // Discard empty line
2469         if(message == L"")
2470                 return;
2471
2472         // Send to others
2473         sendChatMessage(message);
2474
2475         // Show locally
2476         if (message[0] == L'/')
2477         {
2478                 m_chat_queue.push_back(
2479                                 (std::wstring)L"issued command: "+message);
2480         }
2481         else
2482         {
2483                 LocalPlayer *player = m_env.getLocalPlayer();
2484                 assert(player != NULL);
2485                 std::wstring name = narrow_to_wide(player->getName());
2486                 m_chat_queue.push_back(
2487                                 (std::wstring)L"<"+name+L"> "+message);
2488         }
2489 }
2490
2491 void Client::addUpdateMeshTask(v3s16 p, bool ack_to_server, bool urgent)
2492 {
2493         MapBlock *b = m_env.getMap().getBlockNoCreateNoEx(p);
2494         if(b == NULL)
2495                 return;
2496         
2497         /*
2498                 Create a task to update the mesh of the block
2499         */
2500         
2501         MeshMakeData *data = new MeshMakeData(this);
2502         
2503         {
2504                 //TimeTaker timer("data fill");
2505                 // Release: ~0ms
2506                 // Debug: 1-6ms, avg=2ms
2507                 data->fill(b);
2508                 data->setCrack(m_crack_level, m_crack_pos);
2509                 data->setSmoothLighting(g_settings->getBool("smooth_lighting"));
2510         }
2511         
2512         // Add task to queue
2513         m_mesh_update_thread.m_queue_in.addBlock(p, data, ack_to_server, urgent);
2514 }
2515
2516 void Client::addUpdateMeshTaskWithEdge(v3s16 blockpos, bool ack_to_server, bool urgent)
2517 {
2518         try{
2519                 v3s16 p = blockpos + v3s16(0,0,0);
2520                 //MapBlock *b = m_env.getMap().getBlockNoCreate(p);
2521                 addUpdateMeshTask(p, ack_to_server, urgent);
2522         }
2523         catch(InvalidPositionException &e){}
2524
2525         // Leading edge
2526         for (int i=0;i<6;i++)
2527         {
2528                 try{
2529                         v3s16 p = blockpos + g_6dirs[i];
2530                         addUpdateMeshTask(p, false, urgent);
2531                 }
2532                 catch(InvalidPositionException &e){}
2533         }
2534 }
2535
2536 void Client::addUpdateMeshTaskForNode(v3s16 nodepos, bool ack_to_server, bool urgent)
2537 {
2538         {
2539                 v3s16 p = nodepos;
2540                 infostream<<"Client::addUpdateMeshTaskForNode(): "
2541                                 <<"("<<p.X<<","<<p.Y<<","<<p.Z<<")"
2542                                 <<std::endl;
2543         }
2544
2545         v3s16 blockpos          = getNodeBlockPos(nodepos);
2546         v3s16 blockpos_relative = blockpos * MAP_BLOCKSIZE;
2547
2548         try{
2549                 v3s16 p = blockpos + v3s16(0,0,0);
2550                 addUpdateMeshTask(p, ack_to_server, urgent);
2551         }
2552         catch(InvalidPositionException &e){}
2553
2554         // Leading edge
2555         if(nodepos.X == blockpos_relative.X){
2556                 try{
2557                         v3s16 p = blockpos + v3s16(-1,0,0);
2558                         addUpdateMeshTask(p, false, urgent);
2559                 }
2560                 catch(InvalidPositionException &e){}
2561         }
2562
2563         if(nodepos.Y == blockpos_relative.Y){
2564                 try{
2565                         v3s16 p = blockpos + v3s16(0,-1,0);
2566                         addUpdateMeshTask(p, false, urgent);
2567                 }
2568                 catch(InvalidPositionException &e){}
2569         }
2570
2571         if(nodepos.Z == blockpos_relative.Z){
2572                 try{
2573                         v3s16 p = blockpos + v3s16(0,0,-1);
2574                         addUpdateMeshTask(p, false, urgent);
2575                 }
2576                 catch(InvalidPositionException &e){}
2577         }
2578 }
2579
2580 ClientEvent Client::getClientEvent()
2581 {
2582         if(m_client_event_queue.size() == 0)
2583         {
2584                 ClientEvent event;
2585                 event.type = CE_NONE;
2586                 return event;
2587         }
2588         return m_client_event_queue.pop_front();
2589 }
2590
2591 float Client::mediaReceiveProgress()
2592 {
2593         if (m_media_downloader)
2594                 return m_media_downloader->getProgress();
2595         else
2596                 return 1.0; // downloader only exists when not yet done
2597 }
2598
2599 void draw_load_screen(const std::wstring &text,
2600                 IrrlichtDevice* device, gui::IGUIFont* font,
2601                 float dtime=0 ,int percent=0, bool clouds=true);
2602
2603 void Client::afterContentReceived(IrrlichtDevice *device, gui::IGUIFont* font)
2604 {
2605         infostream<<"Client::afterContentReceived() started"<<std::endl;
2606         assert(m_itemdef_received);
2607         assert(m_nodedef_received);
2608         assert(mediaReceived());
2609         
2610         // Rebuild inherited images and recreate textures
2611         infostream<<"- Rebuilding images and textures"<<std::endl;
2612         m_tsrc->rebuildImagesAndTextures();
2613
2614         // Rebuild shaders
2615         infostream<<"- Rebuilding shaders"<<std::endl;
2616         m_shsrc->rebuildShaders();
2617
2618         // Update node aliases
2619         infostream<<"- Updating node aliases"<<std::endl;
2620         m_nodedef->updateAliases(m_itemdef);
2621
2622         // Update node textures
2623         infostream<<"- Updating node textures"<<std::endl;
2624         m_nodedef->updateTextures(m_tsrc);
2625
2626         // Preload item textures and meshes if configured to
2627         if(g_settings->getBool("preload_item_visuals"))
2628         {
2629                 verbosestream<<"Updating item textures and meshes"<<std::endl;
2630                 wchar_t* text = wgettext("Item textures...");
2631                 draw_load_screen(text,device,font,0,0);
2632                 std::set<std::string> names = m_itemdef->getAll();
2633                 size_t size = names.size();
2634                 size_t count = 0;
2635                 int percent = 0;
2636                 for(std::set<std::string>::const_iterator
2637                                 i = names.begin(); i != names.end(); ++i){
2638                         // Asking for these caches the result
2639                         m_itemdef->getInventoryTexture(*i, this);
2640                         m_itemdef->getWieldMesh(*i, this);
2641                         count++;
2642                         percent = count*100/size;
2643                         if (count%50 == 0) // only update every 50 item
2644                                 draw_load_screen(text,device,font,0,percent);
2645                 }
2646                 delete[] text;
2647         }
2648
2649         // Start mesh update thread after setting up content definitions
2650         infostream<<"- Starting mesh update thread"<<std::endl;
2651         m_mesh_update_thread.Start();
2652         
2653         infostream<<"Client::afterContentReceived() done"<<std::endl;
2654 }
2655
2656 float Client::getRTT(void)
2657 {
2658         try{
2659                 return m_con.GetPeerAvgRTT(PEER_ID_SERVER);
2660         } catch(con::PeerNotFoundException &e){
2661                 return 1337;
2662         }
2663 }
2664
2665 // IGameDef interface
2666 // Under envlock
2667 IItemDefManager* Client::getItemDefManager()
2668 {
2669         return m_itemdef;
2670 }
2671 INodeDefManager* Client::getNodeDefManager()
2672 {
2673         return m_nodedef;
2674 }
2675 ICraftDefManager* Client::getCraftDefManager()
2676 {
2677         return NULL;
2678         //return m_craftdef;
2679 }
2680 ITextureSource* Client::getTextureSource()
2681 {
2682         return m_tsrc;
2683 }
2684 IShaderSource* Client::getShaderSource()
2685 {
2686         return m_shsrc;
2687 }
2688 u16 Client::allocateUnknownNodeId(const std::string &name)
2689 {
2690         errorstream<<"Client::allocateUnknownNodeId(): "
2691                         <<"Client cannot allocate node IDs"<<std::endl;
2692         assert(0);
2693         return CONTENT_IGNORE;
2694 }
2695 ISoundManager* Client::getSoundManager()
2696 {
2697         return m_sound;
2698 }
2699 MtEventManager* Client::getEventManager()
2700 {
2701         return m_event;
2702 }
2703
2704 scene::IAnimatedMesh* Client::getMesh(const std::string &filename)
2705 {
2706         std::map<std::string, std::string>::const_iterator i =
2707                         m_mesh_data.find(filename);
2708         if(i == m_mesh_data.end()){
2709                 errorstream<<"Client::getMesh(): Mesh not found: \""<<filename<<"\""
2710                                 <<std::endl;
2711                 return NULL;
2712         }
2713         const std::string &data    = i->second;
2714         scene::ISceneManager *smgr = m_device->getSceneManager();
2715
2716         // Create the mesh, remove it from cache and return it
2717         // This allows unique vertex colors and other properties for each instance
2718         Buffer<char> data_rw(data.c_str(), data.size()); // Const-incorrect Irrlicht
2719         io::IFileSystem *irrfs = m_device->getFileSystem();
2720         io::IReadFile *rfile   = irrfs->createMemoryReadFile(
2721                         *data_rw, data_rw.getSize(), filename.c_str());
2722         assert(rfile);
2723
2724         scene::IAnimatedMesh *mesh = smgr->getMesh(rfile);
2725         rfile->drop();
2726         // NOTE: By playing with Irrlicht refcounts, maybe we could cache a bunch
2727         // of uniquely named instances and re-use them
2728         mesh->grab();
2729         smgr->getMeshCache()->removeMesh(mesh);
2730         return mesh;
2731 }
2732