]> git.lizzy.rs Git - dragonfireclient.git/blob - src/client.cpp
Add set_breath and get_breath to lua 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 << " (" << curl_easy_strerror(res) << ")"<< 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         /*
324                 Add local player
325         */
326         {
327                 Player *player = new LocalPlayer(this);
328
329                 player->updateName(playername);
330
331                 m_env.addPlayer(player);
332         }
333
334         for (size_t i = 0; i < g_settings->getU16("media_fetch_threads"); ++i)
335                 m_media_fetch_threads.push_back(new MediaFetchThread(this));
336 }
337
338 Client::~Client()
339 {
340         {
341                 //JMutexAutoLock conlock(m_con_mutex); //bulk comment-out
342                 m_con.Disconnect();
343         }
344
345         m_mesh_update_thread.setRun(false);
346         while(m_mesh_update_thread.IsRunning())
347                 sleep_ms(100);
348         while(!m_mesh_update_thread.m_queue_out.empty()) {
349                 MeshUpdateResult r = m_mesh_update_thread.m_queue_out.pop_front();
350                 delete r.mesh;
351         }
352
353
354         delete m_inventory_from_server;
355
356         // Delete detached inventories
357         {
358                 for(std::map<std::string, Inventory*>::iterator
359                                 i = m_detached_inventories.begin();
360                                 i != m_detached_inventories.end(); i++){
361                         delete i->second;
362                 }
363         }
364
365         for (std::list<MediaFetchThread*>::iterator i = m_media_fetch_threads.begin();
366                         i != m_media_fetch_threads.end(); ++i)
367                 delete *i;
368
369         // cleanup 3d model meshes on client shutdown
370         while (m_device->getSceneManager()->getMeshCache()->getMeshCount() != 0) {
371                 scene::IAnimatedMesh * mesh =
372                         m_device->getSceneManager()->getMeshCache()->getMeshByIndex(0);
373
374                 if (mesh != NULL)
375                         m_device->getSceneManager()->getMeshCache()->removeMesh(mesh);
376         }
377 }
378
379 void Client::connect(Address address)
380 {
381         DSTACK(__FUNCTION_NAME);
382         //JMutexAutoLock lock(m_con_mutex); //bulk comment-out
383         m_con.SetTimeoutMs(0);
384         m_con.Connect(address);
385 }
386
387 bool Client::connectedAndInitialized()
388 {
389         //JMutexAutoLock lock(m_con_mutex); //bulk comment-out
390
391         if(m_con.Connected() == false)
392                 return false;
393         
394         if(m_server_ser_ver == SER_FMT_VER_INVALID)
395                 return false;
396         
397         return true;
398 }
399
400 void Client::step(float dtime)
401 {
402         DSTACK(__FUNCTION_NAME);
403         
404         // Limit a bit
405         if(dtime > 2.0)
406                 dtime = 2.0;
407         
408         if(m_ignore_damage_timer > dtime)
409                 m_ignore_damage_timer -= dtime;
410         else
411                 m_ignore_damage_timer = 0.0;
412         
413         m_animation_time += dtime;
414         if(m_animation_time > 60.0)
415                 m_animation_time -= 60.0;
416
417         m_time_of_day_update_timer += dtime;
418         
419         //infostream<<"Client steps "<<dtime<<std::endl;
420
421         {
422                 //TimeTaker timer("ReceiveAll()", m_device);
423                 // 0ms
424                 ReceiveAll();
425         }
426         
427         {
428                 //TimeTaker timer("m_con_mutex + m_con.RunTimeouts()", m_device);
429                 // 0ms
430                 //JMutexAutoLock lock(m_con_mutex); //bulk comment-out
431                 m_con.RunTimeouts(dtime);
432         }
433
434         /*
435                 Packet counter
436         */
437         {
438                 float &counter = m_packetcounter_timer;
439                 counter -= dtime;
440                 if(counter <= 0.0)
441                 {
442                         counter = 20.0;
443                         
444                         infostream<<"Client packetcounter (20s):"<<std::endl;
445                         m_packetcounter.print(infostream);
446                         m_packetcounter.clear();
447                 }
448         }
449         
450         // Get connection status
451         bool connected = connectedAndInitialized();
452
453 #if 0
454         {
455                 /*
456                         Delete unused sectors
457
458                         NOTE: This jams the game for a while because deleting sectors
459                               clear caches
460                 */
461                 
462                 float &counter = m_delete_unused_sectors_timer;
463                 counter -= dtime;
464                 if(counter <= 0.0)
465                 {
466                         // 3 minute interval
467                         //counter = 180.0;
468                         counter = 60.0;
469
470                         //JMutexAutoLock lock(m_env_mutex); //bulk comment-out
471
472                         core::list<v3s16> deleted_blocks;
473
474                         float delete_unused_sectors_timeout = 
475                                 g_settings->getFloat("client_delete_unused_sectors_timeout");
476         
477                         // Delete sector blocks
478                         /*u32 num = m_env.getMap().unloadUnusedData
479                                         (delete_unused_sectors_timeout,
480                                         true, &deleted_blocks);*/
481                         
482                         // Delete whole sectors
483                         m_env.getMap().unloadUnusedData
484                                         (delete_unused_sectors_timeout,
485                                         &deleted_blocks);
486
487                         if(deleted_blocks.size() > 0)
488                         {
489                                 /*infostream<<"Client: Deleted blocks of "<<num
490                                                 <<" unused sectors"<<std::endl;*/
491                                 /*infostream<<"Client: Deleted "<<num
492                                                 <<" unused sectors"<<std::endl;*/
493                                 
494                                 /*
495                                         Send info to server
496                                 */
497
498                                 // Env is locked so con can be locked.
499                                 //JMutexAutoLock lock(m_con_mutex); //bulk comment-out
500                                 
501                                 core::list<v3s16>::Iterator i = deleted_blocks.begin();
502                                 core::list<v3s16> sendlist;
503                                 for(;;)
504                                 {
505                                         if(sendlist.size() == 255 || i == deleted_blocks.end())
506                                         {
507                                                 if(sendlist.size() == 0)
508                                                         break;
509                                                 /*
510                                                         [0] u16 command
511                                                         [2] u8 count
512                                                         [3] v3s16 pos_0
513                                                         [3+6] v3s16 pos_1
514                                                         ...
515                                                 */
516                                                 u32 replysize = 2+1+6*sendlist.size();
517                                                 SharedBuffer<u8> reply(replysize);
518                                                 writeU16(&reply[0], TOSERVER_DELETEDBLOCKS);
519                                                 reply[2] = sendlist.size();
520                                                 u32 k = 0;
521                                                 for(core::list<v3s16>::Iterator
522                                                                 j = sendlist.begin();
523                                                                 j != sendlist.end(); j++)
524                                                 {
525                                                         writeV3S16(&reply[2+1+6*k], *j);
526                                                         k++;
527                                                 }
528                                                 m_con.Send(PEER_ID_SERVER, 1, reply, true);
529
530                                                 if(i == deleted_blocks.end())
531                                                         break;
532
533                                                 sendlist.clear();
534                                         }
535
536                                         sendlist.push_back(*i);
537                                         i++;
538                                 }
539                         }
540                 }
541         }
542 #endif
543
544         if(connected == false)
545         {
546                 float &counter = m_connection_reinit_timer;
547                 counter -= dtime;
548                 if(counter <= 0.0)
549                 {
550                         counter = 2.0;
551
552                         //JMutexAutoLock envlock(m_env_mutex); //bulk comment-out
553                         
554                         Player *myplayer = m_env.getLocalPlayer();
555                         assert(myplayer != NULL);
556         
557                         // Send TOSERVER_INIT
558                         // [0] u16 TOSERVER_INIT
559                         // [2] u8 SER_FMT_VER_HIGHEST
560                         // [3] u8[20] player_name
561                         // [23] u8[28] password (new in some version)
562                         // [51] u16 minimum supported network protocol version (added sometime)
563                         // [53] u16 maximum supported network protocol version (added later than the previous one)
564                         SharedBuffer<u8> data(2+1+PLAYERNAME_SIZE+PASSWORD_SIZE+2+2);
565                         writeU16(&data[0], TOSERVER_INIT);
566                         writeU8(&data[2], SER_FMT_VER_HIGHEST);
567
568                         memset((char*)&data[3], 0, PLAYERNAME_SIZE);
569                         snprintf((char*)&data[3], PLAYERNAME_SIZE, "%s", myplayer->getName());
570
571                         /*infostream<<"Client: sending initial password hash: \""<<m_password<<"\""
572                                         <<std::endl;*/
573
574                         memset((char*)&data[23], 0, PASSWORD_SIZE);
575                         snprintf((char*)&data[23], PASSWORD_SIZE, "%s", m_password.c_str());
576                         
577                         writeU16(&data[51], CLIENT_PROTOCOL_VERSION_MIN);
578                         writeU16(&data[53], CLIENT_PROTOCOL_VERSION_MAX);
579
580                         // Send as unreliable
581                         Send(0, data, false);
582                 }
583
584                 // Not connected, return
585                 return;
586         }
587
588         /*
589                 Do stuff if connected
590         */
591         
592         /*
593                 Run Map's timers and unload unused data
594         */
595         const float map_timer_and_unload_dtime = 5.25;
596         if(m_map_timer_and_unload_interval.step(dtime, map_timer_and_unload_dtime))
597         {
598                 ScopeProfiler sp(g_profiler, "Client: map timer and unload");
599                 std::list<v3s16> deleted_blocks;
600                 m_env.getMap().timerUpdate(map_timer_and_unload_dtime,
601                                 g_settings->getFloat("client_unload_unused_data_timeout"),
602                                 &deleted_blocks);
603                                 
604                 /*if(deleted_blocks.size() > 0)
605                         infostream<<"Client: Unloaded "<<deleted_blocks.size()
606                                         <<" unused blocks"<<std::endl;*/
607                         
608                 /*
609                         Send info to server
610                         NOTE: This loop is intentionally iterated the way it is.
611                 */
612
613                 std::list<v3s16>::iterator i = deleted_blocks.begin();
614                 std::list<v3s16> sendlist;
615                 for(;;)
616                 {
617                         if(sendlist.size() == 255 || i == deleted_blocks.end())
618                         {
619                                 if(sendlist.size() == 0)
620                                         break;
621                                 /*
622                                         [0] u16 command
623                                         [2] u8 count
624                                         [3] v3s16 pos_0
625                                         [3+6] v3s16 pos_1
626                                         ...
627                                 */
628                                 u32 replysize = 2+1+6*sendlist.size();
629                                 SharedBuffer<u8> reply(replysize);
630                                 writeU16(&reply[0], TOSERVER_DELETEDBLOCKS);
631                                 reply[2] = sendlist.size();
632                                 u32 k = 0;
633                                 for(std::list<v3s16>::iterator
634                                                 j = sendlist.begin();
635                                                 j != sendlist.end(); ++j)
636                                 {
637                                         writeV3S16(&reply[2+1+6*k], *j);
638                                         k++;
639                                 }
640                                 m_con.Send(PEER_ID_SERVER, 1, reply, true);
641
642                                 if(i == deleted_blocks.end())
643                                         break;
644
645                                 sendlist.clear();
646                         }
647
648                         sendlist.push_back(*i);
649                         ++i;
650                 }
651         }
652
653         /*
654                 Handle environment
655         */
656         {
657                 // 0ms
658                 //JMutexAutoLock lock(m_env_mutex); //bulk comment-out
659
660                 // Control local player (0ms)
661                 LocalPlayer *player = m_env.getLocalPlayer();
662                 assert(player != NULL);
663                 player->applyControl(dtime);
664
665                 //TimeTaker envtimer("env step", m_device);
666                 // Step environment
667                 m_env.step(dtime);
668                 
669                 /*
670                         Get events
671                 */
672                 for(;;)
673                 {
674                         ClientEnvEvent event = m_env.getClientEvent();
675                         if(event.type == CEE_NONE)
676                         {
677                                 break;
678                         }
679                         else if(event.type == CEE_PLAYER_DAMAGE)
680                         {
681                                 if(m_ignore_damage_timer <= 0)
682                                 {
683                                         u8 damage = event.player_damage.amount;
684                                         
685                                         if(event.player_damage.send_to_server)
686                                                 sendDamage(damage);
687
688                                         // Add to ClientEvent queue
689                                         ClientEvent event;
690                                         event.type = CE_PLAYER_DAMAGE;
691                                         event.player_damage.amount = damage;
692                                         m_client_event_queue.push_back(event);
693                                 }
694                         }
695                         else if(event.type == CEE_PLAYER_BREATH)
696                         {
697                                         u16 breath = event.player_breath.amount;
698                                         sendBreath(breath);
699                         }
700                 }
701         }
702
703         /*
704                 Print some info
705         */
706         {
707                 float &counter = m_avg_rtt_timer;
708                 counter += dtime;
709                 if(counter >= 10)
710                 {
711                         counter = 0.0;
712                         //JMutexAutoLock lock(m_con_mutex); //bulk comment-out
713                         // connectedAndInitialized() is true, peer exists.
714                         float avg_rtt = m_con.GetPeerAvgRTT(PEER_ID_SERVER);
715                         infostream<<"Client: avg_rtt="<<avg_rtt<<std::endl;
716                 }
717         }
718
719         /*
720                 Send player position to server
721         */
722         {
723                 float &counter = m_playerpos_send_timer;
724                 counter += dtime;
725                 if(counter >= m_recommended_send_interval)
726                 {
727                         counter = 0.0;
728                         sendPlayerPos();
729                 }
730         }
731
732         /*
733                 Replace updated meshes
734         */
735         {
736                 //JMutexAutoLock lock(m_env_mutex); //bulk comment-out
737
738                 //TimeTaker timer("** Processing mesh update result queue");
739                 // 0ms
740                 
741                 /*infostream<<"Mesh update result queue size is "
742                                 <<m_mesh_update_thread.m_queue_out.size()
743                                 <<std::endl;*/
744                 
745                 int num_processed_meshes = 0;
746                 while(!m_mesh_update_thread.m_queue_out.empty())
747                 {
748                         num_processed_meshes++;
749                         MeshUpdateResult r = m_mesh_update_thread.m_queue_out.pop_front();
750                         MapBlock *block = m_env.getMap().getBlockNoCreateNoEx(r.p);
751                         if(block)
752                         {
753                                 //JMutexAutoLock lock(block->mesh_mutex);
754
755                                 // Delete the old mesh
756                                 if(block->mesh != NULL)
757                                 {
758                                         // TODO: Remove hardware buffers of meshbuffers of block->mesh
759                                         delete block->mesh;
760                                         block->mesh = NULL;
761                                 }
762
763                                 // Replace with the new mesh
764                                 block->mesh = r.mesh;
765                         } else {
766                                 delete r.mesh;
767                         }
768                         if(r.ack_block_to_server)
769                         {
770                                 /*infostream<<"Client: ACK block ("<<r.p.X<<","<<r.p.Y
771                                                 <<","<<r.p.Z<<")"<<std::endl;*/
772                                 /*
773                                         Acknowledge block
774                                 */
775                                 /*
776                                         [0] u16 command
777                                         [2] u8 count
778                                         [3] v3s16 pos_0
779                                         [3+6] v3s16 pos_1
780                                         ...
781                                 */
782                                 u32 replysize = 2+1+6;
783                                 SharedBuffer<u8> reply(replysize);
784                                 writeU16(&reply[0], TOSERVER_GOTBLOCKS);
785                                 reply[2] = 1;
786                                 writeV3S16(&reply[3], r.p);
787                                 // Send as reliable
788                                 m_con.Send(PEER_ID_SERVER, 1, reply, true);
789                         }
790                 }
791                 if(num_processed_meshes > 0)
792                         g_profiler->graphAdd("num_processed_meshes", num_processed_meshes);
793         }
794
795         /*
796                 Load fetched media
797         */
798         if (m_media_receive_started) {
799                 bool all_stopped = true;
800                 for (std::list<MediaFetchThread*>::iterator thread = m_media_fetch_threads.begin();
801                                 thread != m_media_fetch_threads.end(); ++thread) {
802                         all_stopped &= !(*thread)->IsRunning();
803                         while (!(*thread)->m_file_data.empty()) {
804                                 std::pair <std::string, std::string> out = (*thread)->m_file_data.pop_front();
805                                 if(m_media_received_count < m_media_count)
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_BREATH)
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                 u16 breath = readU16(is);
1594                 player->setBreath(breath) ;
1595         }
1596         else if(command == TOCLIENT_MOVE_PLAYER)
1597         {
1598                 std::string datastring((char*)&data[2], datasize-2);
1599                 std::istringstream is(datastring, std::ios_base::binary);
1600                 Player *player = m_env.getLocalPlayer();
1601                 assert(player != NULL);
1602                 v3f pos = readV3F1000(is);
1603                 f32 pitch = readF1000(is);
1604                 f32 yaw = readF1000(is);
1605                 player->setPosition(pos);
1606                 /*player->setPitch(pitch);
1607                 player->setYaw(yaw);*/
1608
1609                 infostream<<"Client got TOCLIENT_MOVE_PLAYER"
1610                                 <<" pos=("<<pos.X<<","<<pos.Y<<","<<pos.Z<<")"
1611                                 <<" pitch="<<pitch
1612                                 <<" yaw="<<yaw
1613                                 <<std::endl;
1614
1615                 /*
1616                         Add to ClientEvent queue.
1617                         This has to be sent to the main program because otherwise
1618                         it would just force the pitch and yaw values to whatever
1619                         the camera points to.
1620                 */
1621                 ClientEvent event;
1622                 event.type = CE_PLAYER_FORCE_MOVE;
1623                 event.player_force_move.pitch = pitch;
1624                 event.player_force_move.yaw = yaw;
1625                 m_client_event_queue.push_back(event);
1626
1627                 // Ignore damage for a few seconds, so that the player doesn't
1628                 // get damage from falling on ground
1629                 m_ignore_damage_timer = 3.0;
1630         }
1631         else if(command == TOCLIENT_PLAYERITEM)
1632         {
1633                 infostream<<"Client: WARNING: Ignoring TOCLIENT_PLAYERITEM"<<std::endl;
1634         }
1635         else if(command == TOCLIENT_DEATHSCREEN)
1636         {
1637                 std::string datastring((char*)&data[2], datasize-2);
1638                 std::istringstream is(datastring, std::ios_base::binary);
1639                 
1640                 bool set_camera_point_target = readU8(is);
1641                 v3f camera_point_target = readV3F1000(is);
1642                 
1643                 ClientEvent event;
1644                 event.type = CE_DEATHSCREEN;
1645                 event.deathscreen.set_camera_point_target = set_camera_point_target;
1646                 event.deathscreen.camera_point_target_x = camera_point_target.X;
1647                 event.deathscreen.camera_point_target_y = camera_point_target.Y;
1648                 event.deathscreen.camera_point_target_z = camera_point_target.Z;
1649                 m_client_event_queue.push_back(event);
1650         }
1651         else if(command == TOCLIENT_ANNOUNCE_MEDIA)
1652         {
1653                 std::string datastring((char*)&data[2], datasize-2);
1654                 std::istringstream is(datastring, std::ios_base::binary);
1655
1656                 // Mesh update thread must be stopped while
1657                 // updating content definitions
1658                 assert(!m_mesh_update_thread.IsRunning());
1659
1660                 int num_files = readU16(is);
1661                 
1662                 infostream<<"Client: Received media announcement: packet size: "
1663                                 <<datasize<<std::endl;
1664
1665                 std::list<MediaRequest> file_requests;
1666
1667                 for(int i=0; i<num_files; i++)
1668                 {
1669                         //read file from cache
1670                         std::string name = deSerializeString(is);
1671                         std::string sha1_base64 = deSerializeString(is);
1672
1673                         // if name contains illegal characters, ignore the file
1674                         if(!string_allowed(name, TEXTURENAME_ALLOWED_CHARS)){
1675                                 errorstream<<"Client: ignoring illegal file name "
1676                                                 <<"sent by server: \""<<name<<"\""<<std::endl;
1677                                 continue;
1678                         }
1679
1680                         std::string sha1_raw = base64_decode(sha1_base64);
1681                         std::string sha1_hex = hex_encode(sha1_raw);
1682                         std::ostringstream tmp_os(std::ios_base::binary);
1683                         bool found_in_cache = m_media_cache.load_sha1(sha1_raw, tmp_os);
1684                         m_media_name_sha1_map[name] = sha1_raw;
1685
1686                         // If found in cache, try to load it from there
1687                         if(found_in_cache)
1688                         {
1689                                 bool success = loadMedia(tmp_os.str(), name);
1690                                 if(success){
1691                                         verbosestream<<"Client: Loaded cached media: "
1692                                                         <<sha1_hex<<" \""<<name<<"\""<<std::endl;
1693                                         continue;
1694                                 } else{
1695                                         infostream<<"Client: Failed to load cached media: "
1696                                                         <<sha1_hex<<" \""<<name<<"\""<<std::endl;
1697                                 }
1698                         }
1699                         // Didn't load from cache; queue it to be requested
1700                         verbosestream<<"Client: Adding file to request list: \""
1701                                         <<sha1_hex<<" \""<<name<<"\""<<std::endl;
1702                         file_requests.push_back(MediaRequest(name));
1703                 }
1704
1705                 std::string remote_media = "";
1706                 try {
1707                         remote_media = deSerializeString(is);
1708                 }
1709                 catch(SerializationError) {
1710                         // not supported by server or turned off
1711                 }
1712
1713                 m_media_count = file_requests.size();
1714                 m_media_receive_started = true;
1715
1716                 if (remote_media == "" || !USE_CURL) {
1717                         request_media(file_requests);
1718                 } else {
1719                         #if USE_CURL
1720                         std::list<MediaFetchThread*>::iterator cur = m_media_fetch_threads.begin();
1721                         for(std::list<MediaRequest>::iterator i = file_requests.begin();
1722                                         i != file_requests.end(); ++i) {
1723                                 (*cur)->m_file_requests.push_back(*i);
1724                                 cur++;
1725                                 if (cur == m_media_fetch_threads.end())
1726                                         cur = m_media_fetch_threads.begin();
1727                         }
1728                         for (std::list<MediaFetchThread*>::iterator i = m_media_fetch_threads.begin();
1729                                         i != m_media_fetch_threads.end(); ++i) {
1730                                 (*i)->m_remote_url = remote_media;
1731                                 (*i)->Start();
1732                         }
1733                         #endif
1734
1735                         // notify server we received everything
1736                         std::ostringstream os(std::ios_base::binary);
1737                         writeU16(os, TOSERVER_RECEIVED_MEDIA);
1738                         std::string s = os.str();
1739                         SharedBuffer<u8> data((u8*)s.c_str(), s.size());
1740                         // Send as reliable
1741                         Send(0, data, true);
1742                 }
1743                 ClientEvent event;
1744                 event.type = CE_TEXTURES_UPDATED;
1745                 m_client_event_queue.push_back(event);
1746         }
1747         else if(command == TOCLIENT_MEDIA)
1748         {
1749                 std::string datastring((char*)&data[2], datasize-2);
1750                 std::istringstream is(datastring, std::ios_base::binary);
1751
1752                 /*
1753                         u16 command
1754                         u16 total number of file bunches
1755                         u16 index of this bunch
1756                         u32 number of files in this bunch
1757                         for each file {
1758                                 u16 length of name
1759                                 string name
1760                                 u32 length of data
1761                                 data
1762                         }
1763                 */
1764                 int num_bunches = readU16(is);
1765                 int bunch_i = readU16(is);
1766                 u32 num_files = readU32(is);
1767                 infostream<<"Client: Received files: bunch "<<bunch_i<<"/"
1768                                 <<num_bunches<<" files="<<num_files
1769                                 <<" size="<<datasize<<std::endl;
1770
1771                 // Check total and received media count
1772                 assert(m_media_received_count <= m_media_count);
1773                 if (num_files > m_media_count - m_media_received_count) {
1774                         errorstream<<"Client: Received more files than requested:"
1775                                 <<" total count="<<m_media_count
1776                                 <<" total received="<<m_media_received_count
1777                                 <<" bunch "<<bunch_i<<"/"<<num_bunches
1778                                 <<" files="<<num_files
1779                                 <<" size="<<datasize<<std::endl;
1780                         num_files = m_media_count - m_media_received_count;
1781                 }
1782                 if (num_files == 0)
1783                         return;
1784
1785                 // Mesh update thread must be stopped while
1786                 // updating content definitions
1787                 assert(!m_mesh_update_thread.IsRunning());
1788
1789                 for(u32 i=0; i<num_files; i++){
1790                         assert(m_media_received_count < m_media_count);
1791                         m_media_received_count++;
1792                         std::string name = deSerializeString(is);
1793                         std::string data = deSerializeLongString(is);
1794
1795                         // if name contains illegal characters, ignore the file
1796                         if(!string_allowed(name, TEXTURENAME_ALLOWED_CHARS)){
1797                                 errorstream<<"Client: ignoring illegal file name "
1798                                                 <<"sent by server: \""<<name<<"\""<<std::endl;
1799                                 continue;
1800                         }
1801                         
1802                         bool success = loadMedia(data, name);
1803                         if(success){
1804                                 verbosestream<<"Client: Loaded received media: "
1805                                                 <<"\""<<name<<"\". Caching."<<std::endl;
1806                         } else{
1807                                 infostream<<"Client: Failed to load received media: "
1808                                                 <<"\""<<name<<"\". Not caching."<<std::endl;
1809                                 continue;
1810                         }
1811
1812                         bool did = fs::CreateAllDirs(getMediaCacheDir());
1813                         if(!did){
1814                                 errorstream<<"Could not create media cache directory"
1815                                                 <<std::endl;
1816                         }
1817
1818                         {
1819                                 std::map<std::string, std::string>::iterator n;
1820                                 n = m_media_name_sha1_map.find(name);
1821                                 if(n == m_media_name_sha1_map.end())
1822                                         errorstream<<"The server sent a file that has not "
1823                                                         <<"been announced."<<std::endl;
1824                                 else
1825                                         m_media_cache.update_sha1(data);
1826                         }
1827                 }
1828
1829                 ClientEvent event;
1830                 event.type = CE_TEXTURES_UPDATED;
1831                 m_client_event_queue.push_back(event);
1832         }
1833         else if(command == TOCLIENT_TOOLDEF)
1834         {
1835                 infostream<<"Client: WARNING: Ignoring TOCLIENT_TOOLDEF"<<std::endl;
1836         }
1837         else if(command == TOCLIENT_NODEDEF)
1838         {
1839                 infostream<<"Client: Received node definitions: packet size: "
1840                                 <<datasize<<std::endl;
1841
1842                 // Mesh update thread must be stopped while
1843                 // updating content definitions
1844                 assert(!m_mesh_update_thread.IsRunning());
1845
1846                 // Decompress node definitions
1847                 std::string datastring((char*)&data[2], datasize-2);
1848                 std::istringstream is(datastring, std::ios_base::binary);
1849                 std::istringstream tmp_is(deSerializeLongString(is), std::ios::binary);
1850                 std::ostringstream tmp_os;
1851                 decompressZlib(tmp_is, tmp_os);
1852
1853                 // Deserialize node definitions
1854                 std::istringstream tmp_is2(tmp_os.str());
1855                 m_nodedef->deSerialize(tmp_is2);
1856                 m_nodedef_received = true;
1857         }
1858         else if(command == TOCLIENT_CRAFTITEMDEF)
1859         {
1860                 infostream<<"Client: WARNING: Ignoring TOCLIENT_CRAFTITEMDEF"<<std::endl;
1861         }
1862         else if(command == TOCLIENT_ITEMDEF)
1863         {
1864                 infostream<<"Client: Received item definitions: packet size: "
1865                                 <<datasize<<std::endl;
1866
1867                 // Mesh update thread must be stopped while
1868                 // updating content definitions
1869                 assert(!m_mesh_update_thread.IsRunning());
1870
1871                 // Decompress item definitions
1872                 std::string datastring((char*)&data[2], datasize-2);
1873                 std::istringstream is(datastring, std::ios_base::binary);
1874                 std::istringstream tmp_is(deSerializeLongString(is), std::ios::binary);
1875                 std::ostringstream tmp_os;
1876                 decompressZlib(tmp_is, tmp_os);
1877
1878                 // Deserialize node definitions
1879                 std::istringstream tmp_is2(tmp_os.str());
1880                 m_itemdef->deSerialize(tmp_is2);
1881                 m_itemdef_received = true;
1882         }
1883         else if(command == TOCLIENT_PLAY_SOUND)
1884         {
1885                 std::string datastring((char*)&data[2], datasize-2);
1886                 std::istringstream is(datastring, std::ios_base::binary);
1887
1888                 s32 server_id = readS32(is);
1889                 std::string name = deSerializeString(is);
1890                 float gain = readF1000(is);
1891                 int type = readU8(is); // 0=local, 1=positional, 2=object
1892                 v3f pos = readV3F1000(is);
1893                 u16 object_id = readU16(is);
1894                 bool loop = readU8(is);
1895                 // Start playing
1896                 int client_id = -1;
1897                 switch(type){
1898                 case 0: // local
1899                         client_id = m_sound->playSound(name, loop, gain);
1900                         break;
1901                 case 1: // positional
1902                         client_id = m_sound->playSoundAt(name, loop, gain, pos);
1903                         break;
1904                 case 2: { // object
1905                         ClientActiveObject *cao = m_env.getActiveObject(object_id);
1906                         if(cao)
1907                                 pos = cao->getPosition();
1908                         client_id = m_sound->playSoundAt(name, loop, gain, pos);
1909                         // TODO: Set up sound to move with object
1910                         break; }
1911                 default:
1912                         break;
1913                 }
1914                 if(client_id != -1){
1915                         m_sounds_server_to_client[server_id] = client_id;
1916                         m_sounds_client_to_server[client_id] = server_id;
1917                         if(object_id != 0)
1918                                 m_sounds_to_objects[client_id] = object_id;
1919                 }
1920         }
1921         else if(command == TOCLIENT_STOP_SOUND)
1922         {
1923                 std::string datastring((char*)&data[2], datasize-2);
1924                 std::istringstream is(datastring, std::ios_base::binary);
1925
1926                 s32 server_id = readS32(is);
1927                 std::map<s32, int>::iterator i =
1928                                 m_sounds_server_to_client.find(server_id);
1929                 if(i != m_sounds_server_to_client.end()){
1930                         int client_id = i->second;
1931                         m_sound->stopSound(client_id);
1932                 }
1933         }
1934         else if(command == TOCLIENT_PRIVILEGES)
1935         {
1936                 std::string datastring((char*)&data[2], datasize-2);
1937                 std::istringstream is(datastring, std::ios_base::binary);
1938                 
1939                 m_privileges.clear();
1940                 infostream<<"Client: Privileges updated: ";
1941                 u16 num_privileges = readU16(is);
1942                 for(u16 i=0; i<num_privileges; i++){
1943                         std::string priv = deSerializeString(is);
1944                         m_privileges.insert(priv);
1945                         infostream<<priv<<" ";
1946                 }
1947                 infostream<<std::endl;
1948         }
1949         else if(command == TOCLIENT_INVENTORY_FORMSPEC)
1950         {
1951                 std::string datastring((char*)&data[2], datasize-2);
1952                 std::istringstream is(datastring, std::ios_base::binary);
1953
1954                 // Store formspec in LocalPlayer
1955                 Player *player = m_env.getLocalPlayer();
1956                 assert(player != NULL);
1957                 player->inventory_formspec = deSerializeLongString(is);
1958         }
1959         else if(command == TOCLIENT_DETACHED_INVENTORY)
1960         {
1961                 std::string datastring((char*)&data[2], datasize-2);
1962                 std::istringstream is(datastring, std::ios_base::binary);
1963
1964                 std::string name = deSerializeString(is);
1965                 
1966                 infostream<<"Client: Detached inventory update: \""<<name<<"\""<<std::endl;
1967
1968                 Inventory *inv = NULL;
1969                 if(m_detached_inventories.count(name) > 0)
1970                         inv = m_detached_inventories[name];
1971                 else{
1972                         inv = new Inventory(m_itemdef);
1973                         m_detached_inventories[name] = inv;
1974                 }
1975                 inv->deSerialize(is);
1976         }
1977         else if(command == TOCLIENT_SHOW_FORMSPEC)
1978         {
1979                 std::string datastring((char*)&data[2], datasize-2);
1980                 std::istringstream is(datastring, std::ios_base::binary);
1981
1982                 std::string formspec = deSerializeLongString(is);
1983                 std::string formname = deSerializeString(is);
1984
1985                 ClientEvent event;
1986                 event.type = CE_SHOW_FORMSPEC;
1987                 // pointer is required as event is a struct only!
1988                 // adding a std:string to a struct isn't possible
1989                 event.show_formspec.formspec = new std::string(formspec);
1990                 event.show_formspec.formname = new std::string(formname);
1991                 m_client_event_queue.push_back(event);
1992         }
1993         else if(command == TOCLIENT_SPAWN_PARTICLE)
1994         {
1995                 std::string datastring((char*)&data[2], datasize-2);
1996                 std::istringstream is(datastring, std::ios_base::binary);
1997
1998                 v3f pos = readV3F1000(is);
1999                 v3f vel = readV3F1000(is);
2000                 v3f acc = readV3F1000(is);
2001                 float expirationtime = readF1000(is);
2002                 float size = readF1000(is);
2003                 bool collisiondetection = readU8(is);
2004                 std::string texture = deSerializeLongString(is);
2005
2006                 ClientEvent event;
2007                 event.type = CE_SPAWN_PARTICLE;
2008                 event.spawn_particle.pos = new v3f (pos);
2009                 event.spawn_particle.vel = new v3f (vel);
2010                 event.spawn_particle.acc = new v3f (acc);
2011
2012                 event.spawn_particle.expirationtime = expirationtime;
2013                 event.spawn_particle.size = size;
2014                 event.spawn_particle.collisiondetection =
2015                                 collisiondetection;
2016                 event.spawn_particle.texture = new std::string(texture);
2017
2018                 m_client_event_queue.push_back(event);
2019         }
2020         else if(command == TOCLIENT_ADD_PARTICLESPAWNER)
2021         {
2022                 std::string datastring((char*)&data[2], datasize-2);
2023                 std::istringstream is(datastring, std::ios_base::binary);
2024
2025                 u16 amount = readU16(is);
2026                 float spawntime = readF1000(is);
2027                 v3f minpos = readV3F1000(is);
2028                 v3f maxpos = readV3F1000(is);
2029                 v3f minvel = readV3F1000(is);
2030                 v3f maxvel = readV3F1000(is);
2031                 v3f minacc = readV3F1000(is);
2032                 v3f maxacc = readV3F1000(is);
2033                 float minexptime = readF1000(is);
2034                 float maxexptime = readF1000(is);
2035                 float minsize = readF1000(is);
2036                 float maxsize = readF1000(is);
2037                 bool collisiondetection = readU8(is);
2038                 std::string texture = deSerializeLongString(is);
2039                 u32 id = readU32(is);
2040
2041                 ClientEvent event;
2042                 event.type = CE_ADD_PARTICLESPAWNER;
2043                 event.add_particlespawner.amount = amount;
2044                 event.add_particlespawner.spawntime = spawntime;
2045
2046                 event.add_particlespawner.minpos = new v3f (minpos);
2047                 event.add_particlespawner.maxpos = new v3f (maxpos);
2048                 event.add_particlespawner.minvel = new v3f (minvel);
2049                 event.add_particlespawner.maxvel = new v3f (maxvel);
2050                 event.add_particlespawner.minacc = new v3f (minacc);
2051                 event.add_particlespawner.maxacc = new v3f (maxacc);
2052
2053                 event.add_particlespawner.minexptime = minexptime;
2054                 event.add_particlespawner.maxexptime = maxexptime;
2055                 event.add_particlespawner.minsize = minsize;
2056                 event.add_particlespawner.maxsize = maxsize;
2057                 event.add_particlespawner.collisiondetection = collisiondetection;
2058                 event.add_particlespawner.texture = new std::string(texture);
2059                 event.add_particlespawner.id = id;
2060
2061                 m_client_event_queue.push_back(event);
2062         }
2063         else if(command == TOCLIENT_DELETE_PARTICLESPAWNER)
2064         {
2065                 std::string datastring((char*)&data[2], datasize-2);
2066                 std::istringstream is(datastring, std::ios_base::binary);
2067
2068                 u32 id = readU16(is);
2069
2070                 ClientEvent event;
2071                 event.type = CE_DELETE_PARTICLESPAWNER;
2072                 event.delete_particlespawner.id = id;
2073
2074                 m_client_event_queue.push_back(event);
2075         }
2076         else if(command == TOCLIENT_HUDADD)
2077         {
2078                 std::string datastring((char *)&data[2], datasize - 2);
2079                 std::istringstream is(datastring, std::ios_base::binary);
2080
2081                 u32 id           = readU32(is);
2082                 u8 type          = readU8(is);
2083                 v2f pos          = readV2F1000(is);
2084                 std::string name = deSerializeString(is);
2085                 v2f scale        = readV2F1000(is);
2086                 std::string text = deSerializeString(is);
2087                 u32 number       = readU32(is);
2088                 u32 item         = readU32(is);
2089                 u32 dir          = readU32(is);
2090                 v2f align        = readV2F1000(is);
2091                 v2f offset       = readV2F1000(is);
2092
2093                 ClientEvent event;
2094                 event.type = CE_HUDADD;
2095                 event.hudadd.id     = id;
2096                 event.hudadd.type   = type;
2097                 event.hudadd.pos    = new v2f(pos);
2098                 event.hudadd.name   = new std::string(name);
2099                 event.hudadd.scale  = new v2f(scale);
2100                 event.hudadd.text   = new std::string(text);
2101                 event.hudadd.number = number;
2102                 event.hudadd.item   = item;
2103                 event.hudadd.dir    = dir;
2104                 event.hudadd.align  = new v2f(align);
2105                 event.hudadd.offset = new v2f(offset);
2106                 m_client_event_queue.push_back(event);
2107         }
2108         else if(command == TOCLIENT_HUDRM)
2109         {
2110                 std::string datastring((char *)&data[2], datasize - 2);
2111                 std::istringstream is(datastring, std::ios_base::binary);
2112
2113                 u32 id = readU32(is);
2114
2115                 ClientEvent event;
2116                 event.type = CE_HUDRM;
2117                 event.hudrm.id = id;
2118                 m_client_event_queue.push_back(event);
2119         }
2120         else if(command == TOCLIENT_HUDCHANGE)
2121         {       
2122                 std::string sdata;
2123                 v2f v2fdata;
2124                 u32 intdata = 0;
2125                 
2126                 std::string datastring((char *)&data[2], datasize - 2);
2127                 std::istringstream is(datastring, std::ios_base::binary);
2128
2129                 u32 id  = readU32(is);
2130                 u8 stat = (HudElementStat)readU8(is);
2131                 
2132                 if (stat == HUD_STAT_POS || stat == HUD_STAT_SCALE ||
2133                         stat == HUD_STAT_ALIGN || stat == HUD_STAT_OFFSET)
2134                         v2fdata = readV2F1000(is);
2135                 else if (stat == HUD_STAT_NAME || stat == HUD_STAT_TEXT)
2136                         sdata = deSerializeString(is);
2137                 else
2138                         intdata = readU32(is);
2139                 
2140                 ClientEvent event;
2141                 event.type = CE_HUDCHANGE;
2142                 event.hudchange.id      = id;
2143                 event.hudchange.stat    = (HudElementStat)stat;
2144                 event.hudchange.v2fdata = new v2f(v2fdata);
2145                 event.hudchange.sdata   = new std::string(sdata);
2146                 event.hudchange.data    = intdata;
2147                 m_client_event_queue.push_back(event);
2148         }
2149         else if(command == TOCLIENT_HUD_SET_FLAGS)
2150         {       
2151                 std::string datastring((char *)&data[2], datasize - 2);
2152                 std::istringstream is(datastring, std::ios_base::binary);
2153
2154                 Player *player = m_env.getLocalPlayer();
2155                 assert(player != NULL);
2156
2157                 u32 flags = readU32(is);
2158                 u32 mask  = readU32(is);
2159                 
2160                 player->hud_flags &= ~mask;
2161                 player->hud_flags |= flags;
2162         }
2163         else if(command == TOCLIENT_HUD_SET_PARAM)
2164         {
2165                 std::string datastring((char *)&data[2], datasize - 2);
2166                 std::istringstream is(datastring, std::ios_base::binary);
2167
2168                 Player *player = m_env.getLocalPlayer();
2169                 assert(player != NULL);
2170
2171                 u16 param         = readU16(is);
2172                 std::string value = deSerializeString(is);
2173
2174                 if(param == HUD_PARAM_HOTBAR_ITEMCOUNT && value.size() == 4){
2175                         s32 hotbar_itemcount = readS32((u8*) value.c_str());
2176                         if(hotbar_itemcount > 0 && hotbar_itemcount <= HUD_HOTBAR_ITEMCOUNT_MAX)
2177                                 player->hud_hotbar_itemcount = hotbar_itemcount;
2178                 }
2179         }
2180         else
2181         {
2182                 infostream<<"Client: Ignoring unknown command "
2183                                 <<command<<std::endl;
2184         }
2185 }
2186
2187 void Client::Send(u16 channelnum, SharedBuffer<u8> data, bool reliable)
2188 {
2189         //JMutexAutoLock lock(m_con_mutex); //bulk comment-out
2190         m_con.Send(PEER_ID_SERVER, channelnum, data, reliable);
2191 }
2192
2193 void Client::interact(u8 action, const PointedThing& pointed)
2194 {
2195         if(connectedAndInitialized() == false){
2196                 infostream<<"Client::interact() "
2197                                 "cancelled (not connected)"
2198                                 <<std::endl;
2199                 return;
2200         }
2201
2202         std::ostringstream os(std::ios_base::binary);
2203
2204         /*
2205                 [0] u16 command
2206                 [2] u8 action
2207                 [3] u16 item
2208                 [5] u32 length of the next item
2209                 [9] serialized PointedThing
2210                 actions:
2211                 0: start digging (from undersurface) or use
2212                 1: stop digging (all parameters ignored)
2213                 2: digging completed
2214                 3: place block or item (to abovesurface)
2215                 4: use item
2216         */
2217         writeU16(os, TOSERVER_INTERACT);
2218         writeU8(os, action);
2219         writeU16(os, getPlayerItem());
2220         std::ostringstream tmp_os(std::ios::binary);
2221         pointed.serialize(tmp_os);
2222         os<<serializeLongString(tmp_os.str());
2223
2224         std::string s = os.str();
2225         SharedBuffer<u8> data((u8*)s.c_str(), s.size());
2226
2227         // Send as reliable
2228         Send(0, data, true);
2229 }
2230
2231 void Client::sendNodemetaFields(v3s16 p, const std::string &formname,
2232                 const std::map<std::string, std::string> &fields)
2233 {
2234         std::ostringstream os(std::ios_base::binary);
2235
2236         writeU16(os, TOSERVER_NODEMETA_FIELDS);
2237         writeV3S16(os, p);
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::sendInventoryFields(const std::string &formname, 
2256                 const std::map<std::string, std::string> &fields)
2257 {
2258         std::ostringstream os(std::ios_base::binary);
2259
2260         writeU16(os, TOSERVER_INVENTORY_FIELDS);
2261         os<<serializeString(formname);
2262         writeU16(os, fields.size());
2263         for(std::map<std::string, std::string>::const_iterator
2264                         i = fields.begin(); i != fields.end(); i++){
2265                 const std::string &name = i->first;
2266                 const std::string &value = i->second;
2267                 os<<serializeString(name);
2268                 os<<serializeLongString(value);
2269         }
2270
2271         // Make data buffer
2272         std::string s = os.str();
2273         SharedBuffer<u8> data((u8*)s.c_str(), s.size());
2274         // Send as reliable
2275         Send(0, data, true);
2276 }
2277
2278 void Client::sendInventoryAction(InventoryAction *a)
2279 {
2280         std::ostringstream os(std::ios_base::binary);
2281         u8 buf[12];
2282         
2283         // Write command
2284         writeU16(buf, TOSERVER_INVENTORY_ACTION);
2285         os.write((char*)buf, 2);
2286
2287         a->serialize(os);
2288         
2289         // Make data buffer
2290         std::string s = os.str();
2291         SharedBuffer<u8> data((u8*)s.c_str(), s.size());
2292         // Send as reliable
2293         Send(0, data, true);
2294 }
2295
2296 void Client::sendChatMessage(const std::wstring &message)
2297 {
2298         std::ostringstream os(std::ios_base::binary);
2299         u8 buf[12];
2300         
2301         // Write command
2302         writeU16(buf, TOSERVER_CHAT_MESSAGE);
2303         os.write((char*)buf, 2);
2304         
2305         // Write length
2306         writeU16(buf, message.size());
2307         os.write((char*)buf, 2);
2308         
2309         // Write string
2310         for(u32 i=0; i<message.size(); i++)
2311         {
2312                 u16 w = message[i];
2313                 writeU16(buf, w);
2314                 os.write((char*)buf, 2);
2315         }
2316         
2317         // Make data buffer
2318         std::string s = os.str();
2319         SharedBuffer<u8> data((u8*)s.c_str(), s.size());
2320         // Send as reliable
2321         Send(0, data, true);
2322 }
2323
2324 void Client::sendChangePassword(const std::wstring oldpassword,
2325                 const std::wstring newpassword)
2326 {
2327         Player *player = m_env.getLocalPlayer();
2328         if(player == NULL)
2329                 return;
2330
2331         std::string playername = player->getName();
2332         std::string oldpwd = translatePassword(playername, oldpassword);
2333         std::string newpwd = translatePassword(playername, newpassword);
2334
2335         std::ostringstream os(std::ios_base::binary);
2336         u8 buf[2+PASSWORD_SIZE*2];
2337         /*
2338                 [0] u16 TOSERVER_PASSWORD
2339                 [2] u8[28] old password
2340                 [30] u8[28] new password
2341         */
2342
2343         writeU16(buf, TOSERVER_PASSWORD);
2344         for(u32 i=0;i<PASSWORD_SIZE-1;i++)
2345         {
2346                 buf[2+i] = i<oldpwd.length()?oldpwd[i]:0;
2347                 buf[30+i] = i<newpwd.length()?newpwd[i]:0;
2348         }
2349         buf[2+PASSWORD_SIZE-1] = 0;
2350         buf[30+PASSWORD_SIZE-1] = 0;
2351         os.write((char*)buf, 2+PASSWORD_SIZE*2);
2352
2353         // Make data buffer
2354         std::string s = os.str();
2355         SharedBuffer<u8> data((u8*)s.c_str(), s.size());
2356         // Send as reliable
2357         Send(0, data, true);
2358 }
2359
2360
2361 void Client::sendDamage(u8 damage)
2362 {
2363         DSTACK(__FUNCTION_NAME);
2364         std::ostringstream os(std::ios_base::binary);
2365
2366         writeU16(os, TOSERVER_DAMAGE);
2367         writeU8(os, damage);
2368
2369         // Make data buffer
2370         std::string s = os.str();
2371         SharedBuffer<u8> data((u8*)s.c_str(), s.size());
2372         // Send as reliable
2373         Send(0, data, true);
2374 }
2375
2376 void Client::sendBreath(u16 breath)
2377 {
2378         DSTACK(__FUNCTION_NAME);
2379         std::ostringstream os(std::ios_base::binary);
2380
2381         writeU16(os, TOSERVER_BREATH);
2382         writeU16(os, breath);
2383         // Make data buffer
2384         std::string s = os.str();
2385         SharedBuffer<u8> data((u8*)s.c_str(), s.size());
2386         // Send as reliable
2387         Send(0, data, true);
2388 }
2389
2390 void Client::sendRespawn()
2391 {
2392         DSTACK(__FUNCTION_NAME);
2393         std::ostringstream os(std::ios_base::binary);
2394
2395         writeU16(os, TOSERVER_RESPAWN);
2396
2397         // Make data buffer
2398         std::string s = os.str();
2399         SharedBuffer<u8> data((u8*)s.c_str(), s.size());
2400         // Send as reliable
2401         Send(0, data, true);
2402 }
2403
2404 void Client::sendPlayerPos()
2405 {
2406         //JMutexAutoLock envlock(m_env_mutex); //bulk comment-out
2407         
2408         LocalPlayer *myplayer = m_env.getLocalPlayer();
2409         if(myplayer == NULL)
2410                 return;
2411
2412         // Save bandwidth by only updating position when something changed
2413         if(myplayer->last_position == myplayer->getPosition() &&
2414                         myplayer->last_speed == myplayer->getSpeed() &&
2415                         myplayer->last_pitch == myplayer->getPitch() &&
2416                         myplayer->last_yaw == myplayer->getYaw() &&
2417                         myplayer->last_keyPressed == myplayer->keyPressed)
2418                 return;
2419
2420         myplayer->last_position = myplayer->getPosition();
2421         myplayer->last_speed = myplayer->getSpeed();
2422         myplayer->last_pitch = myplayer->getPitch();
2423         myplayer->last_yaw = myplayer->getYaw();
2424         myplayer->last_keyPressed = myplayer->keyPressed;
2425
2426         u16 our_peer_id;
2427         {
2428                 //JMutexAutoLock lock(m_con_mutex); //bulk comment-out
2429                 our_peer_id = m_con.GetPeerID();
2430         }
2431         
2432         // Set peer id if not set already
2433         if(myplayer->peer_id == PEER_ID_INEXISTENT)
2434                 myplayer->peer_id = our_peer_id;
2435         // Check that an existing peer_id is the same as the connection's
2436         assert(myplayer->peer_id == our_peer_id);
2437         
2438         v3f pf = myplayer->getPosition();
2439         v3s32 position(pf.X*100, pf.Y*100, pf.Z*100);
2440         v3f sf = myplayer->getSpeed();
2441         v3s32 speed(sf.X*100, sf.Y*100, sf.Z*100);
2442         s32 pitch = myplayer->getPitch() * 100;
2443         s32 yaw = myplayer->getYaw() * 100;
2444         u32 keyPressed=myplayer->keyPressed;
2445         /*
2446                 Format:
2447                 [0] u16 command
2448                 [2] v3s32 position*100
2449                 [2+12] v3s32 speed*100
2450                 [2+12+12] s32 pitch*100
2451                 [2+12+12+4] s32 yaw*100
2452                 [2+12+12+4+4] u32 keyPressed
2453         */
2454         SharedBuffer<u8> data(2+12+12+4+4+4);
2455         writeU16(&data[0], TOSERVER_PLAYERPOS);
2456         writeV3S32(&data[2], position);
2457         writeV3S32(&data[2+12], speed);
2458         writeS32(&data[2+12+12], pitch);
2459         writeS32(&data[2+12+12+4], yaw);        
2460         writeU32(&data[2+12+12+4+4], keyPressed);
2461         // Send as unreliable
2462         Send(0, data, false);
2463 }
2464
2465 void Client::sendPlayerItem(u16 item)
2466 {
2467         Player *myplayer = m_env.getLocalPlayer();
2468         if(myplayer == NULL)
2469                 return;
2470
2471         u16 our_peer_id = m_con.GetPeerID();
2472
2473         // Set peer id if not set already
2474         if(myplayer->peer_id == PEER_ID_INEXISTENT)
2475                 myplayer->peer_id = our_peer_id;
2476         // Check that an existing peer_id is the same as the connection's
2477         assert(myplayer->peer_id == our_peer_id);
2478
2479         SharedBuffer<u8> data(2+2);
2480         writeU16(&data[0], TOSERVER_PLAYERITEM);
2481         writeU16(&data[2], item);
2482
2483         // Send as reliable
2484         Send(0, data, true);
2485 }
2486
2487 void Client::removeNode(v3s16 p)
2488 {
2489         std::map<v3s16, MapBlock*> modified_blocks;
2490
2491         try
2492         {
2493                 //TimeTaker t("removeNodeAndUpdate", m_device);
2494                 m_env.getMap().removeNodeAndUpdate(p, modified_blocks);
2495         }
2496         catch(InvalidPositionException &e)
2497         {
2498         }
2499         
2500         // add urgent task to update the modified node
2501         addUpdateMeshTaskForNode(p, false, true);
2502
2503         for(std::map<v3s16, MapBlock * >::iterator
2504                         i = modified_blocks.begin();
2505                         i != modified_blocks.end(); ++i)
2506         {
2507                 addUpdateMeshTaskWithEdge(i->first);
2508         }
2509 }
2510
2511 void Client::addNode(v3s16 p, MapNode n)
2512 {
2513         TimeTaker timer1("Client::addNode()");
2514
2515         std::map<v3s16, MapBlock*> modified_blocks;
2516
2517         try
2518         {
2519                 //TimeTaker timer3("Client::addNode(): addNodeAndUpdate");
2520                 m_env.getMap().addNodeAndUpdate(p, n, modified_blocks);
2521         }
2522         catch(InvalidPositionException &e)
2523         {}
2524         
2525         for(std::map<v3s16, MapBlock * >::iterator
2526                         i = modified_blocks.begin();
2527                         i != modified_blocks.end(); ++i)
2528         {
2529                 addUpdateMeshTaskWithEdge(i->first);
2530         }
2531 }
2532         
2533 void Client::setPlayerControl(PlayerControl &control)
2534 {
2535         //JMutexAutoLock envlock(m_env_mutex); //bulk comment-out
2536         LocalPlayer *player = m_env.getLocalPlayer();
2537         assert(player != NULL);
2538         player->control = control;
2539 }
2540
2541 void Client::selectPlayerItem(u16 item)
2542 {
2543         //JMutexAutoLock envlock(m_env_mutex); //bulk comment-out
2544         m_playeritem = item;
2545         m_inventory_updated = true;
2546         sendPlayerItem(item);
2547 }
2548
2549 // Returns true if the inventory of the local player has been
2550 // updated from the server. If it is true, it is set to false.
2551 bool Client::getLocalInventoryUpdated()
2552 {
2553         // m_inventory_updated is behind envlock
2554         //JMutexAutoLock envlock(m_env_mutex); //bulk comment-out
2555         bool updated = m_inventory_updated;
2556         m_inventory_updated = false;
2557         return updated;
2558 }
2559
2560 // Copies the inventory of the local player to parameter
2561 void Client::getLocalInventory(Inventory &dst)
2562 {
2563         //JMutexAutoLock envlock(m_env_mutex); //bulk comment-out
2564         Player *player = m_env.getLocalPlayer();
2565         assert(player != NULL);
2566         dst = player->inventory;
2567 }
2568
2569 Inventory* Client::getInventory(const InventoryLocation &loc)
2570 {
2571         switch(loc.type){
2572         case InventoryLocation::UNDEFINED:
2573         {}
2574         break;
2575         case InventoryLocation::CURRENT_PLAYER:
2576         {
2577                 Player *player = m_env.getLocalPlayer();
2578                 assert(player != NULL);
2579                 return &player->inventory;
2580         }
2581         break;
2582         case InventoryLocation::PLAYER:
2583         {
2584                 Player *player = m_env.getPlayer(loc.name.c_str());
2585                 if(!player)
2586                         return NULL;
2587                 return &player->inventory;
2588         }
2589         break;
2590         case InventoryLocation::NODEMETA:
2591         {
2592                 NodeMetadata *meta = m_env.getMap().getNodeMetadata(loc.p);
2593                 if(!meta)
2594                         return NULL;
2595                 return meta->getInventory();
2596         }
2597         break;
2598         case InventoryLocation::DETACHED:
2599         {
2600                 if(m_detached_inventories.count(loc.name) == 0)
2601                         return NULL;
2602                 return m_detached_inventories[loc.name];
2603         }
2604         break;
2605         default:
2606                 assert(0);
2607         }
2608         return NULL;
2609 }
2610 void Client::inventoryAction(InventoryAction *a)
2611 {
2612         /*
2613                 Send it to the server
2614         */
2615         sendInventoryAction(a);
2616
2617         /*
2618                 Predict some local inventory changes
2619         */
2620         a->clientApply(this, this);
2621
2622         // Remove it
2623         delete a;
2624 }
2625
2626 ClientActiveObject * Client::getSelectedActiveObject(
2627                 f32 max_d,
2628                 v3f from_pos_f_on_map,
2629                 core::line3d<f32> shootline_on_map
2630         )
2631 {
2632         std::vector<DistanceSortedActiveObject> objects;
2633
2634         m_env.getActiveObjects(from_pos_f_on_map, max_d, objects);
2635
2636         //infostream<<"Collected "<<objects.size()<<" nearby objects"<<std::endl;
2637         
2638         // Sort them.
2639         // After this, the closest object is the first in the array.
2640         std::sort(objects.begin(), objects.end());
2641
2642         for(u32 i=0; i<objects.size(); i++)
2643         {
2644                 ClientActiveObject *obj = objects[i].obj;
2645                 
2646                 core::aabbox3d<f32> *selection_box = obj->getSelectionBox();
2647                 if(selection_box == NULL)
2648                         continue;
2649
2650                 v3f pos = obj->getPosition();
2651
2652                 core::aabbox3d<f32> offsetted_box(
2653                                 selection_box->MinEdge + pos,
2654                                 selection_box->MaxEdge + pos
2655                 );
2656
2657                 if(offsetted_box.intersectsWithLine(shootline_on_map))
2658                 {
2659                         //infostream<<"Returning selected object"<<std::endl;
2660                         return obj;
2661                 }
2662         }
2663
2664         //infostream<<"No object selected; returning NULL."<<std::endl;
2665         return NULL;
2666 }
2667
2668 void Client::printDebugInfo(std::ostream &os)
2669 {
2670         //JMutexAutoLock lock1(m_fetchblock_mutex);
2671         /*JMutexAutoLock lock2(m_incoming_queue_mutex);
2672
2673         os<<"m_incoming_queue.getSize()="<<m_incoming_queue.getSize()
2674                 //<<", m_fetchblock_history.size()="<<m_fetchblock_history.size()
2675                 //<<", m_opt_not_found_history.size()="<<m_opt_not_found_history.size()
2676                 <<std::endl;*/
2677 }
2678
2679 std::list<std::string> Client::getConnectedPlayerNames()
2680 {
2681         return m_env.getPlayerNames();
2682 }
2683
2684 float Client::getAnimationTime()
2685 {
2686         return m_animation_time;
2687 }
2688
2689 int Client::getCrackLevel()
2690 {
2691         return m_crack_level;
2692 }
2693
2694 void Client::setCrack(int level, v3s16 pos)
2695 {
2696         int old_crack_level = m_crack_level;
2697         v3s16 old_crack_pos = m_crack_pos;
2698
2699         m_crack_level = level;
2700         m_crack_pos = pos;
2701
2702         if(old_crack_level >= 0 && (level < 0 || pos != old_crack_pos))
2703         {
2704                 // remove old crack
2705                 addUpdateMeshTaskForNode(old_crack_pos, false, true);
2706         }
2707         if(level >= 0 && (old_crack_level < 0 || pos != old_crack_pos))
2708         {
2709                 // add new crack
2710                 addUpdateMeshTaskForNode(pos, false, true);
2711         }
2712 }
2713
2714 u16 Client::getHP()
2715 {
2716         Player *player = m_env.getLocalPlayer();
2717         assert(player != NULL);
2718         return player->hp;
2719 }
2720
2721 u16 Client::getBreath()
2722 {
2723         Player *player = m_env.getLocalPlayer();
2724         assert(player != NULL);
2725         return player->getBreath();
2726 }
2727
2728 bool Client::getChatMessage(std::wstring &message)
2729 {
2730         if(m_chat_queue.size() == 0)
2731                 return false;
2732         message = m_chat_queue.pop_front();
2733         return true;
2734 }
2735
2736 void Client::typeChatMessage(const std::wstring &message)
2737 {
2738         // Discard empty line
2739         if(message == L"")
2740                 return;
2741
2742         // Send to others
2743         sendChatMessage(message);
2744
2745         // Show locally
2746         if (message[0] == L'/')
2747         {
2748                 m_chat_queue.push_back(
2749                                 (std::wstring)L"issued command: "+message);
2750         }
2751         else
2752         {
2753                 LocalPlayer *player = m_env.getLocalPlayer();
2754                 assert(player != NULL);
2755                 std::wstring name = narrow_to_wide(player->getName());
2756                 m_chat_queue.push_back(
2757                                 (std::wstring)L"<"+name+L"> "+message);
2758         }
2759 }
2760
2761 void Client::addUpdateMeshTask(v3s16 p, bool ack_to_server, bool urgent)
2762 {
2763         /*infostream<<"Client::addUpdateMeshTask(): "
2764                         <<"("<<p.X<<","<<p.Y<<","<<p.Z<<")"
2765                         <<" ack_to_server="<<ack_to_server
2766                         <<" urgent="<<urgent
2767                         <<std::endl;*/
2768
2769         MapBlock *b = m_env.getMap().getBlockNoCreateNoEx(p);
2770         if(b == NULL)
2771                 return;
2772         
2773         /*
2774                 Create a task to update the mesh of the block
2775         */
2776         
2777         MeshMakeData *data = new MeshMakeData(this);
2778         
2779         {
2780                 //TimeTaker timer("data fill");
2781                 // Release: ~0ms
2782                 // Debug: 1-6ms, avg=2ms
2783                 data->fill(b);
2784                 data->setCrack(m_crack_level, m_crack_pos);
2785                 data->setSmoothLighting(g_settings->getBool("smooth_lighting"));
2786         }
2787
2788         // Debug wait
2789         //while(m_mesh_update_thread.m_queue_in.size() > 0) sleep_ms(10);
2790         
2791         // Add task to queue
2792         m_mesh_update_thread.m_queue_in.addBlock(p, data, ack_to_server, urgent);
2793
2794         /*infostream<<"Mesh update input queue size is "
2795                         <<m_mesh_update_thread.m_queue_in.size()
2796                         <<std::endl;*/
2797 }
2798
2799 void Client::addUpdateMeshTaskWithEdge(v3s16 blockpos, bool ack_to_server, bool urgent)
2800 {
2801         /*{
2802                 v3s16 p = blockpos;
2803                 infostream<<"Client::addUpdateMeshTaskWithEdge(): "
2804                                 <<"("<<p.X<<","<<p.Y<<","<<p.Z<<")"
2805                                 <<std::endl;
2806         }*/
2807
2808         try{
2809                 v3s16 p = blockpos + v3s16(0,0,0);
2810                 //MapBlock *b = m_env.getMap().getBlockNoCreate(p);
2811                 addUpdateMeshTask(p, ack_to_server, urgent);
2812         }
2813         catch(InvalidPositionException &e){}
2814         // Leading edge
2815         for (int i=0;i<6;i++)
2816         {
2817                 try{
2818                         v3s16 p = blockpos + g_6dirs[i];
2819                         addUpdateMeshTask(p, false, urgent);
2820                 }
2821                 catch(InvalidPositionException &e){}
2822         }
2823 }
2824
2825 void Client::addUpdateMeshTaskForNode(v3s16 nodepos, bool ack_to_server, bool urgent)
2826 {
2827         {
2828                 v3s16 p = nodepos;
2829                 infostream<<"Client::addUpdateMeshTaskForNode(): "
2830                                 <<"("<<p.X<<","<<p.Y<<","<<p.Z<<")"
2831                                 <<std::endl;
2832         }
2833
2834         v3s16 blockpos = getNodeBlockPos(nodepos);
2835         v3s16 blockpos_relative = blockpos * MAP_BLOCKSIZE;
2836
2837         try{
2838                 v3s16 p = blockpos + v3s16(0,0,0);
2839                 addUpdateMeshTask(p, ack_to_server, urgent);
2840         }
2841         catch(InvalidPositionException &e){}
2842         // Leading edge
2843         if(nodepos.X == blockpos_relative.X){
2844                 try{
2845                         v3s16 p = blockpos + v3s16(-1,0,0);
2846                         addUpdateMeshTask(p, false, urgent);
2847                 }
2848                 catch(InvalidPositionException &e){}
2849         }
2850         if(nodepos.Y == blockpos_relative.Y){
2851                 try{
2852                         v3s16 p = blockpos + v3s16(0,-1,0);
2853                         addUpdateMeshTask(p, false, urgent);
2854                 }
2855                 catch(InvalidPositionException &e){}
2856         }
2857         if(nodepos.Z == blockpos_relative.Z){
2858                 try{
2859                         v3s16 p = blockpos + v3s16(0,0,-1);
2860                         addUpdateMeshTask(p, false, urgent);
2861                 }
2862                 catch(InvalidPositionException &e){}
2863         }
2864 }
2865
2866 ClientEvent Client::getClientEvent()
2867 {
2868         if(m_client_event_queue.size() == 0)
2869         {
2870                 ClientEvent event;
2871                 event.type = CE_NONE;
2872                 return event;
2873         }
2874         return m_client_event_queue.pop_front();
2875 }
2876
2877 void draw_load_screen(const std::wstring &text,
2878                 IrrlichtDevice* device, gui::IGUIFont* font,
2879                 float dtime=0 ,int percent=0, bool clouds=true);
2880 void Client::afterContentReceived(IrrlichtDevice *device, gui::IGUIFont* font)
2881 {
2882         infostream<<"Client::afterContentReceived() started"<<std::endl;
2883         assert(m_itemdef_received);
2884         assert(m_nodedef_received);
2885         assert(texturesReceived());
2886         
2887         // remove the information about which checksum each texture
2888         // ought to have
2889         m_media_name_sha1_map.clear();
2890
2891         // Rebuild inherited images and recreate textures
2892         infostream<<"- Rebuilding images and textures"<<std::endl;
2893         m_tsrc->rebuildImagesAndTextures();
2894
2895         // Rebuild shaders
2896         infostream<<"- Rebuilding shaders"<<std::endl;
2897         m_shsrc->rebuildShaders();
2898
2899         // Update node aliases
2900         infostream<<"- Updating node aliases"<<std::endl;
2901         m_nodedef->updateAliases(m_itemdef);
2902
2903         // Update node textures
2904         infostream<<"- Updating node textures"<<std::endl;
2905         m_nodedef->updateTextures(m_tsrc);
2906
2907         // Preload item textures and meshes if configured to
2908         if(g_settings->getBool("preload_item_visuals"))
2909         {
2910                 verbosestream<<"Updating item textures and meshes"<<std::endl;
2911                 wchar_t* text = wgettext("Item textures...");
2912                 draw_load_screen(text,device,font,0,0);
2913                 std::set<std::string> names = m_itemdef->getAll();
2914                 size_t size = names.size();
2915                 size_t count = 0;
2916                 int percent = 0;
2917                 for(std::set<std::string>::const_iterator
2918                                 i = names.begin(); i != names.end(); ++i){
2919                         // Asking for these caches the result
2920                         m_itemdef->getInventoryTexture(*i, this);
2921                         m_itemdef->getWieldMesh(*i, this);
2922                         count++;
2923                         percent = count*100/size;
2924                         if (count%50 == 0) // only update every 50 item
2925                                 draw_load_screen(text,device,font,0,percent);
2926                 }
2927                 delete[] text;
2928         }
2929
2930         // Start mesh update thread after setting up content definitions
2931         infostream<<"- Starting mesh update thread"<<std::endl;
2932         m_mesh_update_thread.Start();
2933         
2934         infostream<<"Client::afterContentReceived() done"<<std::endl;
2935 }
2936
2937 float Client::getRTT(void)
2938 {
2939         try{
2940                 return m_con.GetPeerAvgRTT(PEER_ID_SERVER);
2941         } catch(con::PeerNotFoundException &e){
2942                 return 1337;
2943         }
2944 }
2945
2946 // IGameDef interface
2947 // Under envlock
2948 IItemDefManager* Client::getItemDefManager()
2949 {
2950         return m_itemdef;
2951 }
2952 INodeDefManager* Client::getNodeDefManager()
2953 {
2954         return m_nodedef;
2955 }
2956 ICraftDefManager* Client::getCraftDefManager()
2957 {
2958         return NULL;
2959         //return m_craftdef;
2960 }
2961 ITextureSource* Client::getTextureSource()
2962 {
2963         return m_tsrc;
2964 }
2965 IShaderSource* Client::getShaderSource()
2966 {
2967         return m_shsrc;
2968 }
2969 u16 Client::allocateUnknownNodeId(const std::string &name)
2970 {
2971         errorstream<<"Client::allocateUnknownNodeId(): "
2972                         <<"Client cannot allocate node IDs"<<std::endl;
2973         assert(0);
2974         return CONTENT_IGNORE;
2975 }
2976 ISoundManager* Client::getSoundManager()
2977 {
2978         return m_sound;
2979 }
2980 MtEventManager* Client::getEventManager()
2981 {
2982         return m_event;
2983 }
2984