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