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