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