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