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