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