]> git.lizzy.rs Git - dragonfireclient.git/blob - src/client.cpp
f02c14bc8894e967b0b81fe65e17c2f6b9d97fb5
[dragonfireclient.git] / src / client.cpp
1 /*
2 Minetest
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_MOVEMENT)
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
1524                 player->movement_acceleration_default = readF1000(is) * BS;
1525                 player->movement_acceleration_air = readF1000(is) * BS;
1526                 player->movement_acceleration_fast = readF1000(is) * BS;
1527                 player->movement_speed_walk = readF1000(is) * BS;
1528                 player->movement_speed_crouch = readF1000(is) * BS;
1529                 player->movement_speed_fast = readF1000(is) * BS;
1530                 player->movement_speed_climb = readF1000(is) * BS;
1531                 player->movement_speed_jump = readF1000(is) * BS;
1532                 player->movement_liquid_fluidity = readF1000(is) * BS;
1533                 player->movement_liquid_fluidity_smooth = readF1000(is) * BS;
1534                 player->movement_liquid_sink = readF1000(is) * BS;
1535                 player->movement_gravity = readF1000(is) * BS;
1536         }
1537         else if(command == TOCLIENT_HP)
1538         {
1539                 std::string datastring((char*)&data[2], datasize-2);
1540                 std::istringstream is(datastring, std::ios_base::binary);
1541                 Player *player = m_env.getLocalPlayer();
1542                 assert(player != NULL);
1543                 u8 oldhp = player->hp;
1544                 u8 hp = readU8(is);
1545                 player->hp = hp;
1546
1547                 if(hp < oldhp)
1548                 {
1549                         // Add to ClientEvent queue
1550                         ClientEvent event;
1551                         event.type = CE_PLAYER_DAMAGE;
1552                         event.player_damage.amount = oldhp - hp;
1553                         m_client_event_queue.push_back(event);
1554                 }
1555         }
1556         else if(command == TOCLIENT_MOVE_PLAYER)
1557         {
1558                 std::string datastring((char*)&data[2], datasize-2);
1559                 std::istringstream is(datastring, std::ios_base::binary);
1560                 Player *player = m_env.getLocalPlayer();
1561                 assert(player != NULL);
1562                 v3f pos = readV3F1000(is);
1563                 f32 pitch = readF1000(is);
1564                 f32 yaw = readF1000(is);
1565                 player->setPosition(pos);
1566                 /*player->setPitch(pitch);
1567                 player->setYaw(yaw);*/
1568
1569                 infostream<<"Client got TOCLIENT_MOVE_PLAYER"
1570                                 <<" pos=("<<pos.X<<","<<pos.Y<<","<<pos.Z<<")"
1571                                 <<" pitch="<<pitch
1572                                 <<" yaw="<<yaw
1573                                 <<std::endl;
1574
1575                 /*
1576                         Add to ClientEvent queue.
1577                         This has to be sent to the main program because otherwise
1578                         it would just force the pitch and yaw values to whatever
1579                         the camera points to.
1580                 */
1581                 ClientEvent event;
1582                 event.type = CE_PLAYER_FORCE_MOVE;
1583                 event.player_force_move.pitch = pitch;
1584                 event.player_force_move.yaw = yaw;
1585                 m_client_event_queue.push_back(event);
1586
1587                 // Ignore damage for a few seconds, so that the player doesn't
1588                 // get damage from falling on ground
1589                 m_ignore_damage_timer = 3.0;
1590         }
1591         else if(command == TOCLIENT_PLAYERITEM)
1592         {
1593                 infostream<<"Client: WARNING: Ignoring TOCLIENT_PLAYERITEM"<<std::endl;
1594         }
1595         else if(command == TOCLIENT_DEATHSCREEN)
1596         {
1597                 std::string datastring((char*)&data[2], datasize-2);
1598                 std::istringstream is(datastring, std::ios_base::binary);
1599                 
1600                 bool set_camera_point_target = readU8(is);
1601                 v3f camera_point_target = readV3F1000(is);
1602                 
1603                 ClientEvent event;
1604                 event.type = CE_DEATHSCREEN;
1605                 event.deathscreen.set_camera_point_target = set_camera_point_target;
1606                 event.deathscreen.camera_point_target_x = camera_point_target.X;
1607                 event.deathscreen.camera_point_target_y = camera_point_target.Y;
1608                 event.deathscreen.camera_point_target_z = camera_point_target.Z;
1609                 m_client_event_queue.push_back(event);
1610         }
1611         else if(command == TOCLIENT_ANNOUNCE_MEDIA)
1612         {
1613                 std::string datastring((char*)&data[2], datasize-2);
1614                 std::istringstream is(datastring, std::ios_base::binary);
1615
1616                 // Mesh update thread must be stopped while
1617                 // updating content definitions
1618                 assert(!m_mesh_update_thread.IsRunning());
1619
1620                 int num_files = readU16(is);
1621                 
1622                 infostream<<"Client: Received media announcement: packet size: "
1623                                 <<datasize<<std::endl;
1624
1625                 core::list<MediaRequest> file_requests;
1626
1627                 for(int i=0; i<num_files; i++)
1628                 {
1629                         //read file from cache
1630                         std::string name = deSerializeString(is);
1631                         std::string sha1_base64 = deSerializeString(is);
1632
1633                         // if name contains illegal characters, ignore the file
1634                         if(!string_allowed(name, TEXTURENAME_ALLOWED_CHARS)){
1635                                 errorstream<<"Client: ignoring illegal file name "
1636                                                 <<"sent by server: \""<<name<<"\""<<std::endl;
1637                                 continue;
1638                         }
1639
1640                         std::string sha1_raw = base64_decode(sha1_base64);
1641                         std::string sha1_hex = hex_encode(sha1_raw);
1642                         std::ostringstream tmp_os(std::ios_base::binary);
1643                         bool found_in_cache = m_media_cache.load_sha1(sha1_raw, tmp_os);
1644                         m_media_name_sha1_map.set(name, sha1_raw);
1645
1646                         // If found in cache, try to load it from there
1647                         if(found_in_cache)
1648                         {
1649                                 bool success = loadMedia(tmp_os.str(), name);
1650                                 if(success){
1651                                         verbosestream<<"Client: Loaded cached media: "
1652                                                         <<sha1_hex<<" \""<<name<<"\""<<std::endl;
1653                                         continue;
1654                                 } else{
1655                                         infostream<<"Client: Failed to load cached media: "
1656                                                         <<sha1_hex<<" \""<<name<<"\""<<std::endl;
1657                                 }
1658                         }
1659                         // Didn't load from cache; queue it to be requested
1660                         verbosestream<<"Client: Adding file to request list: \""
1661                                         <<sha1_hex<<" \""<<name<<"\""<<std::endl;
1662                         file_requests.push_back(MediaRequest(name));
1663                 }
1664
1665                 std::string remote_media = "";
1666                 try {
1667                         remote_media = deSerializeString(is);
1668                 }
1669                 catch(SerializationError) {
1670                         // not supported by server or turned off
1671                 }
1672
1673                 m_media_count = file_requests.size();
1674                 m_media_receive_started = true;
1675
1676                 if (remote_media == "" || !USE_CURL) {
1677                         request_media(file_requests);
1678                 } else {
1679                         #if USE_CURL
1680                         core::list<MediaFetchThread*>::Iterator cur = m_media_fetch_threads.begin();
1681                         for(core::list<MediaRequest>::Iterator i = file_requests.begin();
1682                                         i != file_requests.end(); i++) {
1683                                 (*cur)->m_file_requests.push_back(*i);
1684                                 cur++;
1685                                 if (cur == m_media_fetch_threads.end())
1686                                         cur = m_media_fetch_threads.begin();
1687                         }
1688                         for (core::list<MediaFetchThread*>::Iterator i = m_media_fetch_threads.begin();
1689                                         i != m_media_fetch_threads.end(); i++) {
1690                                 (*i)->m_remote_url = remote_media;
1691                                 (*i)->Start();
1692                         }
1693                         #endif
1694
1695                         // notify server we received everything
1696                         std::ostringstream os(std::ios_base::binary);
1697                         writeU16(os, TOSERVER_RECEIVED_MEDIA);
1698                         std::string s = os.str();
1699                         SharedBuffer<u8> data((u8*)s.c_str(), s.size());
1700                         // Send as reliable
1701                         Send(0, data, true);
1702                 }
1703                 ClientEvent event;
1704                 event.type = CE_TEXTURES_UPDATED;
1705                 m_client_event_queue.push_back(event);
1706         }
1707         else if(command == TOCLIENT_MEDIA)
1708         {
1709                 if (m_media_count == 0)
1710                         return;
1711                 std::string datastring((char*)&data[2], datasize-2);
1712                 std::istringstream is(datastring, std::ios_base::binary);
1713
1714                 // Mesh update thread must be stopped while
1715                 // updating content definitions
1716                 assert(!m_mesh_update_thread.IsRunning());
1717
1718                 /*
1719                         u16 command
1720                         u16 total number of file bunches
1721                         u16 index of this bunch
1722                         u32 number of files in this bunch
1723                         for each file {
1724                                 u16 length of name
1725                                 string name
1726                                 u32 length of data
1727                                 data
1728                         }
1729                 */
1730                 int num_bunches = readU16(is);
1731                 int bunch_i = readU16(is);
1732                 int num_files = readU32(is);
1733                 infostream<<"Client: Received files: bunch "<<bunch_i<<"/"
1734                                 <<num_bunches<<" files="<<num_files
1735                                 <<" size="<<datasize<<std::endl;
1736                 for(int i=0; i<num_files; i++){
1737                         m_media_received_count++;
1738                         std::string name = deSerializeString(is);
1739                         std::string data = deSerializeLongString(is);
1740
1741                         // if name contains illegal characters, ignore the file
1742                         if(!string_allowed(name, TEXTURENAME_ALLOWED_CHARS)){
1743                                 errorstream<<"Client: ignoring illegal file name "
1744                                                 <<"sent by server: \""<<name<<"\""<<std::endl;
1745                                 continue;
1746                         }
1747                         
1748                         bool success = loadMedia(data, name);
1749                         if(success){
1750                                 verbosestream<<"Client: Loaded received media: "
1751                                                 <<"\""<<name<<"\". Caching."<<std::endl;
1752                         } else{
1753                                 infostream<<"Client: Failed to load received media: "
1754                                                 <<"\""<<name<<"\". Not caching."<<std::endl;
1755                                 continue;
1756                         }
1757
1758                         bool did = fs::CreateAllDirs(getMediaCacheDir());
1759                         if(!did){
1760                                 errorstream<<"Could not create media cache directory"
1761                                                 <<std::endl;
1762                         }
1763
1764                         {
1765                                 core::map<std::string, std::string>::Node *n;
1766                                 n = m_media_name_sha1_map.find(name);
1767                                 if(n == NULL)
1768                                         errorstream<<"The server sent a file that has not "
1769                                                         <<"been announced."<<std::endl;
1770                                 else
1771                                         m_media_cache.update_sha1(data);
1772                         }
1773                 }
1774
1775                 ClientEvent event;
1776                 event.type = CE_TEXTURES_UPDATED;
1777                 m_client_event_queue.push_back(event);
1778         }
1779         else if(command == TOCLIENT_TOOLDEF)
1780         {
1781                 infostream<<"Client: WARNING: Ignoring TOCLIENT_TOOLDEF"<<std::endl;
1782         }
1783         else if(command == TOCLIENT_NODEDEF)
1784         {
1785                 infostream<<"Client: Received node definitions: packet size: "
1786                                 <<datasize<<std::endl;
1787
1788                 // Mesh update thread must be stopped while
1789                 // updating content definitions
1790                 assert(!m_mesh_update_thread.IsRunning());
1791
1792                 // Decompress node definitions
1793                 std::string datastring((char*)&data[2], datasize-2);
1794                 std::istringstream is(datastring, std::ios_base::binary);
1795                 std::istringstream tmp_is(deSerializeLongString(is), std::ios::binary);
1796                 std::ostringstream tmp_os;
1797                 decompressZlib(tmp_is, tmp_os);
1798
1799                 // Deserialize node definitions
1800                 std::istringstream tmp_is2(tmp_os.str());
1801                 m_nodedef->deSerialize(tmp_is2);
1802                 m_nodedef_received = true;
1803         }
1804         else if(command == TOCLIENT_CRAFTITEMDEF)
1805         {
1806                 infostream<<"Client: WARNING: Ignoring TOCLIENT_CRAFTITEMDEF"<<std::endl;
1807         }
1808         else if(command == TOCLIENT_ITEMDEF)
1809         {
1810                 infostream<<"Client: Received item definitions: packet size: "
1811                                 <<datasize<<std::endl;
1812
1813                 // Mesh update thread must be stopped while
1814                 // updating content definitions
1815                 assert(!m_mesh_update_thread.IsRunning());
1816
1817                 // Decompress item definitions
1818                 std::string datastring((char*)&data[2], datasize-2);
1819                 std::istringstream is(datastring, std::ios_base::binary);
1820                 std::istringstream tmp_is(deSerializeLongString(is), std::ios::binary);
1821                 std::ostringstream tmp_os;
1822                 decompressZlib(tmp_is, tmp_os);
1823
1824                 // Deserialize node definitions
1825                 std::istringstream tmp_is2(tmp_os.str());
1826                 m_itemdef->deSerialize(tmp_is2);
1827                 m_itemdef_received = true;
1828         }
1829         else if(command == TOCLIENT_PLAY_SOUND)
1830         {
1831                 std::string datastring((char*)&data[2], datasize-2);
1832                 std::istringstream is(datastring, std::ios_base::binary);
1833
1834                 s32 server_id = readS32(is);
1835                 std::string name = deSerializeString(is);
1836                 float gain = readF1000(is);
1837                 int type = readU8(is); // 0=local, 1=positional, 2=object
1838                 v3f pos = readV3F1000(is);
1839                 u16 object_id = readU16(is);
1840                 bool loop = readU8(is);
1841                 // Start playing
1842                 int client_id = -1;
1843                 switch(type){
1844                 case 0: // local
1845                         client_id = m_sound->playSound(name, loop, gain);
1846                         break;
1847                 case 1: // positional
1848                         client_id = m_sound->playSoundAt(name, loop, gain, pos);
1849                         break;
1850                 case 2: { // object
1851                         ClientActiveObject *cao = m_env.getActiveObject(object_id);
1852                         if(cao)
1853                                 pos = cao->getPosition();
1854                         client_id = m_sound->playSoundAt(name, loop, gain, pos);
1855                         // TODO: Set up sound to move with object
1856                         break; }
1857                 default:
1858                         break;
1859                 }
1860                 if(client_id != -1){
1861                         m_sounds_server_to_client[server_id] = client_id;
1862                         m_sounds_client_to_server[client_id] = server_id;
1863                         if(object_id != 0)
1864                                 m_sounds_to_objects[client_id] = object_id;
1865                 }
1866         }
1867         else if(command == TOCLIENT_STOP_SOUND)
1868         {
1869                 std::string datastring((char*)&data[2], datasize-2);
1870                 std::istringstream is(datastring, std::ios_base::binary);
1871
1872                 s32 server_id = readS32(is);
1873                 std::map<s32, int>::iterator i =
1874                                 m_sounds_server_to_client.find(server_id);
1875                 if(i != m_sounds_server_to_client.end()){
1876                         int client_id = i->second;
1877                         m_sound->stopSound(client_id);
1878                 }
1879         }
1880         else if(command == TOCLIENT_PRIVILEGES)
1881         {
1882                 std::string datastring((char*)&data[2], datasize-2);
1883                 std::istringstream is(datastring, std::ios_base::binary);
1884                 
1885                 m_privileges.clear();
1886                 infostream<<"Client: Privileges updated: ";
1887                 u16 num_privileges = readU16(is);
1888                 for(u16 i=0; i<num_privileges; i++){
1889                         std::string priv = deSerializeString(is);
1890                         m_privileges.insert(priv);
1891                         infostream<<priv<<" ";
1892                 }
1893                 infostream<<std::endl;
1894         }
1895         else if(command == TOCLIENT_INVENTORY_FORMSPEC)
1896         {
1897                 std::string datastring((char*)&data[2], datasize-2);
1898                 std::istringstream is(datastring, std::ios_base::binary);
1899
1900                 // Store formspec in LocalPlayer
1901                 Player *player = m_env.getLocalPlayer();
1902                 assert(player != NULL);
1903                 player->inventory_formspec = deSerializeLongString(is);
1904         }
1905         else if(command == TOCLIENT_DETACHED_INVENTORY)
1906         {
1907                 std::string datastring((char*)&data[2], datasize-2);
1908                 std::istringstream is(datastring, std::ios_base::binary);
1909
1910                 std::string name = deSerializeString(is);
1911                 
1912                 infostream<<"Client: Detached inventory update: \""<<name<<"\""<<std::endl;
1913
1914                 Inventory *inv = NULL;
1915                 if(m_detached_inventories.count(name) > 0)
1916                         inv = m_detached_inventories[name];
1917                 else{
1918                         inv = new Inventory(m_itemdef);
1919                         m_detached_inventories[name] = inv;
1920                 }
1921                 inv->deSerialize(is);
1922         }
1923         else if(command == TOCLIENT_SHOW_FORMSPEC)
1924         {
1925                 std::string datastring((char*)&data[2], datasize-2);
1926                 std::istringstream is(datastring, std::ios_base::binary);
1927
1928                 std::string formspec = deSerializeLongString(is);
1929                 std::string formname = deSerializeString(is);
1930
1931                 ClientEvent event;
1932                 event.type = CE_SHOW_FORMSPEC;
1933                 // pointer is required as event is a struct only!
1934                 // adding a std:string to a struct isn't possible
1935                 event.show_formspec.formspec = new std::string(formspec);
1936                 event.show_formspec.formname = new std::string(formname);
1937                 m_client_event_queue.push_back(event);
1938         }
1939         else
1940         {
1941                 infostream<<"Client: Ignoring unknown command "
1942                                 <<command<<std::endl;
1943         }
1944 }
1945
1946 void Client::Send(u16 channelnum, SharedBuffer<u8> data, bool reliable)
1947 {
1948         //JMutexAutoLock lock(m_con_mutex); //bulk comment-out
1949         m_con.Send(PEER_ID_SERVER, channelnum, data, reliable);
1950 }
1951
1952 void Client::interact(u8 action, const PointedThing& pointed)
1953 {
1954         if(connectedAndInitialized() == false){
1955                 infostream<<"Client::interact() "
1956                                 "cancelled (not connected)"
1957                                 <<std::endl;
1958                 return;
1959         }
1960
1961         std::ostringstream os(std::ios_base::binary);
1962
1963         /*
1964                 [0] u16 command
1965                 [2] u8 action
1966                 [3] u16 item
1967                 [5] u32 length of the next item
1968                 [9] serialized PointedThing
1969                 actions:
1970                 0: start digging (from undersurface) or use
1971                 1: stop digging (all parameters ignored)
1972                 2: digging completed
1973                 3: place block or item (to abovesurface)
1974                 4: use item
1975         */
1976         writeU16(os, TOSERVER_INTERACT);
1977         writeU8(os, action);
1978         writeU16(os, getPlayerItem());
1979         std::ostringstream tmp_os(std::ios::binary);
1980         pointed.serialize(tmp_os);
1981         os<<serializeLongString(tmp_os.str());
1982
1983         std::string s = os.str();
1984         SharedBuffer<u8> data((u8*)s.c_str(), s.size());
1985
1986         // Send as reliable
1987         Send(0, data, true);
1988 }
1989
1990 void Client::sendNodemetaFields(v3s16 p, const std::string &formname,
1991                 const std::map<std::string, std::string> &fields)
1992 {
1993         std::ostringstream os(std::ios_base::binary);
1994
1995         writeU16(os, TOSERVER_NODEMETA_FIELDS);
1996         writeV3S16(os, p);
1997         os<<serializeString(formname);
1998         writeU16(os, fields.size());
1999         for(std::map<std::string, std::string>::const_iterator
2000                         i = fields.begin(); i != fields.end(); i++){
2001                 const std::string &name = i->first;
2002                 const std::string &value = i->second;
2003                 os<<serializeString(name);
2004                 os<<serializeLongString(value);
2005         }
2006
2007         // Make data buffer
2008         std::string s = os.str();
2009         SharedBuffer<u8> data((u8*)s.c_str(), s.size());
2010         // Send as reliable
2011         Send(0, data, true);
2012 }
2013         
2014 void Client::sendInventoryFields(const std::string &formname, 
2015                 const std::map<std::string, std::string> &fields)
2016 {
2017         std::ostringstream os(std::ios_base::binary);
2018
2019         writeU16(os, TOSERVER_INVENTORY_FIELDS);
2020         os<<serializeString(formname);
2021         writeU16(os, fields.size());
2022         for(std::map<std::string, std::string>::const_iterator
2023                         i = fields.begin(); i != fields.end(); i++){
2024                 const std::string &name = i->first;
2025                 const std::string &value = i->second;
2026                 os<<serializeString(name);
2027                 os<<serializeLongString(value);
2028         }
2029
2030         // Make data buffer
2031         std::string s = os.str();
2032         SharedBuffer<u8> data((u8*)s.c_str(), s.size());
2033         // Send as reliable
2034         Send(0, data, true);
2035 }
2036
2037 void Client::sendInventoryAction(InventoryAction *a)
2038 {
2039         std::ostringstream os(std::ios_base::binary);
2040         u8 buf[12];
2041         
2042         // Write command
2043         writeU16(buf, TOSERVER_INVENTORY_ACTION);
2044         os.write((char*)buf, 2);
2045
2046         a->serialize(os);
2047         
2048         // Make data buffer
2049         std::string s = os.str();
2050         SharedBuffer<u8> data((u8*)s.c_str(), s.size());
2051         // Send as reliable
2052         Send(0, data, true);
2053 }
2054
2055 void Client::sendChatMessage(const std::wstring &message)
2056 {
2057         std::ostringstream os(std::ios_base::binary);
2058         u8 buf[12];
2059         
2060         // Write command
2061         writeU16(buf, TOSERVER_CHAT_MESSAGE);
2062         os.write((char*)buf, 2);
2063         
2064         // Write length
2065         writeU16(buf, message.size());
2066         os.write((char*)buf, 2);
2067         
2068         // Write string
2069         for(u32 i=0; i<message.size(); i++)
2070         {
2071                 u16 w = message[i];
2072                 writeU16(buf, w);
2073                 os.write((char*)buf, 2);
2074         }
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 void Client::sendChangePassword(const std::wstring oldpassword,
2084                 const std::wstring newpassword)
2085 {
2086         Player *player = m_env.getLocalPlayer();
2087         if(player == NULL)
2088                 return;
2089
2090         std::string playername = player->getName();
2091         std::string oldpwd = translatePassword(playername, oldpassword);
2092         std::string newpwd = translatePassword(playername, newpassword);
2093
2094         std::ostringstream os(std::ios_base::binary);
2095         u8 buf[2+PASSWORD_SIZE*2];
2096         /*
2097                 [0] u16 TOSERVER_PASSWORD
2098                 [2] u8[28] old password
2099                 [30] u8[28] new password
2100         */
2101
2102         writeU16(buf, TOSERVER_PASSWORD);
2103         for(u32 i=0;i<PASSWORD_SIZE-1;i++)
2104         {
2105                 buf[2+i] = i<oldpwd.length()?oldpwd[i]:0;
2106                 buf[30+i] = i<newpwd.length()?newpwd[i]:0;
2107         }
2108         buf[2+PASSWORD_SIZE-1] = 0;
2109         buf[30+PASSWORD_SIZE-1] = 0;
2110         os.write((char*)buf, 2+PASSWORD_SIZE*2);
2111
2112         // Make data buffer
2113         std::string s = os.str();
2114         SharedBuffer<u8> data((u8*)s.c_str(), s.size());
2115         // Send as reliable
2116         Send(0, data, true);
2117 }
2118
2119
2120 void Client::sendDamage(u8 damage)
2121 {
2122         DSTACK(__FUNCTION_NAME);
2123         std::ostringstream os(std::ios_base::binary);
2124
2125         writeU16(os, TOSERVER_DAMAGE);
2126         writeU8(os, damage);
2127
2128         // Make data buffer
2129         std::string s = os.str();
2130         SharedBuffer<u8> data((u8*)s.c_str(), s.size());
2131         // Send as reliable
2132         Send(0, data, true);
2133 }
2134
2135 void Client::sendRespawn()
2136 {
2137         DSTACK(__FUNCTION_NAME);
2138         std::ostringstream os(std::ios_base::binary);
2139
2140         writeU16(os, TOSERVER_RESPAWN);
2141
2142         // Make data buffer
2143         std::string s = os.str();
2144         SharedBuffer<u8> data((u8*)s.c_str(), s.size());
2145         // Send as reliable
2146         Send(0, data, true);
2147 }
2148
2149 void Client::sendPlayerPos()
2150 {
2151         //JMutexAutoLock envlock(m_env_mutex); //bulk comment-out
2152         
2153         LocalPlayer *myplayer = m_env.getLocalPlayer();
2154         if(myplayer == NULL)
2155                 return;
2156
2157         // Save bandwidth by only updating position when something changed
2158         if(myplayer->last_position == myplayer->getPosition() &&
2159                         myplayer->last_speed == myplayer->getSpeed() &&
2160                         myplayer->last_pitch == myplayer->getPitch() &&
2161                         myplayer->last_yaw == myplayer->getYaw() &&
2162                         myplayer->last_keyPressed == myplayer->keyPressed)
2163                 return;
2164
2165         myplayer->last_position = myplayer->getPosition();
2166         myplayer->last_speed = myplayer->getSpeed();
2167         myplayer->last_pitch = myplayer->getPitch();
2168         myplayer->last_yaw = myplayer->getYaw();
2169         myplayer->last_keyPressed = myplayer->keyPressed;
2170
2171         u16 our_peer_id;
2172         {
2173                 //JMutexAutoLock lock(m_con_mutex); //bulk comment-out
2174                 our_peer_id = m_con.GetPeerID();
2175         }
2176         
2177         // Set peer id if not set already
2178         if(myplayer->peer_id == PEER_ID_INEXISTENT)
2179                 myplayer->peer_id = our_peer_id;
2180         // Check that an existing peer_id is the same as the connection's
2181         assert(myplayer->peer_id == our_peer_id);
2182         
2183         v3f pf = myplayer->getPosition();
2184         v3s32 position(pf.X*100, pf.Y*100, pf.Z*100);
2185         v3f sf = myplayer->getSpeed();
2186         v3s32 speed(sf.X*100, sf.Y*100, sf.Z*100);
2187         s32 pitch = myplayer->getPitch() * 100;
2188         s32 yaw = myplayer->getYaw() * 100;
2189         u32 keyPressed=myplayer->keyPressed;
2190         /*
2191                 Format:
2192                 [0] u16 command
2193                 [2] v3s32 position*100
2194                 [2+12] v3s32 speed*100
2195                 [2+12+12] s32 pitch*100
2196                 [2+12+12+4] s32 yaw*100
2197                 [2+12+12+4+4] u32 keyPressed
2198         */
2199         SharedBuffer<u8> data(2+12+12+4+4+4);
2200         writeU16(&data[0], TOSERVER_PLAYERPOS);
2201         writeV3S32(&data[2], position);
2202         writeV3S32(&data[2+12], speed);
2203         writeS32(&data[2+12+12], pitch);
2204         writeS32(&data[2+12+12+4], yaw);        
2205         writeU32(&data[2+12+12+4+4], keyPressed);
2206         // Send as unreliable
2207         Send(0, data, false);
2208 }
2209
2210 void Client::sendPlayerItem(u16 item)
2211 {
2212         Player *myplayer = m_env.getLocalPlayer();
2213         if(myplayer == NULL)
2214                 return;
2215
2216         u16 our_peer_id = m_con.GetPeerID();
2217
2218         // Set peer id if not set already
2219         if(myplayer->peer_id == PEER_ID_INEXISTENT)
2220                 myplayer->peer_id = our_peer_id;
2221         // Check that an existing peer_id is the same as the connection's
2222         assert(myplayer->peer_id == our_peer_id);
2223
2224         SharedBuffer<u8> data(2+2);
2225         writeU16(&data[0], TOSERVER_PLAYERITEM);
2226         writeU16(&data[2], item);
2227
2228         // Send as reliable
2229         Send(0, data, true);
2230 }
2231
2232 void Client::removeNode(v3s16 p)
2233 {
2234         core::map<v3s16, MapBlock*> modified_blocks;
2235
2236         try
2237         {
2238                 //TimeTaker t("removeNodeAndUpdate", m_device);
2239                 m_env.getMap().removeNodeAndUpdate(p, modified_blocks);
2240         }
2241         catch(InvalidPositionException &e)
2242         {
2243         }
2244         
2245         // add urgent task to update the modified node
2246         addUpdateMeshTaskForNode(p, false, true);
2247
2248         for(core::map<v3s16, MapBlock * >::Iterator
2249                         i = modified_blocks.getIterator();
2250                         i.atEnd() == false; i++)
2251         {
2252                 v3s16 p = i.getNode()->getKey();
2253                 addUpdateMeshTaskWithEdge(p);
2254         }
2255 }
2256
2257 void Client::addNode(v3s16 p, MapNode n)
2258 {
2259         TimeTaker timer1("Client::addNode()");
2260
2261         core::map<v3s16, MapBlock*> modified_blocks;
2262
2263         try
2264         {
2265                 //TimeTaker timer3("Client::addNode(): addNodeAndUpdate");
2266                 m_env.getMap().addNodeAndUpdate(p, n, modified_blocks);
2267         }
2268         catch(InvalidPositionException &e)
2269         {}
2270         
2271         for(core::map<v3s16, MapBlock * >::Iterator
2272                         i = modified_blocks.getIterator();
2273                         i.atEnd() == false; i++)
2274         {
2275                 v3s16 p = i.getNode()->getKey();
2276                 addUpdateMeshTaskWithEdge(p);
2277         }
2278 }
2279         
2280 void Client::setPlayerControl(PlayerControl &control)
2281 {
2282         //JMutexAutoLock envlock(m_env_mutex); //bulk comment-out
2283         LocalPlayer *player = m_env.getLocalPlayer();
2284         assert(player != NULL);
2285         player->control = control;
2286 }
2287
2288 void Client::selectPlayerItem(u16 item)
2289 {
2290         //JMutexAutoLock envlock(m_env_mutex); //bulk comment-out
2291         m_playeritem = item;
2292         m_inventory_updated = true;
2293         sendPlayerItem(item);
2294 }
2295
2296 // Returns true if the inventory of the local player has been
2297 // updated from the server. If it is true, it is set to false.
2298 bool Client::getLocalInventoryUpdated()
2299 {
2300         // m_inventory_updated is behind envlock
2301         //JMutexAutoLock envlock(m_env_mutex); //bulk comment-out
2302         bool updated = m_inventory_updated;
2303         m_inventory_updated = false;
2304         return updated;
2305 }
2306
2307 // Copies the inventory of the local player to parameter
2308 void Client::getLocalInventory(Inventory &dst)
2309 {
2310         //JMutexAutoLock envlock(m_env_mutex); //bulk comment-out
2311         Player *player = m_env.getLocalPlayer();
2312         assert(player != NULL);
2313         dst = player->inventory;
2314 }
2315
2316 Inventory* Client::getInventory(const InventoryLocation &loc)
2317 {
2318         switch(loc.type){
2319         case InventoryLocation::UNDEFINED:
2320         {}
2321         break;
2322         case InventoryLocation::CURRENT_PLAYER:
2323         {
2324                 Player *player = m_env.getLocalPlayer();
2325                 assert(player != NULL);
2326                 return &player->inventory;
2327         }
2328         break;
2329         case InventoryLocation::PLAYER:
2330         {
2331                 Player *player = m_env.getPlayer(loc.name.c_str());
2332                 if(!player)
2333                         return NULL;
2334                 return &player->inventory;
2335         }
2336         break;
2337         case InventoryLocation::NODEMETA:
2338         {
2339                 NodeMetadata *meta = m_env.getMap().getNodeMetadata(loc.p);
2340                 if(!meta)
2341                         return NULL;
2342                 return meta->getInventory();
2343         }
2344         break;
2345         case InventoryLocation::DETACHED:
2346         {
2347                 if(m_detached_inventories.count(loc.name) == 0)
2348                         return NULL;
2349                 return m_detached_inventories[loc.name];
2350         }
2351         break;
2352         default:
2353                 assert(0);
2354         }
2355         return NULL;
2356 }
2357 void Client::inventoryAction(InventoryAction *a)
2358 {
2359         /*
2360                 Send it to the server
2361         */
2362         sendInventoryAction(a);
2363
2364         /*
2365                 Predict some local inventory changes
2366         */
2367         a->clientApply(this, this);
2368 }
2369
2370 ClientActiveObject * Client::getSelectedActiveObject(
2371                 f32 max_d,
2372                 v3f from_pos_f_on_map,
2373                 core::line3d<f32> shootline_on_map
2374         )
2375 {
2376         core::array<DistanceSortedActiveObject> objects;
2377
2378         m_env.getActiveObjects(from_pos_f_on_map, max_d, objects);
2379
2380         //infostream<<"Collected "<<objects.size()<<" nearby objects"<<std::endl;
2381         
2382         // Sort them.
2383         // After this, the closest object is the first in the array.
2384         objects.sort();
2385
2386         for(u32 i=0; i<objects.size(); i++)
2387         {
2388                 ClientActiveObject *obj = objects[i].obj;
2389                 
2390                 core::aabbox3d<f32> *selection_box = obj->getSelectionBox();
2391                 if(selection_box == NULL)
2392                         continue;
2393
2394                 v3f pos = obj->getPosition();
2395
2396                 core::aabbox3d<f32> offsetted_box(
2397                                 selection_box->MinEdge + pos,
2398                                 selection_box->MaxEdge + pos
2399                 );
2400
2401                 if(offsetted_box.intersectsWithLine(shootline_on_map))
2402                 {
2403                         //infostream<<"Returning selected object"<<std::endl;
2404                         return obj;
2405                 }
2406         }
2407
2408         //infostream<<"No object selected; returning NULL."<<std::endl;
2409         return NULL;
2410 }
2411
2412 void Client::printDebugInfo(std::ostream &os)
2413 {
2414         //JMutexAutoLock lock1(m_fetchblock_mutex);
2415         /*JMutexAutoLock lock2(m_incoming_queue_mutex);
2416
2417         os<<"m_incoming_queue.getSize()="<<m_incoming_queue.getSize()
2418                 //<<", m_fetchblock_history.size()="<<m_fetchblock_history.size()
2419                 //<<", m_opt_not_found_history.size()="<<m_opt_not_found_history.size()
2420                 <<std::endl;*/
2421 }
2422
2423 core::list<std::wstring> Client::getConnectedPlayerNames()
2424 {
2425         core::list<Player*> players = m_env.getPlayers(true);
2426         core::list<std::wstring> playerNames;
2427         for(core::list<Player*>::Iterator
2428                         i = players.begin();
2429                         i != players.end(); i++)
2430         {
2431                 Player *player = *i;
2432                 playerNames.push_back(narrow_to_wide(player->getName()));
2433         }
2434         return playerNames;
2435 }
2436
2437 float Client::getAnimationTime()
2438 {
2439         return m_animation_time;
2440 }
2441
2442 int Client::getCrackLevel()
2443 {
2444         return m_crack_level;
2445 }
2446
2447 void Client::setCrack(int level, v3s16 pos)
2448 {
2449         int old_crack_level = m_crack_level;
2450         v3s16 old_crack_pos = m_crack_pos;
2451
2452         m_crack_level = level;
2453         m_crack_pos = pos;
2454
2455         if(old_crack_level >= 0 && (level < 0 || pos != old_crack_pos))
2456         {
2457                 // remove old crack
2458                 addUpdateMeshTaskForNode(old_crack_pos, false, true);
2459         }
2460         if(level >= 0 && (old_crack_level < 0 || pos != old_crack_pos))
2461         {
2462                 // add new crack
2463                 addUpdateMeshTaskForNode(pos, false, true);
2464         }
2465 }
2466
2467 u16 Client::getHP()
2468 {
2469         Player *player = m_env.getLocalPlayer();
2470         assert(player != NULL);
2471         return player->hp;
2472 }
2473
2474 bool Client::getChatMessage(std::wstring &message)
2475 {
2476         if(m_chat_queue.size() == 0)
2477                 return false;
2478         message = m_chat_queue.pop_front();
2479         return true;
2480 }
2481
2482 void Client::typeChatMessage(const std::wstring &message)
2483 {
2484         // Discard empty line
2485         if(message == L"")
2486                 return;
2487
2488         // Send to others
2489         sendChatMessage(message);
2490
2491         // Show locally
2492         if (message[0] == L'/')
2493         {
2494                 m_chat_queue.push_back(
2495                                 (std::wstring)L"issued command: "+message);
2496         }
2497         else
2498         {
2499                 LocalPlayer *player = m_env.getLocalPlayer();
2500                 assert(player != NULL);
2501                 std::wstring name = narrow_to_wide(player->getName());
2502                 m_chat_queue.push_back(
2503                                 (std::wstring)L"<"+name+L"> "+message);
2504         }
2505 }
2506
2507 void Client::addUpdateMeshTask(v3s16 p, bool ack_to_server, bool urgent)
2508 {
2509         /*infostream<<"Client::addUpdateMeshTask(): "
2510                         <<"("<<p.X<<","<<p.Y<<","<<p.Z<<")"
2511                         <<" ack_to_server="<<ack_to_server
2512                         <<" urgent="<<urgent
2513                         <<std::endl;*/
2514
2515         MapBlock *b = m_env.getMap().getBlockNoCreateNoEx(p);
2516         if(b == NULL)
2517                 return;
2518         
2519         /*
2520                 Create a task to update the mesh of the block
2521         */
2522         
2523         MeshMakeData *data = new MeshMakeData(this);
2524         
2525         {
2526                 //TimeTaker timer("data fill");
2527                 // Release: ~0ms
2528                 // Debug: 1-6ms, avg=2ms
2529                 data->fill(b);
2530                 data->setCrack(m_crack_level, m_crack_pos);
2531                 data->setSmoothLighting(g_settings->getBool("smooth_lighting"));
2532         }
2533
2534         // Debug wait
2535         //while(m_mesh_update_thread.m_queue_in.size() > 0) sleep_ms(10);
2536         
2537         // Add task to queue
2538         m_mesh_update_thread.m_queue_in.addBlock(p, data, ack_to_server, urgent);
2539
2540         /*infostream<<"Mesh update input queue size is "
2541                         <<m_mesh_update_thread.m_queue_in.size()
2542                         <<std::endl;*/
2543 }
2544
2545 void Client::addUpdateMeshTaskWithEdge(v3s16 blockpos, bool ack_to_server, bool urgent)
2546 {
2547         /*{
2548                 v3s16 p = blockpos;
2549                 infostream<<"Client::addUpdateMeshTaskWithEdge(): "
2550                                 <<"("<<p.X<<","<<p.Y<<","<<p.Z<<")"
2551                                 <<std::endl;
2552         }*/
2553
2554         try{
2555                 v3s16 p = blockpos + v3s16(0,0,0);
2556                 //MapBlock *b = m_env.getMap().getBlockNoCreate(p);
2557                 addUpdateMeshTask(p, ack_to_server, urgent);
2558         }
2559         catch(InvalidPositionException &e){}
2560         // Leading edge
2561         try{
2562                 v3s16 p = blockpos + v3s16(-1,0,0);
2563                 addUpdateMeshTask(p, false, urgent);
2564         }
2565         catch(InvalidPositionException &e){}
2566         try{
2567                 v3s16 p = blockpos + v3s16(0,-1,0);
2568                 addUpdateMeshTask(p, false, urgent);
2569         }
2570         catch(InvalidPositionException &e){}
2571         try{
2572                 v3s16 p = blockpos + v3s16(0,0,-1);
2573                 addUpdateMeshTask(p, false, urgent);
2574         }
2575         catch(InvalidPositionException &e){}
2576 }
2577
2578 void Client::addUpdateMeshTaskForNode(v3s16 nodepos, bool ack_to_server, bool urgent)
2579 {
2580         {
2581                 v3s16 p = nodepos;
2582                 infostream<<"Client::addUpdateMeshTaskForNode(): "
2583                                 <<"("<<p.X<<","<<p.Y<<","<<p.Z<<")"
2584                                 <<std::endl;
2585         }
2586
2587         v3s16 blockpos = getNodeBlockPos(nodepos);
2588         v3s16 blockpos_relative = blockpos * MAP_BLOCKSIZE;
2589
2590         try{
2591                 v3s16 p = blockpos + v3s16(0,0,0);
2592                 addUpdateMeshTask(p, ack_to_server, urgent);
2593         }
2594         catch(InvalidPositionException &e){}
2595         // Leading edge
2596         if(nodepos.X == blockpos_relative.X){
2597                 try{
2598                         v3s16 p = blockpos + v3s16(-1,0,0);
2599                         addUpdateMeshTask(p, false, urgent);
2600                 }
2601                 catch(InvalidPositionException &e){}
2602         }
2603         if(nodepos.Y == blockpos_relative.Y){
2604                 try{
2605                         v3s16 p = blockpos + v3s16(0,-1,0);
2606                         addUpdateMeshTask(p, false, urgent);
2607                 }
2608                 catch(InvalidPositionException &e){}
2609         }
2610         if(nodepos.Z == blockpos_relative.Z){
2611                 try{
2612                         v3s16 p = blockpos + v3s16(0,0,-1);
2613                         addUpdateMeshTask(p, false, urgent);
2614                 }
2615                 catch(InvalidPositionException &e){}
2616         }
2617 }
2618
2619 ClientEvent Client::getClientEvent()
2620 {
2621         if(m_client_event_queue.size() == 0)
2622         {
2623                 ClientEvent event;
2624                 event.type = CE_NONE;
2625                 return event;
2626         }
2627         return m_client_event_queue.pop_front();
2628 }
2629
2630 void Client::afterContentReceived()
2631 {
2632         infostream<<"Client::afterContentReceived() started"<<std::endl;
2633         assert(m_itemdef_received);
2634         assert(m_nodedef_received);
2635         assert(texturesReceived());
2636         
2637         // remove the information about which checksum each texture
2638         // ought to have
2639         m_media_name_sha1_map.clear();
2640
2641         // Rebuild inherited images and recreate textures
2642         infostream<<"- Rebuilding images and textures"<<std::endl;
2643         m_tsrc->rebuildImagesAndTextures();
2644
2645         // Update texture atlas
2646         infostream<<"- Updating texture atlas"<<std::endl;
2647         if(g_settings->getBool("enable_texture_atlas"))
2648                 m_tsrc->buildMainAtlas(this);
2649
2650         // Rebuild shaders
2651         m_shsrc->rebuildShaders();
2652
2653         // Update node aliases
2654         infostream<<"- Updating node aliases"<<std::endl;
2655         m_nodedef->updateAliases(m_itemdef);
2656
2657         // Update node textures
2658         infostream<<"- Updating node textures"<<std::endl;
2659         m_nodedef->updateTextures(m_tsrc);
2660
2661         // Preload item textures and meshes if configured to
2662         if(g_settings->getBool("preload_item_visuals"))
2663         {
2664                 verbosestream<<"Updating item textures and meshes"<<std::endl;
2665                 std::set<std::string> names = m_itemdef->getAll();
2666                 for(std::set<std::string>::const_iterator
2667                                 i = names.begin(); i != names.end(); ++i){
2668                         // Asking for these caches the result
2669                         m_itemdef->getInventoryTexture(*i, this);
2670                         m_itemdef->getWieldMesh(*i, this);
2671                 }
2672         }
2673
2674         // Start mesh update thread after setting up content definitions
2675         infostream<<"- Starting mesh update thread"<<std::endl;
2676         m_mesh_update_thread.Start();
2677         
2678         infostream<<"Client::afterContentReceived() done"<<std::endl;
2679 }
2680
2681 float Client::getRTT(void)
2682 {
2683         try{
2684                 return m_con.GetPeerAvgRTT(PEER_ID_SERVER);
2685         } catch(con::PeerNotFoundException &e){
2686                 return 1337;
2687         }
2688 }
2689
2690 // IGameDef interface
2691 // Under envlock
2692 IItemDefManager* Client::getItemDefManager()
2693 {
2694         return m_itemdef;
2695 }
2696 INodeDefManager* Client::getNodeDefManager()
2697 {
2698         return m_nodedef;
2699 }
2700 ICraftDefManager* Client::getCraftDefManager()
2701 {
2702         return NULL;
2703         //return m_craftdef;
2704 }
2705 ITextureSource* Client::getTextureSource()
2706 {
2707         return m_tsrc;
2708 }
2709 IShaderSource* Client::getShaderSource()
2710 {
2711         return m_shsrc;
2712 }
2713 u16 Client::allocateUnknownNodeId(const std::string &name)
2714 {
2715         errorstream<<"Client::allocateUnknownNodeId(): "
2716                         <<"Client cannot allocate node IDs"<<std::endl;
2717         assert(0);
2718         return CONTENT_IGNORE;
2719 }
2720 ISoundManager* Client::getSoundManager()
2721 {
2722         return m_sound;
2723 }
2724 MtEventManager* Client::getEventManager()
2725 {
2726         return m_event;
2727 }
2728