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