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