56f55ef6ce6ec92c78ec7e395fab8a7d5fbe23f6
[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
1918         {
1919                 infostream<<"Client: Ignoring unknown command "
1920                                 <<command<<std::endl;
1921         }
1922 }
1923
1924 void Client::Send(u16 channelnum, SharedBuffer<u8> data, bool reliable)
1925 {
1926         //JMutexAutoLock lock(m_con_mutex); //bulk comment-out
1927         m_con.Send(PEER_ID_SERVER, channelnum, data, reliable);
1928 }
1929
1930 void Client::interact(u8 action, const PointedThing& pointed)
1931 {
1932         if(m_state != LC_Ready){
1933                 infostream<<"Client::interact() "
1934                                 "cancelled (not connected)"
1935                                 <<std::endl;
1936                 return;
1937         }
1938
1939         std::ostringstream os(std::ios_base::binary);
1940
1941         /*
1942                 [0] u16 command
1943                 [2] u8 action
1944                 [3] u16 item
1945                 [5] u32 length of the next item
1946                 [9] serialized PointedThing
1947                 actions:
1948                 0: start digging (from undersurface) or use
1949                 1: stop digging (all parameters ignored)
1950                 2: digging completed
1951                 3: place block or item (to abovesurface)
1952                 4: use item
1953         */
1954         writeU16(os, TOSERVER_INTERACT);
1955         writeU8(os, action);
1956         writeU16(os, getPlayerItem());
1957         std::ostringstream tmp_os(std::ios::binary);
1958         pointed.serialize(tmp_os);
1959         os<<serializeLongString(tmp_os.str());
1960
1961         std::string s = os.str();
1962         SharedBuffer<u8> data((u8*)s.c_str(), s.size());
1963
1964         // Send as reliable
1965         Send(0, data, true);
1966 }
1967
1968 void Client::sendNodemetaFields(v3s16 p, const std::string &formname,
1969                 const std::map<std::string, std::string> &fields)
1970 {
1971         std::ostringstream os(std::ios_base::binary);
1972
1973         writeU16(os, TOSERVER_NODEMETA_FIELDS);
1974         writeV3S16(os, p);
1975         os<<serializeString(formname);
1976         size_t fields_size = fields.size();
1977         assert(fields_size <= 0xFFFF);
1978         writeU16(os, (u16) (fields_size & 0xFFFF));
1979         for(std::map<std::string, std::string>::const_iterator
1980                         i = fields.begin(); i != fields.end(); i++){
1981                 const std::string &name = i->first;
1982                 const std::string &value = i->second;
1983                 os<<serializeString(name);
1984                 os<<serializeLongString(value);
1985         }
1986
1987         // Make data buffer
1988         std::string s = os.str();
1989         SharedBuffer<u8> data((u8*)s.c_str(), s.size());
1990         // Send as reliable
1991         Send(0, data, true);
1992 }
1993         
1994 void Client::sendInventoryFields(const std::string &formname,
1995                 const std::map<std::string, std::string> &fields)
1996 {
1997         std::ostringstream os(std::ios_base::binary);
1998
1999         writeU16(os, TOSERVER_INVENTORY_FIELDS);
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::sendInventoryAction(InventoryAction *a)
2020 {
2021         std::ostringstream os(std::ios_base::binary);
2022         u8 buf[12];
2023         
2024         // Write command
2025         writeU16(buf, TOSERVER_INVENTORY_ACTION);
2026         os.write((char*)buf, 2);
2027
2028         a->serialize(os);
2029         
2030         // Make data buffer
2031         std::string s = os.str();
2032         SharedBuffer<u8> data((u8*)s.c_str(), s.size());
2033         // Send as reliable
2034         Send(0, data, true);
2035 }
2036
2037 void Client::sendChatMessage(const std::wstring &message)
2038 {
2039         std::ostringstream os(std::ios_base::binary);
2040         u8 buf[12];
2041         
2042         // Write command
2043         writeU16(buf, TOSERVER_CHAT_MESSAGE);
2044         os.write((char*)buf, 2);
2045         
2046         // Write length
2047         size_t messagesize = message.size();
2048         assert(messagesize <= 0xFFFF);
2049         writeU16(buf, (u16) (messagesize & 0xFF));
2050         os.write((char*)buf, 2);
2051         
2052         // Write string
2053         for(unsigned int i=0; i<message.size(); i++)
2054         {
2055                 u16 w = message[i];
2056                 writeU16(buf, w);
2057                 os.write((char*)buf, 2);
2058         }
2059         
2060         // Make data buffer
2061         std::string s = os.str();
2062         SharedBuffer<u8> data((u8*)s.c_str(), s.size());
2063         // Send as reliable
2064         Send(0, data, true);
2065 }
2066
2067 void Client::sendChangePassword(const std::wstring &oldpassword,
2068                                 const std::wstring &newpassword)
2069 {
2070         Player *player = m_env.getLocalPlayer();
2071         if(player == NULL)
2072                 return;
2073
2074         std::string playername = player->getName();
2075         std::string oldpwd = translatePassword(playername, oldpassword);
2076         std::string newpwd = translatePassword(playername, newpassword);
2077
2078         std::ostringstream os(std::ios_base::binary);
2079         u8 buf[2+PASSWORD_SIZE*2];
2080         /*
2081                 [0] u16 TOSERVER_PASSWORD
2082                 [2] u8[28] old password
2083                 [30] u8[28] new password
2084         */
2085
2086         writeU16(buf, TOSERVER_PASSWORD);
2087         for(unsigned int i=0;i<PASSWORD_SIZE-1;i++)
2088         {
2089                 buf[2+i] = i<oldpwd.length()?oldpwd[i]:0;
2090                 buf[30+i] = i<newpwd.length()?newpwd[i]:0;
2091         }
2092         buf[2+PASSWORD_SIZE-1] = 0;
2093         buf[30+PASSWORD_SIZE-1] = 0;
2094         os.write((char*)buf, 2+PASSWORD_SIZE*2);
2095
2096         // Make data buffer
2097         std::string s = os.str();
2098         SharedBuffer<u8> data((u8*)s.c_str(), s.size());
2099         // Send as reliable
2100         Send(0, data, true);
2101 }
2102
2103
2104 void Client::sendDamage(u8 damage)
2105 {
2106         DSTACK(__FUNCTION_NAME);
2107         std::ostringstream os(std::ios_base::binary);
2108
2109         writeU16(os, TOSERVER_DAMAGE);
2110         writeU8(os, damage);
2111
2112         // Make data buffer
2113         std::string s = os.str();
2114         SharedBuffer<u8> data((u8*)s.c_str(), s.size());
2115         // Send as reliable
2116         Send(0, data, true);
2117 }
2118
2119 void Client::sendBreath(u16 breath)
2120 {
2121         DSTACK(__FUNCTION_NAME);
2122         std::ostringstream os(std::ios_base::binary);
2123
2124         writeU16(os, TOSERVER_BREATH);
2125         writeU16(os, breath);
2126         // Make data buffer
2127         std::string s = os.str();
2128         SharedBuffer<u8> data((u8*)s.c_str(), s.size());
2129         // Send as reliable
2130         Send(0, data, true);
2131 }
2132
2133 void Client::sendRespawn()
2134 {
2135         DSTACK(__FUNCTION_NAME);
2136         std::ostringstream os(std::ios_base::binary);
2137
2138         writeU16(os, TOSERVER_RESPAWN);
2139
2140         // Make data buffer
2141         std::string s = os.str();
2142         SharedBuffer<u8> data((u8*)s.c_str(), s.size());
2143         // Send as reliable
2144         Send(0, data, true);
2145 }
2146
2147 void Client::sendReady()
2148 {
2149         DSTACK(__FUNCTION_NAME);
2150         std::ostringstream os(std::ios_base::binary);
2151
2152         writeU16(os, TOSERVER_CLIENT_READY);
2153         writeU8(os,VERSION_MAJOR);
2154         writeU8(os,VERSION_MINOR);
2155         writeU8(os,VERSION_PATCH_ORIG);
2156         writeU8(os,0);
2157
2158         writeU16(os,strlen(CMAKE_VERSION_GITHASH));
2159         os.write(CMAKE_VERSION_GITHASH,strlen(CMAKE_VERSION_GITHASH));
2160
2161         // Make data buffer
2162         std::string s = os.str();
2163         SharedBuffer<u8> data((u8*)s.c_str(), s.size());
2164         // Send as reliable
2165         Send(0, data, true);
2166 }
2167
2168 void Client::sendPlayerPos()
2169 {
2170         LocalPlayer *myplayer = m_env.getLocalPlayer();
2171         if(myplayer == NULL)
2172                 return;
2173
2174         // Save bandwidth by only updating position when something changed
2175         if(myplayer->last_position        == myplayer->getPosition() &&
2176                         myplayer->last_speed      == myplayer->getSpeed()    &&
2177                         myplayer->last_pitch      == myplayer->getPitch()    &&
2178                         myplayer->last_yaw        == myplayer->getYaw()      &&
2179                         myplayer->last_keyPressed == myplayer->keyPressed)
2180                 return;
2181
2182         myplayer->last_position   = myplayer->getPosition();
2183         myplayer->last_speed      = myplayer->getSpeed();
2184         myplayer->last_pitch      = myplayer->getPitch();
2185         myplayer->last_yaw        = myplayer->getYaw();
2186         myplayer->last_keyPressed = myplayer->keyPressed;
2187
2188         u16 our_peer_id;
2189         {
2190                 //JMutexAutoLock lock(m_con_mutex); //bulk comment-out
2191                 our_peer_id = m_con.GetPeerID();
2192         }
2193         
2194         // Set peer id if not set already
2195         if(myplayer->peer_id == PEER_ID_INEXISTENT)
2196                 myplayer->peer_id = our_peer_id;
2197         // Check that an existing peer_id is the same as the connection's
2198         assert(myplayer->peer_id == our_peer_id);
2199         
2200         v3f pf         = myplayer->getPosition();
2201         v3f sf         = myplayer->getSpeed();
2202         s32 pitch      = myplayer->getPitch() * 100;
2203         s32 yaw        = myplayer->getYaw() * 100;
2204         u32 keyPressed = myplayer->keyPressed;
2205
2206         v3s32 position(pf.X*100, pf.Y*100, pf.Z*100);
2207         v3s32 speed(sf.X*100, sf.Y*100, sf.Z*100);
2208         /*
2209                 Format:
2210                 [0] u16 command
2211                 [2] v3s32 position*100
2212                 [2+12] v3s32 speed*100
2213                 [2+12+12] s32 pitch*100
2214                 [2+12+12+4] s32 yaw*100
2215                 [2+12+12+4+4] u32 keyPressed
2216         */
2217         SharedBuffer<u8> data(2+12+12+4+4+4);
2218         writeU16(&data[0], TOSERVER_PLAYERPOS);
2219         writeV3S32(&data[2], position);
2220         writeV3S32(&data[2+12], speed);
2221         writeS32(&data[2+12+12], pitch);
2222         writeS32(&data[2+12+12+4], yaw);
2223         writeU32(&data[2+12+12+4+4], keyPressed);
2224         // Send as unreliable
2225         Send(0, data, false);
2226 }
2227
2228 void Client::sendPlayerItem(u16 item)
2229 {
2230         Player *myplayer = m_env.getLocalPlayer();
2231         if(myplayer == NULL)
2232                 return;
2233
2234         u16 our_peer_id = m_con.GetPeerID();
2235
2236         // Set peer id if not set already
2237         if(myplayer->peer_id == PEER_ID_INEXISTENT)
2238                 myplayer->peer_id = our_peer_id;
2239         // Check that an existing peer_id is the same as the connection's
2240         assert(myplayer->peer_id == our_peer_id);
2241
2242         SharedBuffer<u8> data(2+2);
2243         writeU16(&data[0], TOSERVER_PLAYERITEM);
2244         writeU16(&data[2], item);
2245
2246         // Send as reliable
2247         Send(0, data, true);
2248 }
2249
2250 void Client::removeNode(v3s16 p)
2251 {
2252         std::map<v3s16, MapBlock*> modified_blocks;
2253
2254         try
2255         {
2256                 m_env.getMap().removeNodeAndUpdate(p, modified_blocks);
2257         }
2258         catch(InvalidPositionException &e)
2259         {
2260         }
2261         
2262         // add urgent task to update the modified node
2263         addUpdateMeshTaskForNode(p, false, true);
2264
2265         for(std::map<v3s16, MapBlock * >::iterator
2266                         i = modified_blocks.begin();
2267                         i != modified_blocks.end(); ++i)
2268         {
2269                 addUpdateMeshTaskWithEdge(i->first);
2270         }
2271 }
2272
2273 void Client::addNode(v3s16 p, MapNode n, bool remove_metadata)
2274 {
2275         TimeTaker timer1("Client::addNode()");
2276
2277         std::map<v3s16, MapBlock*> modified_blocks;
2278
2279         try
2280         {
2281                 //TimeTaker timer3("Client::addNode(): addNodeAndUpdate");
2282                 m_env.getMap().addNodeAndUpdate(p, n, modified_blocks, remove_metadata);
2283         }
2284         catch(InvalidPositionException &e)
2285         {}
2286         
2287         for(std::map<v3s16, MapBlock * >::iterator
2288                         i = modified_blocks.begin();
2289                         i != modified_blocks.end(); ++i)
2290         {
2291                 addUpdateMeshTaskWithEdge(i->first);
2292         }
2293 }
2294         
2295 void Client::setPlayerControl(PlayerControl &control)
2296 {
2297         LocalPlayer *player = m_env.getLocalPlayer();
2298         assert(player != NULL);
2299         player->control = control;
2300 }
2301
2302 void Client::selectPlayerItem(u16 item)
2303 {
2304         m_playeritem = item;
2305         m_inventory_updated = true;
2306         sendPlayerItem(item);
2307 }
2308
2309 // Returns true if the inventory of the local player has been
2310 // updated from the server. If it is true, it is set to false.
2311 bool Client::getLocalInventoryUpdated()
2312 {
2313         bool updated = m_inventory_updated;
2314         m_inventory_updated = false;
2315         return updated;
2316 }
2317
2318 // Copies the inventory of the local player to parameter
2319 void Client::getLocalInventory(Inventory &dst)
2320 {
2321         Player *player = m_env.getLocalPlayer();
2322         assert(player != NULL);
2323         dst = player->inventory;
2324 }
2325
2326 Inventory* Client::getInventory(const InventoryLocation &loc)
2327 {
2328         switch(loc.type){
2329         case InventoryLocation::UNDEFINED:
2330         {}
2331         break;
2332         case InventoryLocation::CURRENT_PLAYER:
2333         {
2334                 Player *player = m_env.getLocalPlayer();
2335                 assert(player != NULL);
2336                 return &player->inventory;
2337         }
2338         break;
2339         case InventoryLocation::PLAYER:
2340         {
2341                 Player *player = m_env.getPlayer(loc.name.c_str());
2342                 if(!player)
2343                         return NULL;
2344                 return &player->inventory;
2345         }
2346         break;
2347         case InventoryLocation::NODEMETA:
2348         {
2349                 NodeMetadata *meta = m_env.getMap().getNodeMetadata(loc.p);
2350                 if(!meta)
2351                         return NULL;
2352                 return meta->getInventory();
2353         }
2354         break;
2355         case InventoryLocation::DETACHED:
2356         {
2357                 if(m_detached_inventories.count(loc.name) == 0)
2358                         return NULL;
2359                 return m_detached_inventories[loc.name];
2360         }
2361         break;
2362         default:
2363                 assert(0);
2364         }
2365         return NULL;
2366 }
2367
2368 void Client::inventoryAction(InventoryAction *a)
2369 {
2370         /*
2371                 Send it to the server
2372         */
2373         sendInventoryAction(a);
2374
2375         /*
2376                 Predict some local inventory changes
2377         */
2378         a->clientApply(this, this);
2379
2380         // Remove it
2381         delete a;
2382 }
2383
2384 ClientActiveObject * Client::getSelectedActiveObject(
2385                 f32 max_d,
2386                 v3f from_pos_f_on_map,
2387                 core::line3d<f32> shootline_on_map
2388         )
2389 {
2390         std::vector<DistanceSortedActiveObject> objects;
2391
2392         m_env.getActiveObjects(from_pos_f_on_map, max_d, objects);
2393         
2394         // Sort them.
2395         // After this, the closest object is the first in the array.
2396         std::sort(objects.begin(), objects.end());
2397
2398         for(unsigned int i=0; i<objects.size(); i++)
2399         {
2400                 ClientActiveObject *obj = objects[i].obj;
2401                 
2402                 core::aabbox3d<f32> *selection_box = obj->getSelectionBox();
2403                 if(selection_box == NULL)
2404                         continue;
2405
2406                 v3f pos = obj->getPosition();
2407
2408                 core::aabbox3d<f32> offsetted_box(
2409                                 selection_box->MinEdge + pos,
2410                                 selection_box->MaxEdge + pos
2411                 );
2412
2413                 if(offsetted_box.intersectsWithLine(shootline_on_map))
2414                 {
2415                         return obj;
2416                 }
2417         }
2418
2419         return NULL;
2420 }
2421
2422 std::list<std::string> Client::getConnectedPlayerNames()
2423 {
2424         return m_env.getPlayerNames();
2425 }
2426
2427 float Client::getAnimationTime()
2428 {
2429         return m_animation_time;
2430 }
2431
2432 int Client::getCrackLevel()
2433 {
2434         return m_crack_level;
2435 }
2436
2437 void Client::setCrack(int level, v3s16 pos)
2438 {
2439         int old_crack_level = m_crack_level;
2440         v3s16 old_crack_pos = m_crack_pos;
2441
2442         m_crack_level = level;
2443         m_crack_pos = pos;
2444
2445         if(old_crack_level >= 0 && (level < 0 || pos != old_crack_pos))
2446         {
2447                 // remove old crack
2448                 addUpdateMeshTaskForNode(old_crack_pos, false, true);
2449         }
2450         if(level >= 0 && (old_crack_level < 0 || pos != old_crack_pos))
2451         {
2452                 // add new crack
2453                 addUpdateMeshTaskForNode(pos, false, true);
2454         }
2455 }
2456
2457 u16 Client::getHP()
2458 {
2459         Player *player = m_env.getLocalPlayer();
2460         assert(player != NULL);
2461         return player->hp;
2462 }
2463
2464 u16 Client::getBreath()
2465 {
2466         Player *player = m_env.getLocalPlayer();
2467         assert(player != NULL);
2468         return player->getBreath();
2469 }
2470
2471 bool Client::getChatMessage(std::wstring &message)
2472 {
2473         if(m_chat_queue.size() == 0)
2474                 return false;
2475         message = m_chat_queue.pop_front();
2476         return true;
2477 }
2478
2479 void Client::typeChatMessage(const std::wstring &message)
2480 {
2481         // Discard empty line
2482         if(message == L"")
2483                 return;
2484
2485         // Send to others
2486         sendChatMessage(message);
2487
2488         // Show locally
2489         if (message[0] == L'/')
2490         {
2491                 m_chat_queue.push_back(
2492                                 (std::wstring)L"issued command: "+message);
2493         }
2494         else
2495         {
2496                 LocalPlayer *player = m_env.getLocalPlayer();
2497                 assert(player != NULL);
2498                 std::wstring name = narrow_to_wide(player->getName());
2499                 m_chat_queue.push_back(
2500                                 (std::wstring)L"<"+name+L"> "+message);
2501         }
2502 }
2503
2504 void Client::addUpdateMeshTask(v3s16 p, bool ack_to_server, bool urgent)
2505 {
2506         MapBlock *b = m_env.getMap().getBlockNoCreateNoEx(p);
2507         if(b == NULL)
2508                 return;
2509         
2510         /*
2511                 Create a task to update the mesh of the block
2512         */
2513         
2514         MeshMakeData *data = new MeshMakeData(this);
2515         
2516         {
2517                 //TimeTaker timer("data fill");
2518                 // Release: ~0ms
2519                 // Debug: 1-6ms, avg=2ms
2520                 data->fill(b);
2521                 data->setCrack(m_crack_level, m_crack_pos);
2522                 data->setSmoothLighting(g_settings->getBool("smooth_lighting"));
2523         }
2524         
2525         // Add task to queue
2526         m_mesh_update_thread.m_queue_in.addBlock(p, data, ack_to_server, urgent);
2527 }
2528
2529 void Client::addUpdateMeshTaskWithEdge(v3s16 blockpos, bool ack_to_server, bool urgent)
2530 {
2531         try{
2532                 v3s16 p = blockpos + v3s16(0,0,0);
2533                 //MapBlock *b = m_env.getMap().getBlockNoCreate(p);
2534                 addUpdateMeshTask(p, ack_to_server, urgent);
2535         }
2536         catch(InvalidPositionException &e){}
2537
2538         // Leading edge
2539         for (int i=0;i<6;i++)
2540         {
2541                 try{
2542                         v3s16 p = blockpos + g_6dirs[i];
2543                         addUpdateMeshTask(p, false, urgent);
2544                 }
2545                 catch(InvalidPositionException &e){}
2546         }
2547 }
2548
2549 void Client::addUpdateMeshTaskForNode(v3s16 nodepos, bool ack_to_server, bool urgent)
2550 {
2551         {
2552                 v3s16 p = nodepos;
2553                 infostream<<"Client::addUpdateMeshTaskForNode(): "
2554                                 <<"("<<p.X<<","<<p.Y<<","<<p.Z<<")"
2555                                 <<std::endl;
2556         }
2557
2558         v3s16 blockpos          = getNodeBlockPos(nodepos);
2559         v3s16 blockpos_relative = blockpos * MAP_BLOCKSIZE;
2560
2561         try{
2562                 v3s16 p = blockpos + v3s16(0,0,0);
2563                 addUpdateMeshTask(p, ack_to_server, urgent);
2564         }
2565         catch(InvalidPositionException &e){}
2566
2567         // Leading edge
2568         if(nodepos.X == blockpos_relative.X){
2569                 try{
2570                         v3s16 p = blockpos + v3s16(-1,0,0);
2571                         addUpdateMeshTask(p, false, urgent);
2572                 }
2573                 catch(InvalidPositionException &e){}
2574         }
2575
2576         if(nodepos.Y == blockpos_relative.Y){
2577                 try{
2578                         v3s16 p = blockpos + v3s16(0,-1,0);
2579                         addUpdateMeshTask(p, false, urgent);
2580                 }
2581                 catch(InvalidPositionException &e){}
2582         }
2583
2584         if(nodepos.Z == blockpos_relative.Z){
2585                 try{
2586                         v3s16 p = blockpos + v3s16(0,0,-1);
2587                         addUpdateMeshTask(p, false, urgent);
2588                 }
2589                 catch(InvalidPositionException &e){}
2590         }
2591 }
2592
2593 ClientEvent Client::getClientEvent()
2594 {
2595         if(m_client_event_queue.size() == 0)
2596         {
2597                 ClientEvent event;
2598                 event.type = CE_NONE;
2599                 return event;
2600         }
2601         return m_client_event_queue.pop_front();
2602 }
2603
2604 float Client::mediaReceiveProgress()
2605 {
2606         if (m_media_downloader)
2607                 return m_media_downloader->getProgress();
2608         else
2609                 return 1.0; // downloader only exists when not yet done
2610 }
2611
2612 void draw_load_screen(const std::wstring &text,
2613                 IrrlichtDevice* device, gui::IGUIFont* font,
2614                 float dtime=0 ,int percent=0, bool clouds=true);
2615
2616 void Client::afterContentReceived(IrrlichtDevice *device, gui::IGUIFont* font)
2617 {
2618         infostream<<"Client::afterContentReceived() started"<<std::endl;
2619         assert(m_itemdef_received);
2620         assert(m_nodedef_received);
2621         assert(mediaReceived());
2622         
2623         // Rebuild inherited images and recreate textures
2624         infostream<<"- Rebuilding images and textures"<<std::endl;
2625         m_tsrc->rebuildImagesAndTextures();
2626
2627         // Rebuild shaders
2628         infostream<<"- Rebuilding shaders"<<std::endl;
2629         m_shsrc->rebuildShaders();
2630
2631         // Update node aliases
2632         infostream<<"- Updating node aliases"<<std::endl;
2633         m_nodedef->updateAliases(m_itemdef);
2634
2635         // Update node textures
2636         infostream<<"- Updating node textures"<<std::endl;
2637         m_nodedef->updateTextures(m_tsrc);
2638
2639         // Preload item textures and meshes if configured to
2640         if(g_settings->getBool("preload_item_visuals"))
2641         {
2642                 verbosestream<<"Updating item textures and meshes"<<std::endl;
2643                 wchar_t* text = wgettext("Item textures...");
2644                 draw_load_screen(text,device,font,0,0);
2645                 std::set<std::string> names = m_itemdef->getAll();
2646                 size_t size = names.size();
2647                 size_t count = 0;
2648                 int percent = 0;
2649                 for(std::set<std::string>::const_iterator
2650                                 i = names.begin(); i != names.end(); ++i){
2651                         // Asking for these caches the result
2652                         m_itemdef->getInventoryTexture(*i, this);
2653                         m_itemdef->getWieldMesh(*i, this);
2654                         count++;
2655                         percent = count*100/size;
2656                         if (count%50 == 0) // only update every 50 item
2657                                 draw_load_screen(text,device,font,0,percent);
2658                 }
2659                 delete[] text;
2660         }
2661
2662         // Start mesh update thread after setting up content definitions
2663         infostream<<"- Starting mesh update thread"<<std::endl;
2664         m_mesh_update_thread.Start();
2665         
2666         m_state = LC_Ready;
2667         sendReady();
2668         infostream<<"Client::afterContentReceived() done"<<std::endl;
2669 }
2670
2671 float Client::getRTT(void)
2672 {
2673         return m_con.getPeerStat(PEER_ID_SERVER,con::AVG_RTT);
2674 }
2675
2676 // IGameDef interface
2677 // Under envlock
2678 IItemDefManager* Client::getItemDefManager()
2679 {
2680         return m_itemdef;
2681 }
2682 INodeDefManager* Client::getNodeDefManager()
2683 {
2684         return m_nodedef;
2685 }
2686 ICraftDefManager* Client::getCraftDefManager()
2687 {
2688         return NULL;
2689         //return m_craftdef;
2690 }
2691 ITextureSource* Client::getTextureSource()
2692 {
2693         return m_tsrc;
2694 }
2695 IShaderSource* Client::getShaderSource()
2696 {
2697         return m_shsrc;
2698 }
2699 u16 Client::allocateUnknownNodeId(const std::string &name)
2700 {
2701         errorstream<<"Client::allocateUnknownNodeId(): "
2702                         <<"Client cannot allocate node IDs"<<std::endl;
2703         assert(0);
2704         return CONTENT_IGNORE;
2705 }
2706 ISoundManager* Client::getSoundManager()
2707 {
2708         return m_sound;
2709 }
2710 MtEventManager* Client::getEventManager()
2711 {
2712         return m_event;
2713 }
2714
2715 scene::IAnimatedMesh* Client::getMesh(const std::string &filename)
2716 {
2717         std::map<std::string, std::string>::const_iterator i =
2718                         m_mesh_data.find(filename);
2719         if(i == m_mesh_data.end()){
2720                 errorstream<<"Client::getMesh(): Mesh not found: \""<<filename<<"\""
2721                                 <<std::endl;
2722                 return NULL;
2723         }
2724         const std::string &data    = i->second;
2725         scene::ISceneManager *smgr = m_device->getSceneManager();
2726
2727         // Create the mesh, remove it from cache and return it
2728         // This allows unique vertex colors and other properties for each instance
2729         Buffer<char> data_rw(data.c_str(), data.size()); // Const-incorrect Irrlicht
2730         io::IFileSystem *irrfs = m_device->getFileSystem();
2731         io::IReadFile *rfile   = irrfs->createMemoryReadFile(
2732                         *data_rw, data_rw.getSize(), filename.c_str());
2733         assert(rfile);
2734
2735         scene::IAnimatedMesh *mesh = smgr->getMesh(rfile);
2736         rfile->drop();
2737         // NOTE: By playing with Irrlicht refcounts, maybe we could cache a bunch
2738         // of uniquely named instances and re-use them
2739         mesh->grab();
2740         smgr->getMeshCache()->removeMesh(mesh);
2741         return mesh;
2742 }
2743