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