Client: better m_proto_ver initialisation
[oweals/minetest.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 <iostream>
21 #include <algorithm>
22 #include <sstream>
23 #include <IFileSystem.h>
24 #include "jthread/jmutexautolock.h"
25 #include "util/auth.h"
26 #include "util/directiontables.h"
27 #include "util/pointedthing.h"
28 #include "util/serialize.h"
29 #include "util/string.h"
30 #include "util/srp.h"
31 #include "client.h"
32 #include "network/clientopcodes.h"
33 #include "filesys.h"
34 #include "porting.h"
35 #include "mapblock_mesh.h"
36 #include "mapblock.h"
37 #include "minimap.h"
38 #include "settings.h"
39 #include "profiler.h"
40 #include "gettext.h"
41 #include "log.h"
42 #include "nodemetadata.h"
43 #include "itemdef.h"
44 #include "shader.h"
45 #include "clientmap.h"
46 #include "clientmedia.h"
47 #include "sound.h"
48 #include "IMeshCache.h"
49 #include "config.h"
50 #include "version.h"
51 #include "drawscene.h"
52 #include "database-sqlite3.h"
53 #include "serialization.h"
54 #include "guiscalingfilter.h"
55
56 extern gui::IGUIEnvironment* guienv;
57
58 /*
59         QueuedMeshUpdate
60 */
61
62 QueuedMeshUpdate::QueuedMeshUpdate():
63         p(-1337,-1337,-1337),
64         data(NULL),
65         ack_block_to_server(false)
66 {
67 }
68
69 QueuedMeshUpdate::~QueuedMeshUpdate()
70 {
71         if(data)
72                 delete data;
73 }
74
75 /*
76         MeshUpdateQueue
77 */
78
79 MeshUpdateQueue::MeshUpdateQueue()
80 {
81 }
82
83 MeshUpdateQueue::~MeshUpdateQueue()
84 {
85         JMutexAutoLock lock(m_mutex);
86
87         for(std::vector<QueuedMeshUpdate*>::iterator
88                         i = m_queue.begin();
89                         i != m_queue.end(); i++)
90         {
91                 QueuedMeshUpdate *q = *i;
92                 delete q;
93         }
94 }
95
96 /*
97         peer_id=0 adds with nobody to send to
98 */
99 void MeshUpdateQueue::addBlock(v3s16 p, MeshMakeData *data, bool ack_block_to_server, bool urgent)
100 {
101         DSTACK(__FUNCTION_NAME);
102
103         assert(data);   // pre-condition
104
105         JMutexAutoLock lock(m_mutex);
106
107         if(urgent)
108                 m_urgents.insert(p);
109
110         /*
111                 Find if block is already in queue.
112                 If it is, update the data and quit.
113         */
114         for(std::vector<QueuedMeshUpdate*>::iterator
115                         i = m_queue.begin();
116                         i != m_queue.end(); i++)
117         {
118                 QueuedMeshUpdate *q = *i;
119                 if(q->p == p)
120                 {
121                         if(q->data)
122                                 delete q->data;
123                         q->data = data;
124                         if(ack_block_to_server)
125                                 q->ack_block_to_server = true;
126                         return;
127                 }
128         }
129
130         /*
131                 Add the block
132         */
133         QueuedMeshUpdate *q = new QueuedMeshUpdate;
134         q->p = p;
135         q->data = data;
136         q->ack_block_to_server = ack_block_to_server;
137         m_queue.push_back(q);
138 }
139
140 // Returned pointer must be deleted
141 // Returns NULL if queue is empty
142 QueuedMeshUpdate *MeshUpdateQueue::pop()
143 {
144         JMutexAutoLock lock(m_mutex);
145
146         bool must_be_urgent = !m_urgents.empty();
147         for(std::vector<QueuedMeshUpdate*>::iterator
148                         i = m_queue.begin();
149                         i != m_queue.end(); i++)
150         {
151                 QueuedMeshUpdate *q = *i;
152                 if(must_be_urgent && m_urgents.count(q->p) == 0)
153                         continue;
154                 m_queue.erase(i);
155                 m_urgents.erase(q->p);
156                 return q;
157         }
158         return NULL;
159 }
160
161 /*
162         MeshUpdateThread
163 */
164
165 void MeshUpdateThread::enqueueUpdate(v3s16 p, MeshMakeData *data,
166                 bool ack_block_to_server, bool urgent)
167 {
168         m_queue_in.addBlock(p, data, ack_block_to_server, urgent);
169         deferUpdate();
170 }
171
172 void MeshUpdateThread::doUpdate()
173 {
174         QueuedMeshUpdate *q;
175         while ((q = m_queue_in.pop())) {
176
177                 ScopeProfiler sp(g_profiler, "Client: Mesh making");
178
179                 MapBlockMesh *mesh_new = new MapBlockMesh(q->data, m_camera_offset);
180
181                 MeshUpdateResult r;
182                 r.p = q->p;
183                 r.mesh = mesh_new;
184                 r.ack_block_to_server = q->ack_block_to_server;
185
186                 m_queue_out.push_back(r);
187
188                 delete q;
189         }
190 }
191
192 /*
193         Client
194 */
195
196 Client::Client(
197                 IrrlichtDevice *device,
198                 const char *playername,
199                 std::string password,
200                 MapDrawControl &control,
201                 IWritableTextureSource *tsrc,
202                 IWritableShaderSource *shsrc,
203                 IWritableItemDefManager *itemdef,
204                 IWritableNodeDefManager *nodedef,
205                 ISoundManager *sound,
206                 MtEventManager *event,
207                 bool ipv6
208 ):
209         m_packetcounter_timer(0.0),
210         m_connection_reinit_timer(0.1),
211         m_avg_rtt_timer(0.0),
212         m_playerpos_send_timer(0.0),
213         m_ignore_damage_timer(0.0),
214         m_tsrc(tsrc),
215         m_shsrc(shsrc),
216         m_itemdef(itemdef),
217         m_nodedef(nodedef),
218         m_sound(sound),
219         m_event(event),
220         m_mesh_update_thread(),
221         m_env(
222                 new ClientMap(this, this, control,
223                         device->getSceneManager()->getRootSceneNode(),
224                         device->getSceneManager(), 666),
225                 device->getSceneManager(),
226                 tsrc, this, device
227         ),
228         m_particle_manager(&m_env),
229         m_con(PROTOCOL_ID, 512, CONNECTION_TIMEOUT, ipv6, this),
230         m_device(device),
231         m_server_ser_ver(SER_FMT_VER_INVALID),
232         m_proto_ver(0),
233         m_playeritem(0),
234         m_inventory_updated(false),
235         m_inventory_from_server(NULL),
236         m_inventory_from_server_age(0.0),
237         m_show_highlighted(false),
238         m_animation_time(0),
239         m_crack_level(-1),
240         m_crack_pos(0,0,0),
241         m_highlighted_pos(0,0,0),
242         m_map_seed(0),
243         m_password(password),
244         m_chosen_auth_mech(AUTH_MECHANISM_NONE),
245         m_auth_data(NULL),
246         m_access_denied(false),
247         m_itemdef_received(false),
248         m_nodedef_received(false),
249         m_media_downloader(new ClientMediaDownloader()),
250         m_time_of_day_set(false),
251         m_last_time_of_day_f(-1),
252         m_time_of_day_update_timer(0),
253         m_recommended_send_interval(0.1),
254         m_removed_sounds_check_timer(0),
255         m_state(LC_Created),
256         m_localdb(NULL)
257 {
258         // Add local player
259         m_env.addPlayer(new LocalPlayer(this, playername));
260
261         m_mapper = new Mapper(device, this);
262         m_cache_save_interval = g_settings->getU16("server_map_save_interval");
263
264         m_cache_smooth_lighting = g_settings->getBool("smooth_lighting");
265         m_cache_enable_shaders  = g_settings->getBool("enable_shaders");
266 }
267
268 void Client::Stop()
269 {
270         //request all client managed threads to stop
271         m_mesh_update_thread.Stop();
272         // Save local server map
273         if (m_localdb) {
274                 infostream << "Local map saving ended." << std::endl;
275                 m_localdb->endSave();
276         }
277 }
278
279 bool Client::isShutdown()
280 {
281
282         if (!m_mesh_update_thread.IsRunning()) return true;
283
284         return false;
285 }
286
287 Client::~Client()
288 {
289         m_con.Disconnect();
290
291         m_mesh_update_thread.Stop();
292         m_mesh_update_thread.Wait();
293         while(!m_mesh_update_thread.m_queue_out.empty()) {
294                 MeshUpdateResult r = m_mesh_update_thread.m_queue_out.pop_frontNoEx();
295                 delete r.mesh;
296         }
297
298
299         delete m_inventory_from_server;
300
301         // Delete detached inventories
302         for(std::map<std::string, Inventory*>::iterator
303                         i = m_detached_inventories.begin();
304                         i != m_detached_inventories.end(); i++){
305                 delete i->second;
306         }
307
308         // cleanup 3d model meshes on client shutdown
309         while (m_device->getSceneManager()->getMeshCache()->getMeshCount() != 0) {
310                 scene::IAnimatedMesh * mesh =
311                         m_device->getSceneManager()->getMeshCache()->getMeshByIndex(0);
312
313                 if (mesh != NULL)
314                         m_device->getSceneManager()->getMeshCache()->removeMesh(mesh);
315         }
316 }
317
318 void Client::connect(Address address,
319                 const std::string &address_name,
320                 bool is_local_server)
321 {
322         DSTACK(__FUNCTION_NAME);
323
324         initLocalMapSaving(address, address_name, is_local_server);
325
326         m_con.SetTimeoutMs(0);
327         m_con.Connect(address);
328 }
329
330 void Client::step(float dtime)
331 {
332         DSTACK(__FUNCTION_NAME);
333
334         // Limit a bit
335         if(dtime > 2.0)
336                 dtime = 2.0;
337
338         if(m_ignore_damage_timer > dtime)
339                 m_ignore_damage_timer -= dtime;
340         else
341                 m_ignore_damage_timer = 0.0;
342
343         m_animation_time += dtime;
344         if(m_animation_time > 60.0)
345                 m_animation_time -= 60.0;
346
347         m_time_of_day_update_timer += dtime;
348
349         ReceiveAll();
350
351         /*
352                 Packet counter
353         */
354         {
355                 float &counter = m_packetcounter_timer;
356                 counter -= dtime;
357                 if(counter <= 0.0)
358                 {
359                         counter = 20.0;
360
361                         infostream << "Client packetcounter (" << m_packetcounter_timer
362                                         << "):"<<std::endl;
363                         m_packetcounter.print(infostream);
364                         m_packetcounter.clear();
365                 }
366         }
367
368         // UGLY hack to fix 2 second startup delay caused by non existent
369         // server client startup synchronization in local server or singleplayer mode
370         static bool initial_step = true;
371         if (initial_step) {
372                 initial_step = false;
373         }
374         else if(m_state == LC_Created) {
375                 float &counter = m_connection_reinit_timer;
376                 counter -= dtime;
377                 if(counter <= 0.0) {
378                         counter = 2.0;
379
380                         Player *myplayer = m_env.getLocalPlayer();
381                         FATAL_ERROR_IF(myplayer == NULL, "Local player not found in environment.");
382
383                         // Send TOSERVER_INIT_LEGACY
384                         // [0] u16 TOSERVER_INIT_LEGACY
385                         // [2] u8 SER_FMT_VER_HIGHEST_READ
386                         // [3] u8[20] player_name
387                         // [23] u8[28] password (new in some version)
388                         // [51] u16 minimum supported network protocol version (added sometime)
389                         // [53] u16 maximum supported network protocol version (added later than the previous one)
390
391                         char pName[PLAYERNAME_SIZE];
392                         char pPassword[PASSWORD_SIZE];
393                         memset(pName, 0, PLAYERNAME_SIZE * sizeof(char));
394                         memset(pPassword, 0, PASSWORD_SIZE * sizeof(char));
395
396                         std::string hashed_password = translatePassword(myplayer->getName(), m_password);
397                         snprintf(pName, PLAYERNAME_SIZE, "%s", myplayer->getName());
398                         snprintf(pPassword, PASSWORD_SIZE, "%s", hashed_password.c_str());
399
400                         sendLegacyInit(pName, pPassword);
401                         if (LATEST_PROTOCOL_VERSION >= 25)
402                                 sendInit(myplayer->getName());
403                 }
404
405                 // Not connected, return
406                 return;
407         }
408
409         /*
410                 Do stuff if connected
411         */
412
413         /*
414                 Run Map's timers and unload unused data
415         */
416         const float map_timer_and_unload_dtime = 5.25;
417         if(m_map_timer_and_unload_interval.step(dtime, map_timer_and_unload_dtime)) {
418                 ScopeProfiler sp(g_profiler, "Client: map timer and unload");
419                 std::vector<v3s16> deleted_blocks;
420                 m_env.getMap().timerUpdate(map_timer_and_unload_dtime,
421                                 g_settings->getFloat("client_unload_unused_data_timeout"),
422                                 &deleted_blocks);
423
424                 /*
425                         Send info to server
426                         NOTE: This loop is intentionally iterated the way it is.
427                 */
428
429                 std::vector<v3s16>::iterator i = deleted_blocks.begin();
430                 std::vector<v3s16> sendlist;
431                 for(;;) {
432                         if(sendlist.size() == 255 || i == deleted_blocks.end()) {
433                                 if(sendlist.empty())
434                                         break;
435                                 /*
436                                         [0] u16 command
437                                         [2] u8 count
438                                         [3] v3s16 pos_0
439                                         [3+6] v3s16 pos_1
440                                         ...
441                                 */
442
443                                 sendDeletedBlocks(sendlist);
444
445                                 if(i == deleted_blocks.end())
446                                         break;
447
448                                 sendlist.clear();
449                         }
450
451                         sendlist.push_back(*i);
452                         ++i;
453                 }
454         }
455
456         /*
457                 Handle environment
458         */
459         // Control local player (0ms)
460         LocalPlayer *player = m_env.getLocalPlayer();
461         assert(player != NULL);
462         player->applyControl(dtime);
463
464         // Step environment
465         m_env.step(dtime);
466
467         /*
468                 Get events
469         */
470         for(;;) {
471                 ClientEnvEvent event = m_env.getClientEvent();
472                 if(event.type == CEE_NONE) {
473                         break;
474                 }
475                 else if(event.type == CEE_PLAYER_DAMAGE) {
476                         if(m_ignore_damage_timer <= 0) {
477                                 u8 damage = event.player_damage.amount;
478
479                                 if(event.player_damage.send_to_server)
480                                         sendDamage(damage);
481
482                                 // Add to ClientEvent queue
483                                 ClientEvent event;
484                                 event.type = CE_PLAYER_DAMAGE;
485                                 event.player_damage.amount = damage;
486                                 m_client_event_queue.push(event);
487                         }
488                 }
489                 else if(event.type == CEE_PLAYER_BREATH) {
490                                 u16 breath = event.player_breath.amount;
491                                 sendBreath(breath);
492                 }
493         }
494
495         /*
496                 Print some info
497         */
498         float &counter = m_avg_rtt_timer;
499         counter += dtime;
500         if(counter >= 10) {
501                 counter = 0.0;
502                 // connectedAndInitialized() is true, peer exists.
503                 float avg_rtt = getRTT();
504                 infostream << "Client: avg_rtt=" << avg_rtt << std::endl;
505         }
506
507         /*
508                 Send player position to server
509         */
510         {
511                 float &counter = m_playerpos_send_timer;
512                 counter += dtime;
513                 if((m_state == LC_Ready) && (counter >= m_recommended_send_interval))
514                 {
515                         counter = 0.0;
516                         sendPlayerPos();
517                 }
518         }
519
520         /*
521                 Replace updated meshes
522         */
523         {
524                 int num_processed_meshes = 0;
525                 while (!m_mesh_update_thread.m_queue_out.empty())
526                 {
527                         num_processed_meshes++;
528                         MeshUpdateResult r = m_mesh_update_thread.m_queue_out.pop_frontNoEx();
529                         MapBlock *block = m_env.getMap().getBlockNoCreateNoEx(r.p);
530                         MinimapMapblock *minimap_mapblock = NULL;
531                         if (block) {
532                                 // Delete the old mesh
533                                 if (block->mesh != NULL)        {
534                                         delete block->mesh;
535                                         block->mesh = NULL;
536                                 }
537
538                                 if (r.mesh)
539                                         minimap_mapblock = r.mesh->getMinimapMapblock();
540
541                                 if (r.mesh && r.mesh->getMesh()->getMeshBufferCount() == 0) {
542                                         delete r.mesh;
543                                         block->mesh = NULL;
544                                 } else {
545                                         // Replace with the new mesh
546                                         block->mesh = r.mesh;
547                                 }
548                         } else {
549                                 delete r.mesh;
550                                 minimap_mapblock = NULL;
551                         }
552
553                         m_mapper->addBlock(r.p, minimap_mapblock);
554
555                         if (r.ack_block_to_server) {
556                                 /*
557                                         Acknowledge block
558                                         [0] u8 count
559                                         [1] v3s16 pos_0
560                                 */
561                                 sendGotBlocks(r.p);
562                         }
563                 }
564
565                 if (num_processed_meshes > 0)
566                         g_profiler->graphAdd("num_processed_meshes", num_processed_meshes);
567         }
568
569         /*
570                 Load fetched media
571         */
572         if (m_media_downloader && m_media_downloader->isStarted()) {
573                 m_media_downloader->step(this);
574                 if (m_media_downloader->isDone()) {
575                         received_media();
576                         delete m_media_downloader;
577                         m_media_downloader = NULL;
578                 }
579         }
580
581         /*
582                 If the server didn't update the inventory in a while, revert
583                 the local inventory (so the player notices the lag problem
584                 and knows something is wrong).
585         */
586         if(m_inventory_from_server)
587         {
588                 float interval = 10.0;
589                 float count_before = floor(m_inventory_from_server_age / interval);
590
591                 m_inventory_from_server_age += dtime;
592
593                 float count_after = floor(m_inventory_from_server_age / interval);
594
595                 if(count_after != count_before)
596                 {
597                         // Do this every <interval> seconds after TOCLIENT_INVENTORY
598                         // Reset the locally changed inventory to the authoritative inventory
599                         Player *player = m_env.getLocalPlayer();
600                         player->inventory = *m_inventory_from_server;
601                         m_inventory_updated = true;
602                 }
603         }
604
605         /*
606                 Update positions of sounds attached to objects
607         */
608         {
609                 for(std::map<int, u16>::iterator
610                                 i = m_sounds_to_objects.begin();
611                                 i != m_sounds_to_objects.end(); i++)
612                 {
613                         int client_id = i->first;
614                         u16 object_id = i->second;
615                         ClientActiveObject *cao = m_env.getActiveObject(object_id);
616                         if(!cao)
617                                 continue;
618                         v3f pos = cao->getPosition();
619                         m_sound->updateSoundPosition(client_id, pos);
620                 }
621         }
622
623         /*
624                 Handle removed remotely initiated sounds
625         */
626         m_removed_sounds_check_timer += dtime;
627         if(m_removed_sounds_check_timer >= 2.32) {
628                 m_removed_sounds_check_timer = 0;
629                 // Find removed sounds and clear references to them
630                 std::vector<s32> removed_server_ids;
631                 for(std::map<s32, int>::iterator
632                                 i = m_sounds_server_to_client.begin();
633                                 i != m_sounds_server_to_client.end();) {
634                         s32 server_id = i->first;
635                         int client_id = i->second;
636                         i++;
637                         if(!m_sound->soundExists(client_id)) {
638                                 m_sounds_server_to_client.erase(server_id);
639                                 m_sounds_client_to_server.erase(client_id);
640                                 m_sounds_to_objects.erase(client_id);
641                                 removed_server_ids.push_back(server_id);
642                         }
643                 }
644
645                 // Sync to server
646                 if(!removed_server_ids.empty()) {
647                         sendRemovedSounds(removed_server_ids);
648                 }
649         }
650
651         // Write server map
652         if (m_localdb && m_localdb_save_interval.step(dtime,
653                         m_cache_save_interval)) {
654                 m_localdb->endSave();
655                 m_localdb->beginSave();
656         }
657 }
658
659 bool Client::loadMedia(const std::string &data, const std::string &filename)
660 {
661         // Silly irrlicht's const-incorrectness
662         Buffer<char> data_rw(data.c_str(), data.size());
663
664         std::string name;
665
666         const char *image_ext[] = {
667                 ".png", ".jpg", ".bmp", ".tga",
668                 ".pcx", ".ppm", ".psd", ".wal", ".rgb",
669                 NULL
670         };
671         name = removeStringEnd(filename, image_ext);
672         if(name != "")
673         {
674                 verbosestream<<"Client: Attempting to load image "
675                 <<"file \""<<filename<<"\""<<std::endl;
676
677                 io::IFileSystem *irrfs = m_device->getFileSystem();
678                 video::IVideoDriver *vdrv = m_device->getVideoDriver();
679
680                 // Create an irrlicht memory file
681                 io::IReadFile *rfile = irrfs->createMemoryReadFile(
682                                 *data_rw, data_rw.getSize(), "_tempreadfile");
683
684                 FATAL_ERROR_IF(!rfile, "Could not create irrlicht memory file.");
685
686                 // Read image
687                 video::IImage *img = vdrv->createImageFromFile(rfile);
688                 if(!img){
689                         errorstream<<"Client: Cannot create image from data of "
690                                         <<"file \""<<filename<<"\""<<std::endl;
691                         rfile->drop();
692                         return false;
693                 }
694                 else {
695                         m_tsrc->insertSourceImage(filename, img);
696                         img->drop();
697                         rfile->drop();
698                         return true;
699                 }
700         }
701
702         const char *sound_ext[] = {
703                 ".0.ogg", ".1.ogg", ".2.ogg", ".3.ogg", ".4.ogg",
704                 ".5.ogg", ".6.ogg", ".7.ogg", ".8.ogg", ".9.ogg",
705                 ".ogg", NULL
706         };
707         name = removeStringEnd(filename, sound_ext);
708         if(name != "")
709         {
710                 verbosestream<<"Client: Attempting to load sound "
711                 <<"file \""<<filename<<"\""<<std::endl;
712                 m_sound->loadSoundData(name, data);
713                 return true;
714         }
715
716         const char *model_ext[] = {
717                 ".x", ".b3d", ".md2", ".obj",
718                 NULL
719         };
720         name = removeStringEnd(filename, model_ext);
721         if(name != "")
722         {
723                 verbosestream<<"Client: Storing model into memory: "
724                                 <<"\""<<filename<<"\""<<std::endl;
725                 if(m_mesh_data.count(filename))
726                         errorstream<<"Multiple models with name \""<<filename.c_str()
727                                         <<"\" found; replacing previous model"<<std::endl;
728                 m_mesh_data[filename] = data;
729                 return true;
730         }
731
732         errorstream<<"Client: Don't know how to load file \""
733                         <<filename<<"\""<<std::endl;
734         return false;
735 }
736
737 // Virtual methods from con::PeerHandler
738 void Client::peerAdded(con::Peer *peer)
739 {
740         infostream<<"Client::peerAdded(): peer->id="
741                         <<peer->id<<std::endl;
742 }
743 void Client::deletingPeer(con::Peer *peer, bool timeout)
744 {
745         infostream<<"Client::deletingPeer(): "
746                         "Server Peer is getting deleted "
747                         <<"(timeout="<<timeout<<")"<<std::endl;
748 }
749
750 /*
751         u16 command
752         u16 number of files requested
753         for each file {
754                 u16 length of name
755                 string name
756         }
757 */
758 void Client::request_media(const std::vector<std::string> &file_requests)
759 {
760         std::ostringstream os(std::ios_base::binary);
761         writeU16(os, TOSERVER_REQUEST_MEDIA);
762         size_t file_requests_size = file_requests.size();
763
764         FATAL_ERROR_IF(file_requests_size > 0xFFFF, "Unsupported number of file requests");
765
766         // Packet dynamicly resized
767         NetworkPacket pkt(TOSERVER_REQUEST_MEDIA, 2 + 0);
768
769         pkt << (u16) (file_requests_size & 0xFFFF);
770
771         for(std::vector<std::string>::const_iterator i = file_requests.begin();
772                         i != file_requests.end(); ++i) {
773                 pkt << (*i);
774         }
775
776         Send(&pkt);
777
778         infostream << "Client: Sending media request list to server ("
779                         << file_requests.size() << " files. packet size)" << std::endl;
780 }
781
782 void Client::received_media()
783 {
784         NetworkPacket pkt(TOSERVER_RECEIVED_MEDIA, 0);
785         Send(&pkt);
786         infostream << "Client: Notifying server that we received all media"
787                         << std::endl;
788 }
789
790 void Client::initLocalMapSaving(const Address &address,
791                 const std::string &hostname,
792                 bool is_local_server)
793 {
794         if (!g_settings->getBool("enable_local_map_saving") || is_local_server) {
795                 return;
796         }
797
798         const std::string world_path = porting::path_user
799                 + DIR_DELIM + "worlds"
800                 + DIR_DELIM + "server_"
801                 + hostname + "_" + to_string(address.getPort());
802
803         fs::CreateAllDirs(world_path);
804
805         m_localdb = new Database_SQLite3(world_path);
806         m_localdb->beginSave();
807         actionstream << "Local map saving started, map will be saved at '" << world_path << "'" << std::endl;
808 }
809
810 void Client::ReceiveAll()
811 {
812         DSTACK(__FUNCTION_NAME);
813         u32 start_ms = porting::getTimeMs();
814         for(;;)
815         {
816                 // Limit time even if there would be huge amounts of data to
817                 // process
818                 if(porting::getTimeMs() > start_ms + 100)
819                         break;
820
821                 try {
822                         Receive();
823                         g_profiler->graphAdd("client_received_packets", 1);
824                 }
825                 catch(con::NoIncomingDataException &e) {
826                         break;
827                 }
828                 catch(con::InvalidIncomingDataException &e) {
829                         infostream<<"Client::ReceiveAll(): "
830                                         "InvalidIncomingDataException: what()="
831                                         <<e.what()<<std::endl;
832                 }
833         }
834 }
835
836 void Client::Receive()
837 {
838         DSTACK(__FUNCTION_NAME);
839         NetworkPacket pkt;
840         m_con.Receive(&pkt);
841         ProcessData(&pkt);
842 }
843
844 inline void Client::handleCommand(NetworkPacket* pkt)
845 {
846         const ToClientCommandHandler& opHandle = toClientCommandTable[pkt->getCommand()];
847         (this->*opHandle.handler)(pkt);
848 }
849
850 /*
851         sender_peer_id given to this shall be quaranteed to be a valid peer
852 */
853 void Client::ProcessData(NetworkPacket *pkt)
854 {
855         DSTACK(__FUNCTION_NAME);
856
857         ToClientCommand command = (ToClientCommand) pkt->getCommand();
858         u32 sender_peer_id = pkt->getPeerId();
859
860         //infostream<<"Client: received command="<<command<<std::endl;
861         m_packetcounter.add((u16)command);
862
863         /*
864                 If this check is removed, be sure to change the queue
865                 system to know the ids
866         */
867         if(sender_peer_id != PEER_ID_SERVER) {
868                 infostream << "Client::ProcessData(): Discarding data not "
869                         "coming from server: peer_id=" << sender_peer_id
870                         << std::endl;
871                 return;
872         }
873
874         // Command must be handled into ToClientCommandHandler
875         if (command >= TOCLIENT_NUM_MSG_TYPES) {
876                 infostream << "Client: Ignoring unknown command "
877                         << command << std::endl;
878                 return;
879         }
880
881         /*
882          * Those packets are handled before m_server_ser_ver is set, it's normal
883          * But we must use the new ToClientConnectionState in the future,
884          * as a byte mask
885          */
886         if(toClientCommandTable[command].state == TOCLIENT_STATE_NOT_CONNECTED) {
887                 handleCommand(pkt);
888                 return;
889         }
890
891         if(m_server_ser_ver == SER_FMT_VER_INVALID) {
892                 infostream << "Client: Server serialization"
893                                 " format invalid or not initialized."
894                                 " Skipping incoming command=" << command << std::endl;
895                 return;
896         }
897
898         /*
899           Handle runtime commands
900         */
901
902         handleCommand(pkt);
903 }
904
905 void Client::Send(NetworkPacket* pkt)
906 {
907         m_con.Send(PEER_ID_SERVER,
908                 serverCommandFactoryTable[pkt->getCommand()].channel,
909                 pkt,
910                 serverCommandFactoryTable[pkt->getCommand()].reliable);
911 }
912
913 void Client::interact(u8 action, const PointedThing& pointed)
914 {
915         if(m_state != LC_Ready) {
916                 errorstream << "Client::interact() "
917                                 "Canceled (not connected)"
918                                 << std::endl;
919                 return;
920         }
921
922         /*
923                 [0] u16 command
924                 [2] u8 action
925                 [3] u16 item
926                 [5] u32 length of the next item
927                 [9] serialized PointedThing
928                 actions:
929                 0: start digging (from undersurface) or use
930                 1: stop digging (all parameters ignored)
931                 2: digging completed
932                 3: place block or item (to abovesurface)
933                 4: use item
934         */
935
936         NetworkPacket pkt(TOSERVER_INTERACT, 1 + 2 + 0);
937
938         pkt << action;
939         pkt << (u16)getPlayerItem();
940
941         std::ostringstream tmp_os(std::ios::binary);
942         pointed.serialize(tmp_os);
943
944         pkt.putLongString(tmp_os.str());
945
946         Send(&pkt);
947 }
948
949 void Client::deleteAuthData()
950 {
951         if (!m_auth_data)
952                 return;
953
954         switch (m_chosen_auth_mech) {
955                 case AUTH_MECHANISM_FIRST_SRP:
956                         break;
957                 case AUTH_MECHANISM_SRP:
958                 case AUTH_MECHANISM_LEGACY_PASSWORD:
959                         srp_user_delete((SRPUser *) m_auth_data);
960                         m_auth_data = NULL;
961                         break;
962                 case AUTH_MECHANISM_NONE:
963                         break;
964         }
965 }
966
967
968 AuthMechanism Client::choseAuthMech(const u32 mechs)
969 {
970         if (mechs & AUTH_MECHANISM_SRP)
971                 return AUTH_MECHANISM_SRP;
972
973         if (mechs & AUTH_MECHANISM_FIRST_SRP)
974                 return AUTH_MECHANISM_FIRST_SRP;
975
976         if (mechs & AUTH_MECHANISM_LEGACY_PASSWORD)
977                 return AUTH_MECHANISM_LEGACY_PASSWORD;
978
979         return AUTH_MECHANISM_NONE;
980 }
981
982 void Client::sendLegacyInit(const char* playerName, const char* playerPassword)
983 {
984         NetworkPacket pkt(TOSERVER_INIT_LEGACY,
985                         1 + PLAYERNAME_SIZE + PASSWORD_SIZE + 2 + 2);
986
987         pkt << (u8) SER_FMT_VER_HIGHEST_READ;
988         pkt.putRawString(playerName,PLAYERNAME_SIZE);
989         pkt.putRawString(playerPassword, PASSWORD_SIZE);
990         pkt << (u16) CLIENT_PROTOCOL_VERSION_MIN << (u16) CLIENT_PROTOCOL_VERSION_MAX;
991
992         Send(&pkt);
993 }
994
995 void Client::sendInit(const std::string &playerName)
996 {
997         NetworkPacket pkt(TOSERVER_INIT, 1 + 2 + 2 + (1 + playerName.size()));
998
999         // we don't support network compression yet
1000         u16 supp_comp_modes = NETPROTO_COMPRESSION_NONE;
1001         pkt << (u8) SER_FMT_VER_HIGHEST_READ << (u16) supp_comp_modes;
1002         pkt << (u16) CLIENT_PROTOCOL_VERSION_MIN << (u16) CLIENT_PROTOCOL_VERSION_MAX;
1003         pkt << playerName;
1004
1005         Send(&pkt);
1006 }
1007
1008 void Client::startAuth(AuthMechanism chosen_auth_mechanism)
1009 {
1010         m_chosen_auth_mech = chosen_auth_mechanism;
1011
1012         switch (chosen_auth_mechanism) {
1013                 case AUTH_MECHANISM_FIRST_SRP: {
1014                         // send srp verifier to server
1015                         NetworkPacket resp_pkt(TOSERVER_FIRST_SRP, 0);
1016                         char *salt, *bytes_v;
1017                         std::size_t len_salt, len_v;
1018                         salt = NULL;
1019                         getSRPVerifier(getPlayerName(), m_password,
1020                                 &salt, &len_salt, &bytes_v, &len_v);
1021                         resp_pkt
1022                                 << std::string((char*)salt, len_salt)
1023                                 << std::string((char*)bytes_v, len_v)
1024                                 << (u8)((m_password == "") ? 1 : 0);
1025                         free(salt);
1026                         free(bytes_v);
1027                         Send(&resp_pkt);
1028                         break;
1029                 }
1030                 case AUTH_MECHANISM_SRP:
1031                 case AUTH_MECHANISM_LEGACY_PASSWORD: {
1032                         u8 based_on = 1;
1033
1034                         if (chosen_auth_mechanism == AUTH_MECHANISM_LEGACY_PASSWORD) {
1035                                 m_password = translatePassword(getPlayerName(), m_password);
1036                                 based_on = 0;
1037                         }
1038
1039                         std::string playername_u = lowercase(getPlayerName());
1040                         m_auth_data = srp_user_new(SRP_SHA256, SRP_NG_2048,
1041                                 getPlayerName().c_str(), playername_u.c_str(),
1042                                 (const unsigned char *) m_password.c_str(),
1043                                 m_password.length(), NULL, NULL);
1044                         char *bytes_A = 0;
1045                         size_t len_A = 0;
1046                         srp_user_start_authentication((struct SRPUser *) m_auth_data,
1047                                 NULL, NULL, 0, (unsigned char **) &bytes_A, &len_A);
1048
1049                         NetworkPacket resp_pkt(TOSERVER_SRP_BYTES_A, 0);
1050                         resp_pkt << std::string(bytes_A, len_A) << based_on;
1051                         free(bytes_A);
1052                         Send(&resp_pkt);
1053                         break;
1054                 }
1055                 case AUTH_MECHANISM_NONE:
1056                         break; // not handled in this method
1057         }
1058 }
1059
1060 void Client::sendDeletedBlocks(std::vector<v3s16> &blocks)
1061 {
1062         NetworkPacket pkt(TOSERVER_DELETEDBLOCKS, 1 + sizeof(v3s16) * blocks.size());
1063
1064         pkt << (u8) blocks.size();
1065
1066         u32 k = 0;
1067         for(std::vector<v3s16>::iterator
1068                         j = blocks.begin();
1069                         j != blocks.end(); ++j) {
1070                 pkt << *j;
1071                 k++;
1072         }
1073
1074         Send(&pkt);
1075 }
1076
1077 void Client::sendGotBlocks(v3s16 block)
1078 {
1079         NetworkPacket pkt(TOSERVER_GOTBLOCKS, 1 + 6);
1080         pkt << (u8) 1 << block;
1081         Send(&pkt);
1082 }
1083
1084 void Client::sendRemovedSounds(std::vector<s32> &soundList)
1085 {
1086         size_t server_ids = soundList.size();
1087         assert(server_ids <= 0xFFFF);
1088
1089         NetworkPacket pkt(TOSERVER_REMOVED_SOUNDS, 2 + server_ids * 4);
1090
1091         pkt << (u16) (server_ids & 0xFFFF);
1092
1093         for(std::vector<s32>::iterator i = soundList.begin();
1094                         i != soundList.end(); i++)
1095                 pkt << *i;
1096
1097         Send(&pkt);
1098 }
1099
1100 void Client::sendNodemetaFields(v3s16 p, const std::string &formname,
1101                 const StringMap &fields)
1102 {
1103         size_t fields_size = fields.size();
1104
1105         FATAL_ERROR_IF(fields_size > 0xFFFF, "Unsupported number of nodemeta fields");
1106
1107         NetworkPacket pkt(TOSERVER_NODEMETA_FIELDS, 0);
1108
1109         pkt << p << formname << (u16) (fields_size & 0xFFFF);
1110
1111         StringMap::const_iterator it;
1112         for (it = fields.begin(); it != fields.end(); ++it) {
1113                 const std::string &name = it->first;
1114                 const std::string &value = it->second;
1115                 pkt << name;
1116                 pkt.putLongString(value);
1117         }
1118
1119         Send(&pkt);
1120 }
1121
1122 void Client::sendInventoryFields(const std::string &formname,
1123                 const StringMap &fields)
1124 {
1125         size_t fields_size = fields.size();
1126         FATAL_ERROR_IF(fields_size > 0xFFFF, "Unsupported number of inventory fields");
1127
1128         NetworkPacket pkt(TOSERVER_INVENTORY_FIELDS, 0);
1129         pkt << formname << (u16) (fields_size & 0xFFFF);
1130
1131         StringMap::const_iterator it;
1132         for (it = fields.begin(); it != fields.end(); ++it) {
1133                 const std::string &name  = it->first;
1134                 const std::string &value = it->second;
1135                 pkt << name;
1136                 pkt.putLongString(value);
1137         }
1138
1139         Send(&pkt);
1140 }
1141
1142 void Client::sendInventoryAction(InventoryAction *a)
1143 {
1144         std::ostringstream os(std::ios_base::binary);
1145
1146         a->serialize(os);
1147
1148         // Make data buffer
1149         std::string s = os.str();
1150
1151         NetworkPacket pkt(TOSERVER_INVENTORY_ACTION, s.size());
1152         pkt.putRawString(s.c_str(),s.size());
1153
1154         Send(&pkt);
1155 }
1156
1157 void Client::sendChatMessage(const std::wstring &message)
1158 {
1159         NetworkPacket pkt(TOSERVER_CHAT_MESSAGE, 2 + message.size() * sizeof(u16));
1160
1161         pkt << message;
1162
1163         Send(&pkt);
1164 }
1165
1166 void Client::sendChangePassword(const std::string &oldpassword,
1167         const std::string &newpassword)
1168 {
1169         Player *player = m_env.getLocalPlayer();
1170         if (player == NULL)
1171                 return;
1172
1173         std::string playername = player->getName();
1174         if (m_proto_ver >= 25) {
1175                 // get into sudo mode and then send new password to server
1176                 m_password = oldpassword;
1177                 m_new_password = newpassword;
1178                 startAuth(choseAuthMech(m_sudo_auth_methods));
1179         } else {
1180                 std::string oldpwd = translatePassword(playername, oldpassword);
1181                 std::string newpwd = translatePassword(playername, newpassword);
1182
1183                 NetworkPacket pkt(TOSERVER_PASSWORD_LEGACY, 2 * PASSWORD_SIZE);
1184
1185                 for (u8 i = 0; i < PASSWORD_SIZE; i++) {
1186                         pkt << (u8) (i < oldpwd.length() ? oldpwd[i] : 0);
1187                 }
1188
1189                 for (u8 i = 0; i < PASSWORD_SIZE; i++) {
1190                         pkt << (u8) (i < newpwd.length() ? newpwd[i] : 0);
1191                 }
1192                 Send(&pkt);
1193         }
1194 }
1195
1196
1197 void Client::sendDamage(u8 damage)
1198 {
1199         DSTACK(__FUNCTION_NAME);
1200
1201         NetworkPacket pkt(TOSERVER_DAMAGE, sizeof(u8));
1202         pkt << damage;
1203         Send(&pkt);
1204 }
1205
1206 void Client::sendBreath(u16 breath)
1207 {
1208         DSTACK(__FUNCTION_NAME);
1209
1210         NetworkPacket pkt(TOSERVER_BREATH, sizeof(u16));
1211         pkt << breath;
1212         Send(&pkt);
1213 }
1214
1215 void Client::sendRespawn()
1216 {
1217         DSTACK(__FUNCTION_NAME);
1218
1219         NetworkPacket pkt(TOSERVER_RESPAWN, 0);
1220         Send(&pkt);
1221 }
1222
1223 void Client::sendReady()
1224 {
1225         DSTACK(__FUNCTION_NAME);
1226
1227         NetworkPacket pkt(TOSERVER_CLIENT_READY,
1228                         1 + 1 + 1 + 1 + 2 + sizeof(char) * strlen(g_version_hash));
1229
1230         pkt << (u8) VERSION_MAJOR << (u8) VERSION_MINOR << (u8) VERSION_PATCH
1231                 << (u8) 0 << (u16) strlen(g_version_hash);
1232
1233         pkt.putRawString(g_version_hash, (u16) strlen(g_version_hash));
1234         Send(&pkt);
1235 }
1236
1237 void Client::sendPlayerPos()
1238 {
1239         LocalPlayer *myplayer = m_env.getLocalPlayer();
1240         if(myplayer == NULL)
1241                 return;
1242
1243         // Save bandwidth by only updating position when something changed
1244         if(myplayer->last_position        == myplayer->getPosition() &&
1245                         myplayer->last_speed      == myplayer->getSpeed()    &&
1246                         myplayer->last_pitch      == myplayer->getPitch()    &&
1247                         myplayer->last_yaw        == myplayer->getYaw()      &&
1248                         myplayer->last_keyPressed == myplayer->keyPressed)
1249                 return;
1250
1251         myplayer->last_position   = myplayer->getPosition();
1252         myplayer->last_speed      = myplayer->getSpeed();
1253         myplayer->last_pitch      = myplayer->getPitch();
1254         myplayer->last_yaw        = myplayer->getYaw();
1255         myplayer->last_keyPressed = myplayer->keyPressed;
1256
1257         u16 our_peer_id;
1258         {
1259                 //JMutexAutoLock lock(m_con_mutex); //bulk comment-out
1260                 our_peer_id = m_con.GetPeerID();
1261         }
1262
1263         // Set peer id if not set already
1264         if(myplayer->peer_id == PEER_ID_INEXISTENT)
1265                 myplayer->peer_id = our_peer_id;
1266
1267         assert(myplayer->peer_id == our_peer_id);
1268
1269         v3f pf         = myplayer->getPosition();
1270         v3f sf         = myplayer->getSpeed();
1271         s32 pitch      = myplayer->getPitch() * 100;
1272         s32 yaw        = myplayer->getYaw() * 100;
1273         u32 keyPressed = myplayer->keyPressed;
1274
1275         v3s32 position(pf.X*100, pf.Y*100, pf.Z*100);
1276         v3s32 speed(sf.X*100, sf.Y*100, sf.Z*100);
1277         /*
1278                 Format:
1279                 [0] v3s32 position*100
1280                 [12] v3s32 speed*100
1281                 [12+12] s32 pitch*100
1282                 [12+12+4] s32 yaw*100
1283                 [12+12+4+4] u32 keyPressed
1284         */
1285
1286         NetworkPacket pkt(TOSERVER_PLAYERPOS, 12 + 12 + 4 + 4 + 4);
1287
1288         pkt << position << speed << pitch << yaw << keyPressed;
1289
1290         Send(&pkt);
1291 }
1292
1293 void Client::sendPlayerItem(u16 item)
1294 {
1295         Player *myplayer = m_env.getLocalPlayer();
1296         if(myplayer == NULL)
1297                 return;
1298
1299         u16 our_peer_id = m_con.GetPeerID();
1300
1301         // Set peer id if not set already
1302         if(myplayer->peer_id == PEER_ID_INEXISTENT)
1303                 myplayer->peer_id = our_peer_id;
1304         assert(myplayer->peer_id == our_peer_id);
1305
1306         NetworkPacket pkt(TOSERVER_PLAYERITEM, 2);
1307
1308         pkt << item;
1309
1310         Send(&pkt);
1311 }
1312
1313 void Client::removeNode(v3s16 p)
1314 {
1315         std::map<v3s16, MapBlock*> modified_blocks;
1316
1317         try {
1318                 m_env.getMap().removeNodeAndUpdate(p, modified_blocks);
1319         }
1320         catch(InvalidPositionException &e) {
1321         }
1322
1323         for(std::map<v3s16, MapBlock *>::iterator
1324                         i = modified_blocks.begin();
1325                         i != modified_blocks.end(); ++i) {
1326                 addUpdateMeshTaskWithEdge(i->first, false, true);
1327         }
1328 }
1329
1330 void Client::addNode(v3s16 p, MapNode n, bool remove_metadata)
1331 {
1332         //TimeTaker timer1("Client::addNode()");
1333
1334         std::map<v3s16, MapBlock*> modified_blocks;
1335
1336         try {
1337                 //TimeTaker timer3("Client::addNode(): addNodeAndUpdate");
1338                 m_env.getMap().addNodeAndUpdate(p, n, modified_blocks, remove_metadata);
1339         }
1340         catch(InvalidPositionException &e) {
1341         }
1342
1343         for(std::map<v3s16, MapBlock *>::iterator
1344                         i = modified_blocks.begin();
1345                         i != modified_blocks.end(); ++i) {
1346                 addUpdateMeshTaskWithEdge(i->first, false, true);
1347         }
1348 }
1349
1350 void Client::setPlayerControl(PlayerControl &control)
1351 {
1352         LocalPlayer *player = m_env.getLocalPlayer();
1353         assert(player != NULL);
1354         player->control = control;
1355 }
1356
1357 void Client::selectPlayerItem(u16 item)
1358 {
1359         m_playeritem = item;
1360         m_inventory_updated = true;
1361         sendPlayerItem(item);
1362 }
1363
1364 // Returns true if the inventory of the local player has been
1365 // updated from the server. If it is true, it is set to false.
1366 bool Client::getLocalInventoryUpdated()
1367 {
1368         bool updated = m_inventory_updated;
1369         m_inventory_updated = false;
1370         return updated;
1371 }
1372
1373 // Copies the inventory of the local player to parameter
1374 void Client::getLocalInventory(Inventory &dst)
1375 {
1376         Player *player = m_env.getLocalPlayer();
1377         assert(player != NULL);
1378         dst = player->inventory;
1379 }
1380
1381 Inventory* Client::getInventory(const InventoryLocation &loc)
1382 {
1383         switch(loc.type){
1384         case InventoryLocation::UNDEFINED:
1385         {}
1386         break;
1387         case InventoryLocation::CURRENT_PLAYER:
1388         {
1389                 Player *player = m_env.getLocalPlayer();
1390                 assert(player != NULL);
1391                 return &player->inventory;
1392         }
1393         break;
1394         case InventoryLocation::PLAYER:
1395         {
1396                 Player *player = m_env.getPlayer(loc.name.c_str());
1397                 if(!player)
1398                         return NULL;
1399                 return &player->inventory;
1400         }
1401         break;
1402         case InventoryLocation::NODEMETA:
1403         {
1404                 NodeMetadata *meta = m_env.getMap().getNodeMetadata(loc.p);
1405                 if(!meta)
1406                         return NULL;
1407                 return meta->getInventory();
1408         }
1409         break;
1410         case InventoryLocation::DETACHED:
1411         {
1412                 if(m_detached_inventories.count(loc.name) == 0)
1413                         return NULL;
1414                 return m_detached_inventories[loc.name];
1415         }
1416         break;
1417         default:
1418                 FATAL_ERROR("Invalid inventory location type.");
1419                 break;
1420         }
1421         return NULL;
1422 }
1423
1424 void Client::inventoryAction(InventoryAction *a)
1425 {
1426         /*
1427                 Send it to the server
1428         */
1429         sendInventoryAction(a);
1430
1431         /*
1432                 Predict some local inventory changes
1433         */
1434         a->clientApply(this, this);
1435
1436         // Remove it
1437         delete a;
1438 }
1439
1440 ClientActiveObject * Client::getSelectedActiveObject(
1441                 f32 max_d,
1442                 v3f from_pos_f_on_map,
1443                 core::line3d<f32> shootline_on_map
1444         )
1445 {
1446         std::vector<DistanceSortedActiveObject> objects;
1447
1448         m_env.getActiveObjects(from_pos_f_on_map, max_d, objects);
1449
1450         // Sort them.
1451         // After this, the closest object is the first in the array.
1452         std::sort(objects.begin(), objects.end());
1453
1454         for(unsigned int i=0; i<objects.size(); i++)
1455         {
1456                 ClientActiveObject *obj = objects[i].obj;
1457
1458                 core::aabbox3d<f32> *selection_box = obj->getSelectionBox();
1459                 if(selection_box == NULL)
1460                         continue;
1461
1462                 v3f pos = obj->getPosition();
1463
1464                 core::aabbox3d<f32> offsetted_box(
1465                                 selection_box->MinEdge + pos,
1466                                 selection_box->MaxEdge + pos
1467                 );
1468
1469                 if(offsetted_box.intersectsWithLine(shootline_on_map))
1470                 {
1471                         return obj;
1472                 }
1473         }
1474
1475         return NULL;
1476 }
1477
1478 std::list<std::string> Client::getConnectedPlayerNames()
1479 {
1480         return m_env.getPlayerNames();
1481 }
1482
1483 float Client::getAnimationTime()
1484 {
1485         return m_animation_time;
1486 }
1487
1488 int Client::getCrackLevel()
1489 {
1490         return m_crack_level;
1491 }
1492
1493 void Client::setHighlighted(v3s16 pos, bool show_highlighted)
1494 {
1495         m_show_highlighted = show_highlighted;
1496         v3s16 old_highlighted_pos = m_highlighted_pos;
1497         m_highlighted_pos = pos;
1498         addUpdateMeshTaskForNode(old_highlighted_pos, false, true);
1499         addUpdateMeshTaskForNode(m_highlighted_pos, false, true);
1500 }
1501
1502 void Client::setCrack(int level, v3s16 pos)
1503 {
1504         int old_crack_level = m_crack_level;
1505         v3s16 old_crack_pos = m_crack_pos;
1506
1507         m_crack_level = level;
1508         m_crack_pos = pos;
1509
1510         if(old_crack_level >= 0 && (level < 0 || pos != old_crack_pos))
1511         {
1512                 // remove old crack
1513                 addUpdateMeshTaskForNode(old_crack_pos, false, true);
1514         }
1515         if(level >= 0 && (old_crack_level < 0 || pos != old_crack_pos))
1516         {
1517                 // add new crack
1518                 addUpdateMeshTaskForNode(pos, false, true);
1519         }
1520 }
1521
1522 u16 Client::getHP()
1523 {
1524         Player *player = m_env.getLocalPlayer();
1525         assert(player != NULL);
1526         return player->hp;
1527 }
1528
1529 u16 Client::getBreath()
1530 {
1531         Player *player = m_env.getLocalPlayer();
1532         assert(player != NULL);
1533         return player->getBreath();
1534 }
1535
1536 bool Client::getChatMessage(std::wstring &message)
1537 {
1538         if(m_chat_queue.size() == 0)
1539                 return false;
1540         message = m_chat_queue.front();
1541         m_chat_queue.pop();
1542         return true;
1543 }
1544
1545 void Client::typeChatMessage(const std::wstring &message)
1546 {
1547         // Discard empty line
1548         if(message == L"")
1549                 return;
1550
1551         // Send to others
1552         sendChatMessage(message);
1553
1554         // Show locally
1555         if (message[0] == L'/')
1556         {
1557                 m_chat_queue.push((std::wstring)L"issued command: " + message);
1558         }
1559         else
1560         {
1561                 LocalPlayer *player = m_env.getLocalPlayer();
1562                 assert(player != NULL);
1563                 std::wstring name = narrow_to_wide(player->getName());
1564                 m_chat_queue.push((std::wstring)L"<" + name + L"> " + message);
1565         }
1566 }
1567
1568 void Client::addUpdateMeshTask(v3s16 p, bool ack_to_server, bool urgent)
1569 {
1570         MapBlock *b = m_env.getMap().getBlockNoCreateNoEx(p);
1571         if(b == NULL)
1572                 return;
1573
1574         /*
1575                 Create a task to update the mesh of the block
1576         */
1577
1578         MeshMakeData *data = new MeshMakeData(this, m_cache_enable_shaders);
1579
1580         {
1581                 //TimeTaker timer("data fill");
1582                 // Release: ~0ms
1583                 // Debug: 1-6ms, avg=2ms
1584                 data->fill(b);
1585                 data->setCrack(m_crack_level, m_crack_pos);
1586                 data->setHighlighted(m_highlighted_pos, m_show_highlighted);
1587                 data->setSmoothLighting(m_cache_smooth_lighting);
1588         }
1589
1590         // Add task to queue
1591         m_mesh_update_thread.enqueueUpdate(p, data, ack_to_server, urgent);
1592 }
1593
1594 void Client::addUpdateMeshTaskWithEdge(v3s16 blockpos, bool ack_to_server, bool urgent)
1595 {
1596         try{
1597                 addUpdateMeshTask(blockpos, ack_to_server, urgent);
1598         }
1599         catch(InvalidPositionException &e){}
1600
1601         // Leading edge
1602         for (int i=0;i<6;i++)
1603         {
1604                 try{
1605                         v3s16 p = blockpos + g_6dirs[i];
1606                         addUpdateMeshTask(p, false, urgent);
1607                 }
1608                 catch(InvalidPositionException &e){}
1609         }
1610 }
1611
1612 void Client::addUpdateMeshTaskForNode(v3s16 nodepos, bool ack_to_server, bool urgent)
1613 {
1614         {
1615                 v3s16 p = nodepos;
1616                 infostream<<"Client::addUpdateMeshTaskForNode(): "
1617                                 <<"("<<p.X<<","<<p.Y<<","<<p.Z<<")"
1618                                 <<std::endl;
1619         }
1620
1621         v3s16 blockpos          = getNodeBlockPos(nodepos);
1622         v3s16 blockpos_relative = blockpos * MAP_BLOCKSIZE;
1623
1624         try{
1625                 addUpdateMeshTask(blockpos, ack_to_server, urgent);
1626         }
1627         catch(InvalidPositionException &e) {}
1628
1629         // Leading edge
1630         if(nodepos.X == blockpos_relative.X){
1631                 try{
1632                         v3s16 p = blockpos + v3s16(-1,0,0);
1633                         addUpdateMeshTask(p, false, urgent);
1634                 }
1635                 catch(InvalidPositionException &e){}
1636         }
1637
1638         if(nodepos.Y == blockpos_relative.Y){
1639                 try{
1640                         v3s16 p = blockpos + v3s16(0,-1,0);
1641                         addUpdateMeshTask(p, false, urgent);
1642                 }
1643                 catch(InvalidPositionException &e){}
1644         }
1645
1646         if(nodepos.Z == blockpos_relative.Z){
1647                 try{
1648                         v3s16 p = blockpos + v3s16(0,0,-1);
1649                         addUpdateMeshTask(p, false, urgent);
1650                 }
1651                 catch(InvalidPositionException &e){}
1652         }
1653 }
1654
1655 ClientEvent Client::getClientEvent()
1656 {
1657         ClientEvent event;
1658         if(m_client_event_queue.size() == 0) {
1659                 event.type = CE_NONE;
1660         }
1661         else {
1662                 event = m_client_event_queue.front();
1663                 m_client_event_queue.pop();
1664         }
1665         return event;
1666 }
1667
1668 float Client::mediaReceiveProgress()
1669 {
1670         if (m_media_downloader)
1671                 return m_media_downloader->getProgress();
1672         else
1673                 return 1.0; // downloader only exists when not yet done
1674 }
1675
1676 typedef struct TextureUpdateArgs {
1677         IrrlichtDevice *device;
1678         gui::IGUIEnvironment *guienv;
1679         u32 last_time_ms;
1680         u16 last_percent;
1681         const wchar_t* text_base;
1682 } TextureUpdateArgs;
1683
1684 void texture_update_progress(void *args, u32 progress, u32 max_progress)
1685 {
1686                 TextureUpdateArgs* targs = (TextureUpdateArgs*) args;
1687                 u16 cur_percent = ceil(progress / (double) max_progress * 100.);
1688
1689                 // update the loading menu -- if neccessary
1690                 bool do_draw = false;
1691                 u32 time_ms = targs->last_time_ms;
1692                 if (cur_percent != targs->last_percent) {
1693                         targs->last_percent = cur_percent;
1694                         time_ms = getTimeMs();
1695                         // only draw when the user will notice something:
1696                         do_draw = (time_ms - targs->last_time_ms > 100);
1697                 }
1698
1699                 if (do_draw) {
1700                         targs->last_time_ms = time_ms;
1701                         std::basic_stringstream<wchar_t> strm;
1702                         strm << targs->text_base << " " << targs->last_percent << "%...";
1703                         draw_load_screen(strm.str(), targs->device, targs->guienv, 0,
1704                                 72 + (u16) ((18. / 100.) * (double) targs->last_percent));
1705                 }
1706 }
1707
1708 void Client::afterContentReceived(IrrlichtDevice *device)
1709 {
1710         infostream<<"Client::afterContentReceived() started"<<std::endl;
1711         assert(m_itemdef_received); // pre-condition
1712         assert(m_nodedef_received); // pre-condition
1713         assert(mediaReceived()); // pre-condition
1714
1715         const wchar_t* text = wgettext("Loading textures...");
1716
1717         // Clear cached pre-scaled 2D GUI images, as this cache
1718         // might have images with the same name but different
1719         // content from previous sessions.
1720         guiScalingCacheClear(device->getVideoDriver());
1721
1722         // Rebuild inherited images and recreate textures
1723         infostream<<"- Rebuilding images and textures"<<std::endl;
1724         draw_load_screen(text,device, guienv, 0, 70);
1725         m_tsrc->rebuildImagesAndTextures();
1726         delete[] text;
1727
1728         // Rebuild shaders
1729         infostream<<"- Rebuilding shaders"<<std::endl;
1730         text = wgettext("Rebuilding shaders...");
1731         draw_load_screen(text, device, guienv, 0, 71);
1732         m_shsrc->rebuildShaders();
1733         delete[] text;
1734
1735         // Update node aliases
1736         infostream<<"- Updating node aliases"<<std::endl;
1737         text = wgettext("Initializing nodes...");
1738         draw_load_screen(text, device, guienv, 0, 72);
1739         m_nodedef->updateAliases(m_itemdef);
1740         std::string texture_path = g_settings->get("texture_path");
1741         if (texture_path != "" && fs::IsDir(texture_path))
1742                 m_nodedef->applyTextureOverrides(texture_path + DIR_DELIM + "override.txt");
1743         m_nodedef->setNodeRegistrationStatus(true);
1744         m_nodedef->runNodeResolveCallbacks();
1745         delete[] text;
1746
1747         // Update node textures and assign shaders to each tile
1748         infostream<<"- Updating node textures"<<std::endl;
1749         TextureUpdateArgs tu_args;
1750         tu_args.device = device;
1751         tu_args.guienv = guienv;
1752         tu_args.last_time_ms = getTimeMs();
1753         tu_args.last_percent = 0;
1754         tu_args.text_base =  wgettext("Initializing nodes");
1755         m_nodedef->updateTextures(this, texture_update_progress, &tu_args);
1756         delete[] tu_args.text_base;
1757
1758         // Preload item textures and meshes if configured to
1759         if(g_settings->getBool("preload_item_visuals"))
1760         {
1761                 verbosestream<<"Updating item textures and meshes"<<std::endl;
1762                 text = wgettext("Item textures...");
1763                 draw_load_screen(text, device, guienv, 0, 0);
1764                 std::set<std::string> names = m_itemdef->getAll();
1765                 size_t size = names.size();
1766                 size_t count = 0;
1767                 int percent = 0;
1768                 for(std::set<std::string>::const_iterator
1769                                 i = names.begin(); i != names.end(); ++i)
1770                 {
1771                         // Asking for these caches the result
1772                         m_itemdef->getInventoryTexture(*i, this);
1773                         m_itemdef->getWieldMesh(*i, this);
1774                         count++;
1775                         percent = (count * 100 / size * 0.2) + 80;
1776                         draw_load_screen(text, device, guienv, 0, percent);
1777                 }
1778                 delete[] text;
1779         }
1780
1781         // Start mesh update thread after setting up content definitions
1782         infostream<<"- Starting mesh update thread"<<std::endl;
1783         m_mesh_update_thread.Start();
1784
1785         m_state = LC_Ready;
1786         sendReady();
1787         text = wgettext("Done!");
1788         draw_load_screen(text, device, guienv, 0, 100);
1789         infostream<<"Client::afterContentReceived() done"<<std::endl;
1790         delete[] text;
1791 }
1792
1793 float Client::getRTT(void)
1794 {
1795         return m_con.getPeerStat(PEER_ID_SERVER,con::AVG_RTT);
1796 }
1797
1798 float Client::getCurRate(void)
1799 {
1800         return ( m_con.getLocalStat(con::CUR_INC_RATE) +
1801                         m_con.getLocalStat(con::CUR_DL_RATE));
1802 }
1803
1804 float Client::getAvgRate(void)
1805 {
1806         return ( m_con.getLocalStat(con::AVG_INC_RATE) +
1807                         m_con.getLocalStat(con::AVG_DL_RATE));
1808 }
1809
1810 void Client::makeScreenshot(IrrlichtDevice *device)
1811 {
1812         irr::video::IVideoDriver *driver = device->getVideoDriver();
1813         irr::video::IImage* const raw_image = driver->createScreenShot();
1814
1815         if (!raw_image)
1816                 return;
1817
1818         time_t t = time(NULL);
1819         struct tm *tm = localtime(&t);
1820
1821         char timetstamp_c[64];
1822         strftime(timetstamp_c, sizeof(timetstamp_c), "%Y%m%d_%H%M%S", tm);
1823
1824         std::string filename_base = g_settings->get("screenshot_path")
1825                         + DIR_DELIM
1826                         + std::string("screenshot_")
1827                         + std::string(timetstamp_c);
1828         std::string filename_ext = ".png";
1829         std::string filename;
1830
1831         // Try to find a unique filename
1832         unsigned serial = 0;
1833
1834         while (serial < SCREENSHOT_MAX_SERIAL_TRIES) {
1835                 filename = filename_base + (serial > 0 ? ("_" + itos(serial)) : "") + filename_ext;
1836                 std::ifstream tmp(filename.c_str());
1837                 if (!tmp.good())
1838                         break;  // File did not apparently exist, we'll go with it
1839                 serial++;
1840         }
1841
1842         if (serial == SCREENSHOT_MAX_SERIAL_TRIES) {
1843                 infostream << "Could not find suitable filename for screenshot" << std::endl;
1844         } else {
1845                 irr::video::IImage* const image =
1846                                 driver->createImage(video::ECF_R8G8B8, raw_image->getDimension());
1847
1848                 if (image) {
1849                         raw_image->copyTo(image);
1850
1851                         std::ostringstream sstr;
1852                         if (driver->writeImageToFile(image, filename.c_str())) {
1853                                 sstr << "Saved screenshot to '" << filename << "'";
1854                         } else {
1855                                 sstr << "Failed to save screenshot '" << filename << "'";
1856                         }
1857                         m_chat_queue.push(narrow_to_wide(sstr.str()));
1858                         infostream << sstr.str() << std::endl;
1859                         image->drop();
1860                 }
1861         }
1862
1863         raw_image->drop();
1864 }
1865
1866 // IGameDef interface
1867 // Under envlock
1868 IItemDefManager* Client::getItemDefManager()
1869 {
1870         return m_itemdef;
1871 }
1872 INodeDefManager* Client::getNodeDefManager()
1873 {
1874         return m_nodedef;
1875 }
1876 ICraftDefManager* Client::getCraftDefManager()
1877 {
1878         return NULL;
1879         //return m_craftdef;
1880 }
1881 ITextureSource* Client::getTextureSource()
1882 {
1883         return m_tsrc;
1884 }
1885 IShaderSource* Client::getShaderSource()
1886 {
1887         return m_shsrc;
1888 }
1889 scene::ISceneManager* Client::getSceneManager()
1890 {
1891         return m_device->getSceneManager();
1892 }
1893 u16 Client::allocateUnknownNodeId(const std::string &name)
1894 {
1895         errorstream << "Client::allocateUnknownNodeId(): "
1896                         << "Client cannot allocate node IDs" << std::endl;
1897         FATAL_ERROR("Client allocated unknown node");
1898
1899         return CONTENT_IGNORE;
1900 }
1901 ISoundManager* Client::getSoundManager()
1902 {
1903         return m_sound;
1904 }
1905 MtEventManager* Client::getEventManager()
1906 {
1907         return m_event;
1908 }
1909
1910 ParticleManager* Client::getParticleManager()
1911 {
1912         return &m_particle_manager;
1913 }
1914
1915 scene::IAnimatedMesh* Client::getMesh(const std::string &filename)
1916 {
1917         StringMap::const_iterator it = m_mesh_data.find(filename);
1918         if (it == m_mesh_data.end()) {
1919                 errorstream << "Client::getMesh(): Mesh not found: \"" << filename
1920                         << "\"" << std::endl;
1921                 return NULL;
1922         }
1923         const std::string &data    = it->second;
1924         scene::ISceneManager *smgr = m_device->getSceneManager();
1925
1926         // Create the mesh, remove it from cache and return it
1927         // This allows unique vertex colors and other properties for each instance
1928         Buffer<char> data_rw(data.c_str(), data.size()); // Const-incorrect Irrlicht
1929         io::IFileSystem *irrfs = m_device->getFileSystem();
1930         io::IReadFile *rfile   = irrfs->createMemoryReadFile(
1931                         *data_rw, data_rw.getSize(), filename.c_str());
1932         FATAL_ERROR_IF(!rfile, "Could not create/open RAM file");
1933
1934         scene::IAnimatedMesh *mesh = smgr->getMesh(rfile);
1935         rfile->drop();
1936         // NOTE: By playing with Irrlicht refcounts, maybe we could cache a bunch
1937         // of uniquely named instances and re-use them
1938         mesh->grab();
1939         smgr->getMeshCache()->removeMesh(mesh);
1940         return mesh;
1941 }