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