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