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