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