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