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