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