]> git.lizzy.rs Git - dragonfireclient.git/blob - src/client/client.cpp
DevTest: Fix broken PNG textures
[dragonfireclient.git] / src / client / 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 <cmath>
24 #include <IFileSystem.h>
25 #include "client.h"
26 #include "network/clientopcodes.h"
27 #include "network/connection.h"
28 #include "network/networkpacket.h"
29 #include "threading/mutex_auto_lock.h"
30 #include "client/clientevent.h"
31 #include "client/gameui.h"
32 #include "client/renderingengine.h"
33 #include "client/sound.h"
34 #include "client/tile.h"
35 #include "util/auth.h"
36 #include "util/directiontables.h"
37 #include "util/pointedthing.h"
38 #include "util/serialize.h"
39 #include "util/string.h"
40 #include "util/srp.h"
41 #include "filesys.h"
42 #include "mapblock_mesh.h"
43 #include "mapblock.h"
44 #include "minimap.h"
45 #include "modchannels.h"
46 #include "content/mods.h"
47 #include "profiler.h"
48 #include "shader.h"
49 #include "gettext.h"
50 #include "clientmap.h"
51 #include "clientmedia.h"
52 #include "version.h"
53 #include "database/database-files.h"
54 #include "database/database-sqlite3.h"
55 #include "serialization.h"
56 #include "guiscalingfilter.h"
57 #include "script/scripting_client.h"
58 #include "game.h"
59 #include "chatmessage.h"
60 #include "translation.h"
61
62 extern gui::IGUIEnvironment* guienv;
63
64 /*
65         Utility classes
66 */
67
68 u32 PacketCounter::sum() const
69 {
70         u32 n = 0;
71         for (const auto &it : m_packets)
72                 n += it.second;
73         return n;
74 }
75
76 void PacketCounter::print(std::ostream &o) const
77 {
78         for (const auto &it : m_packets) {
79                 auto name = it.first >= TOCLIENT_NUM_MSG_TYPES ? "?"
80                         : toClientCommandTable[it.first].name;
81                 o << "cmd " << it.first << " (" << name << ") count "
82                         << it.second << std::endl;
83         }
84 }
85
86 /*
87         Client
88 */
89
90 Client::Client(
91                 const char *playername,
92                 const std::string &password,
93                 const std::string &address_name,
94                 MapDrawControl &control,
95                 IWritableTextureSource *tsrc,
96                 IWritableShaderSource *shsrc,
97                 IWritableItemDefManager *itemdef,
98                 NodeDefManager *nodedef,
99                 ISoundManager *sound,
100                 MtEventManager *event,
101                 RenderingEngine *rendering_engine,
102                 bool ipv6,
103                 GameUI *game_ui
104 ):
105         m_tsrc(tsrc),
106         m_shsrc(shsrc),
107         m_itemdef(itemdef),
108         m_nodedef(nodedef),
109         m_sound(sound),
110         m_event(event),
111         m_rendering_engine(rendering_engine),
112         m_mesh_update_thread(this),
113         m_env(
114                 new ClientMap(this, rendering_engine, control, 666),
115                 tsrc, this
116         ),
117         m_particle_manager(&m_env),
118         m_con(new con::Connection(PROTOCOL_ID, 512, CONNECTION_TIMEOUT, ipv6, this)),
119         m_address_name(address_name),
120         m_server_ser_ver(SER_FMT_VER_INVALID),
121         m_last_chat_message_sent(time(NULL)),
122         m_password(password),
123         m_chosen_auth_mech(AUTH_MECHANISM_NONE),
124         m_media_downloader(new ClientMediaDownloader()),
125         m_state(LC_Created),
126         m_game_ui(game_ui),
127         m_modchannel_mgr(new ModChannelMgr())
128 {
129         // Add local player
130         m_env.setLocalPlayer(new LocalPlayer(this, playername));
131
132         // Make the mod storage database and begin the save for later
133         m_mod_storage_database =
134                 new ModMetadataDatabaseSQLite3(porting::path_user + DIR_DELIM + "client");
135         m_mod_storage_database->beginSave();
136
137         if (g_settings->getBool("enable_minimap")) {
138                 m_minimap = new Minimap(this);
139         }
140
141         m_cache_save_interval = g_settings->getU16("server_map_save_interval");
142 }
143
144 void Client::migrateModStorage()
145 {
146         std::string mod_storage_dir = porting::path_user + DIR_DELIM + "client";
147         std::string old_mod_storage = mod_storage_dir + DIR_DELIM + "mod_storage";
148         if (fs::IsDir(old_mod_storage)) {
149                 infostream << "Migrating client mod storage to SQLite3 database" << std::endl;
150                 {
151                         ModMetadataDatabaseFiles files_db(mod_storage_dir);
152                         std::vector<std::string> mod_list;
153                         files_db.listMods(&mod_list);
154                         for (const std::string &modname : mod_list) {
155                                 infostream << "Migrating client mod storage for mod " << modname << std::endl;
156                                 StringMap meta;
157                                 files_db.getModEntries(modname, &meta);
158                                 for (const auto &pair : meta) {
159                                         m_mod_storage_database->setModEntry(modname, pair.first, pair.second);
160                                 }
161                         }
162                 }
163                 if (!fs::Rename(old_mod_storage, old_mod_storage + ".bak")) {
164                         // Execution cannot move forward if the migration does not complete.
165                         throw BaseException("Could not finish migrating client mod storage");
166                 }
167                 infostream << "Finished migration of client mod storage" << std::endl;
168         }
169 }
170
171 void Client::loadMods()
172 {
173         // Don't load mods twice.
174         // If client scripting is disabled by the client, don't load builtin or
175         // client-provided mods.
176         if (m_mods_loaded || !g_settings->getBool("enable_client_modding"))
177                 return;
178
179         // If client scripting is disabled by the server, don't load builtin or
180         // client-provided mods.
181         // TODO Delete this code block when server-sent CSM and verifying of builtin are
182         // complete.
183         if (checkCSMRestrictionFlag(CSMRestrictionFlags::CSM_RF_LOAD_CLIENT_MODS)) {
184                 warningstream << "Client-provided mod loading is disabled by server." <<
185                         std::endl;
186                 return;
187         }
188
189         m_script = new ClientScripting(this);
190         m_env.setScript(m_script);
191         m_script->setEnv(&m_env);
192
193         // Load builtin
194         scanModIntoMemory(BUILTIN_MOD_NAME, getBuiltinLuaPath());
195         m_script->loadModFromMemory(BUILTIN_MOD_NAME);
196
197         ClientModConfiguration modconf(getClientModsLuaPath());
198         m_mods = modconf.getMods();
199         // complain about mods with unsatisfied dependencies
200         if (!modconf.isConsistent()) {
201                 modconf.printUnsatisfiedModsError();
202                 return;
203         }
204
205         // Print mods
206         infostream << "Client loading mods: ";
207         for (const ModSpec &mod : m_mods)
208                 infostream << mod.name << " ";
209         infostream << std::endl;
210
211         // Load "mod" scripts
212         for (const ModSpec &mod : m_mods) {
213                 mod.checkAndLog();
214                 scanModIntoMemory(mod.name, mod.path);
215         }
216
217         // Run them
218         for (const ModSpec &mod : m_mods)
219                 m_script->loadModFromMemory(mod.name);
220
221         // Mods are done loading. Unlock callbacks
222         m_mods_loaded = true;
223
224         // Run a callback when mods are loaded
225         m_script->on_mods_loaded();
226
227         // Create objects if they're ready
228         if (m_state == LC_Ready)
229                 m_script->on_client_ready(m_env.getLocalPlayer());
230         if (m_camera)
231                 m_script->on_camera_ready(m_camera);
232         if (m_minimap)
233                 m_script->on_minimap_ready(m_minimap);
234 }
235
236 void Client::scanModSubfolder(const std::string &mod_name, const std::string &mod_path,
237                         std::string mod_subpath)
238 {
239         std::string full_path = mod_path + DIR_DELIM + mod_subpath;
240         std::vector<fs::DirListNode> mod = fs::GetDirListing(full_path);
241         for (const fs::DirListNode &j : mod) {
242                 if (j.name[0] == '.')
243                         continue;
244
245                 if (j.dir) {
246                         scanModSubfolder(mod_name, mod_path, mod_subpath + j.name + DIR_DELIM);
247                         continue;
248                 }
249                 std::replace(mod_subpath.begin(), mod_subpath.end(), DIR_DELIM_CHAR, '/');
250
251                 std::string real_path = full_path + j.name;
252                 std::string vfs_path = mod_name + ":" + mod_subpath + j.name;
253                 infostream << "Client::scanModSubfolder(): Loading \"" << real_path
254                                 << "\" as \"" << vfs_path << "\"." << std::endl;
255
256                 std::string contents;
257                 if (!fs::ReadFile(real_path, contents)) {
258                         errorstream << "Client::scanModSubfolder(): Can't read file \""
259                                         << real_path << "\"." << std::endl;
260                         continue;
261                 }
262
263                 m_mod_vfs.emplace(vfs_path, contents);
264         }
265 }
266
267 const std::string &Client::getBuiltinLuaPath()
268 {
269         static const std::string builtin_dir = porting::path_share + DIR_DELIM + "builtin";
270         return builtin_dir;
271 }
272
273 const std::string &Client::getClientModsLuaPath()
274 {
275         static const std::string clientmods_dir = porting::path_share + DIR_DELIM + "clientmods";
276         return clientmods_dir;
277 }
278
279 const std::vector<ModSpec>& Client::getMods() const
280 {
281         static std::vector<ModSpec> client_modspec_temp;
282         return client_modspec_temp;
283 }
284
285 const ModSpec* Client::getModSpec(const std::string &modname) const
286 {
287         return NULL;
288 }
289
290 void Client::Stop()
291 {
292         m_shutdown = true;
293         if (m_mods_loaded)
294                 m_script->on_shutdown();
295         //request all client managed threads to stop
296         m_mesh_update_thread.stop();
297         // Save local server map
298         if (m_localdb) {
299                 infostream << "Local map saving ended." << std::endl;
300                 m_localdb->endSave();
301         }
302
303         if (m_mods_loaded)
304                 delete m_script;
305 }
306
307 bool Client::isShutdown()
308 {
309         return m_shutdown || !m_mesh_update_thread.isRunning();
310 }
311
312 Client::~Client()
313 {
314         m_shutdown = true;
315         m_con->Disconnect();
316
317         deleteAuthData();
318
319         m_mesh_update_thread.stop();
320         m_mesh_update_thread.wait();
321         while (!m_mesh_update_thread.m_queue_out.empty()) {
322                 MeshUpdateResult r = m_mesh_update_thread.m_queue_out.pop_frontNoEx();
323                 delete r.mesh;
324         }
325
326
327         delete m_inventory_from_server;
328
329         // Delete detached inventories
330         for (auto &m_detached_inventorie : m_detached_inventories) {
331                 delete m_detached_inventorie.second;
332         }
333
334         // cleanup 3d model meshes on client shutdown
335         m_rendering_engine->cleanupMeshCache();
336
337         guiScalingCacheClear();
338
339         delete m_minimap;
340         m_minimap = nullptr;
341
342         delete m_media_downloader;
343
344         // Write the changes and delete
345         if (m_mod_storage_database)
346                 m_mod_storage_database->endSave();
347         delete m_mod_storage_database;
348 }
349
350 void Client::connect(Address address, bool is_local_server)
351 {
352         initLocalMapSaving(address, m_address_name, is_local_server);
353
354         // Since we use TryReceive() a timeout here would be ineffective anyway
355         m_con->SetTimeoutMs(0);
356         m_con->Connect(address);
357 }
358
359 void Client::step(float dtime)
360 {
361         // Limit a bit
362         if (dtime > 2.0)
363                 dtime = 2.0;
364
365         m_animation_time += dtime;
366         if(m_animation_time > 60.0)
367                 m_animation_time -= 60.0;
368
369         m_time_of_day_update_timer += dtime;
370
371         ReceiveAll();
372
373         /*
374                 Packet counter
375         */
376         {
377                 float &counter = m_packetcounter_timer;
378                 counter -= dtime;
379                 if(counter <= 0.0f)
380                 {
381                         counter = 30.0f;
382                         u32 sum = m_packetcounter.sum();
383                         float avg = sum / counter;
384
385                         infostream << "Client packetcounter (" << counter << "s): "
386                                         << "sum=" << sum << " avg=" << avg << "/s" << std::endl;
387                         m_packetcounter.print(infostream);
388                         m_packetcounter.clear();
389                 }
390         }
391
392         // UGLY hack to fix 2 second startup delay caused by non existent
393         // server client startup synchronization in local server or singleplayer mode
394         static bool initial_step = true;
395         if (initial_step) {
396                 initial_step = false;
397         }
398         else if(m_state == LC_Created) {
399                 if (m_is_registration_confirmation_state) {
400                         // Waiting confirmation
401                         return;
402                 }
403                 float &counter = m_connection_reinit_timer;
404                 counter -= dtime;
405                 if(counter <= 0.0) {
406                         counter = 2.0;
407
408                         LocalPlayer *myplayer = m_env.getLocalPlayer();
409                         FATAL_ERROR_IF(myplayer == NULL, "Local player not found in environment.");
410
411                         sendInit(myplayer->getName());
412                 }
413
414                 // Not connected, return
415                 return;
416         }
417
418         /*
419                 Do stuff if connected
420         */
421
422         /*
423                 Run Map's timers and unload unused data
424         */
425         const float map_timer_and_unload_dtime = 5.25;
426         if(m_map_timer_and_unload_interval.step(dtime, map_timer_and_unload_dtime)) {
427                 std::vector<v3s16> deleted_blocks;
428                 m_env.getMap().timerUpdate(map_timer_and_unload_dtime,
429                         g_settings->getFloat("client_unload_unused_data_timeout"),
430                         g_settings->getS32("client_mapblock_limit"),
431                         &deleted_blocks);
432
433                 /*
434                         Send info to server
435                         NOTE: This loop is intentionally iterated the way it is.
436                 */
437
438                 std::vector<v3s16>::iterator i = deleted_blocks.begin();
439                 std::vector<v3s16> sendlist;
440                 for(;;) {
441                         if(sendlist.size() == 255 || i == deleted_blocks.end()) {
442                                 if(sendlist.empty())
443                                         break;
444                                 /*
445                                         [0] u16 command
446                                         [2] u8 count
447                                         [3] v3s16 pos_0
448                                         [3+6] v3s16 pos_1
449                                         ...
450                                 */
451
452                                 sendDeletedBlocks(sendlist);
453
454                                 if(i == deleted_blocks.end())
455                                         break;
456
457                                 sendlist.clear();
458                         }
459
460                         sendlist.push_back(*i);
461                         ++i;
462                 }
463         }
464
465         /*
466                 Send pending messages on out chat queue
467         */
468         if (!m_out_chat_queue.empty() && canSendChatMessage()) {
469                 sendChatMessage(m_out_chat_queue.front());
470                 m_out_chat_queue.pop();
471         }
472
473         /*
474                 Handle environment
475         */
476         LocalPlayer *player = m_env.getLocalPlayer();
477
478         // Step environment (also handles player controls)
479         m_env.step(dtime);
480         m_sound->step(dtime);
481
482         /*
483                 Get events
484         */
485         while (m_env.hasClientEnvEvents()) {
486                 ClientEnvEvent envEvent = m_env.getClientEnvEvent();
487
488                 if (envEvent.type == CEE_PLAYER_DAMAGE) {
489                         u16 damage = envEvent.player_damage.amount;
490
491                         if (envEvent.player_damage.send_to_server)
492                                 sendDamage(damage);
493
494                         // Add to ClientEvent queue
495                         ClientEvent *event = new ClientEvent();
496                         event->type = CE_PLAYER_DAMAGE;
497                         event->player_damage.amount = damage;
498                         m_client_event_queue.push(event);
499                 }
500         }
501
502         /*
503                 Print some info
504         */
505         float &counter = m_avg_rtt_timer;
506         counter += dtime;
507         if(counter >= 10) {
508                 counter = 0.0;
509                 // connectedAndInitialized() is true, peer exists.
510                 float avg_rtt = getRTT();
511                 infostream << "Client: avg_rtt=" << avg_rtt << std::endl;
512         }
513
514         /*
515                 Send player position to server
516         */
517         {
518                 float &counter = m_playerpos_send_timer;
519                 counter += dtime;
520                 if((m_state == LC_Ready) && (counter >= m_recommended_send_interval))
521                 {
522                         counter = 0.0;
523                         sendPlayerPos();
524                 }
525         }
526
527         /*
528                 Replace updated meshes
529         */
530         {
531                 int num_processed_meshes = 0;
532                 std::vector<v3s16> blocks_to_ack;
533                 while (!m_mesh_update_thread.m_queue_out.empty())
534                 {
535                         num_processed_meshes++;
536
537                         MinimapMapblock *minimap_mapblock = NULL;
538                         bool do_mapper_update = true;
539
540                         MeshUpdateResult r = m_mesh_update_thread.m_queue_out.pop_frontNoEx();
541                         MapBlock *block = m_env.getMap().getBlockNoCreateNoEx(r.p);
542                         if (block) {
543                                 // Delete the old mesh
544                                 delete block->mesh;
545                                 block->mesh = nullptr;
546
547                                 if (r.mesh) {
548                                         minimap_mapblock = r.mesh->moveMinimapMapblock();
549                                         if (minimap_mapblock == NULL)
550                                                 do_mapper_update = false;
551
552                                         bool is_empty = true;
553                                         for (int l = 0; l < MAX_TILE_LAYERS; l++)
554                                                 if (r.mesh->getMesh(l)->getMeshBufferCount() != 0)
555                                                         is_empty = false;
556
557                                         if (is_empty)
558                                                 delete r.mesh;
559                                         else
560                                                 // Replace with the new mesh
561                                                 block->mesh = r.mesh;
562                                 }
563                         } else {
564                                 delete r.mesh;
565                         }
566
567                         if (m_minimap && do_mapper_update)
568                                 m_minimap->addBlock(r.p, minimap_mapblock);
569
570                         if (r.ack_block_to_server) {
571                                 if (blocks_to_ack.size() == 255) {
572                                         sendGotBlocks(blocks_to_ack);
573                                         blocks_to_ack.clear();
574                                 }
575
576                                 blocks_to_ack.emplace_back(r.p);
577                         }
578                 }
579                 if (blocks_to_ack.size() > 0) {
580                                 // Acknowledge block(s)
581                                 sendGotBlocks(blocks_to_ack);
582                 }
583
584                 if (num_processed_meshes > 0)
585                         g_profiler->graphAdd("num_processed_meshes", num_processed_meshes);
586         }
587
588         /*
589                 Load fetched media
590         */
591         if (m_media_downloader && m_media_downloader->isStarted()) {
592                 m_media_downloader->step(this);
593                 if (m_media_downloader->isDone()) {
594                         delete m_media_downloader;
595                         m_media_downloader = NULL;
596                 }
597         }
598         {
599                 // Acknowledge dynamic media downloads to server
600                 std::vector<u32> done;
601                 for (auto it = m_pending_media_downloads.begin();
602                                 it != m_pending_media_downloads.end();) {
603                         assert(it->second->isStarted());
604                         it->second->step(this);
605                         if (it->second->isDone()) {
606                                 done.emplace_back(it->first);
607
608                                 it = m_pending_media_downloads.erase(it);
609                         } else {
610                                 it++;
611                         }
612
613                         if (done.size() == 255) { // maximum in one packet
614                                 sendHaveMedia(done);
615                                 done.clear();
616                         }
617                 }
618                 if (!done.empty())
619                         sendHaveMedia(done);
620         }
621
622         /*
623                 If the server didn't update the inventory in a while, revert
624                 the local inventory (so the player notices the lag problem
625                 and knows something is wrong).
626         */
627         if (m_inventory_from_server) {
628                 float interval = 10.0f;
629                 float count_before = std::floor(m_inventory_from_server_age / interval);
630
631                 m_inventory_from_server_age += dtime;
632
633                 float count_after = std::floor(m_inventory_from_server_age / interval);
634
635                 if (count_after != count_before) {
636                         // Do this every <interval> seconds after TOCLIENT_INVENTORY
637                         // Reset the locally changed inventory to the authoritative inventory
638                         player->inventory = *m_inventory_from_server;
639                         m_update_wielded_item = true;
640                 }
641         }
642
643         /*
644                 Update positions of sounds attached to objects
645         */
646         {
647                 for (auto &m_sounds_to_object : m_sounds_to_objects) {
648                         int client_id = m_sounds_to_object.first;
649                         u16 object_id = m_sounds_to_object.second;
650                         ClientActiveObject *cao = m_env.getActiveObject(object_id);
651                         if (!cao)
652                                 continue;
653                         m_sound->updateSoundPosition(client_id, cao->getPosition());
654                 }
655         }
656
657         /*
658                 Handle removed remotely initiated sounds
659         */
660         m_removed_sounds_check_timer += dtime;
661         if(m_removed_sounds_check_timer >= 2.32) {
662                 m_removed_sounds_check_timer = 0;
663                 // Find removed sounds and clear references to them
664                 std::vector<s32> removed_server_ids;
665                 for (std::unordered_map<s32, int>::iterator i = m_sounds_server_to_client.begin();
666                                 i != m_sounds_server_to_client.end();) {
667                         s32 server_id = i->first;
668                         int client_id = i->second;
669                         ++i;
670                         if(!m_sound->soundExists(client_id)) {
671                                 m_sounds_server_to_client.erase(server_id);
672                                 m_sounds_client_to_server.erase(client_id);
673                                 m_sounds_to_objects.erase(client_id);
674                                 removed_server_ids.push_back(server_id);
675                         }
676                 }
677
678                 // Sync to server
679                 if(!removed_server_ids.empty()) {
680                         sendRemovedSounds(removed_server_ids);
681                 }
682         }
683
684         // Write changes to the mod storage
685         m_mod_storage_save_timer -= dtime;
686         if (m_mod_storage_save_timer <= 0.0f) {
687                 m_mod_storage_save_timer = g_settings->getFloat("server_map_save_interval");
688                 m_mod_storage_database->endSave();
689                 m_mod_storage_database->beginSave();
690         }
691
692         // Write server map
693         if (m_localdb && m_localdb_save_interval.step(dtime,
694                         m_cache_save_interval)) {
695                 m_localdb->endSave();
696                 m_localdb->beginSave();
697         }
698 }
699
700 bool Client::loadMedia(const std::string &data, const std::string &filename,
701         bool from_media_push)
702 {
703         std::string name;
704
705         const char *image_ext[] = {
706                 ".png", ".jpg", ".bmp", ".tga",
707                 ".pcx", ".ppm", ".psd", ".wal", ".rgb",
708                 NULL
709         };
710         name = removeStringEnd(filename, image_ext);
711         if (!name.empty()) {
712                 TRACESTREAM(<< "Client: Attempting to load image "
713                         << "file \"" << filename << "\"" << std::endl);
714
715                 io::IFileSystem *irrfs = m_rendering_engine->get_filesystem();
716                 video::IVideoDriver *vdrv = m_rendering_engine->get_video_driver();
717
718                 io::IReadFile *rfile = irrfs->createMemoryReadFile(
719                                 data.c_str(), data.size(), "_tempreadfile");
720
721                 FATAL_ERROR_IF(!rfile, "Could not create irrlicht memory file.");
722
723                 // Read image
724                 video::IImage *img = vdrv->createImageFromFile(rfile);
725                 if (!img) {
726                         errorstream<<"Client: Cannot create image from data of "
727                                         <<"file \""<<filename<<"\""<<std::endl;
728                         rfile->drop();
729                         return false;
730                 }
731
732                 m_tsrc->insertSourceImage(filename, img);
733                 img->drop();
734                 rfile->drop();
735                 return true;
736         }
737
738         const char *sound_ext[] = {
739                 ".0.ogg", ".1.ogg", ".2.ogg", ".3.ogg", ".4.ogg",
740                 ".5.ogg", ".6.ogg", ".7.ogg", ".8.ogg", ".9.ogg",
741                 ".ogg", NULL
742         };
743         name = removeStringEnd(filename, sound_ext);
744         if (!name.empty()) {
745                 TRACESTREAM(<< "Client: Attempting to load sound "
746                         << "file \"" << filename << "\"" << std::endl);
747                 return m_sound->loadSoundData(name, data);
748         }
749
750         const char *model_ext[] = {
751                 ".x", ".b3d", ".md2", ".obj",
752                 NULL
753         };
754         name = removeStringEnd(filename, model_ext);
755         if (!name.empty()) {
756                 verbosestream<<"Client: Storing model into memory: "
757                                 <<"\""<<filename<<"\""<<std::endl;
758                 if(m_mesh_data.count(filename))
759                         errorstream<<"Multiple models with name \""<<filename.c_str()
760                                         <<"\" found; replacing previous model"<<std::endl;
761                 m_mesh_data[filename] = data;
762                 return true;
763         }
764
765         const char *translate_ext[] = {
766                 ".tr", NULL
767         };
768         name = removeStringEnd(filename, translate_ext);
769         if (!name.empty()) {
770                 if (from_media_push)
771                         return false;
772                 TRACESTREAM(<< "Client: Loading translation: "
773                                 << "\"" << filename << "\"" << std::endl);
774                 g_client_translations->loadTranslation(data);
775                 return true;
776         }
777
778         errorstream << "Client: Don't know how to load file \""
779                 << filename << "\"" << std::endl;
780         return false;
781 }
782
783 // Virtual methods from con::PeerHandler
784 void Client::peerAdded(con::Peer *peer)
785 {
786         infostream << "Client::peerAdded(): peer->id="
787                         << peer->id << std::endl;
788 }
789 void Client::deletingPeer(con::Peer *peer, bool timeout)
790 {
791         infostream << "Client::deletingPeer(): "
792                         "Server Peer is getting deleted "
793                         << "(timeout=" << timeout << ")" << std::endl;
794
795         if (timeout) {
796                 m_access_denied = true;
797                 m_access_denied_reason = gettext("Connection timed out.");
798         }
799 }
800
801 /*
802         u16 command
803         u16 number of files requested
804         for each file {
805                 u16 length of name
806                 string name
807         }
808 */
809 void Client::request_media(const std::vector<std::string> &file_requests)
810 {
811         std::ostringstream os(std::ios_base::binary);
812         writeU16(os, TOSERVER_REQUEST_MEDIA);
813         size_t file_requests_size = file_requests.size();
814
815         FATAL_ERROR_IF(file_requests_size > 0xFFFF, "Unsupported number of file requests");
816
817         // Packet dynamicly resized
818         NetworkPacket pkt(TOSERVER_REQUEST_MEDIA, 2 + 0);
819
820         pkt << (u16) (file_requests_size & 0xFFFF);
821
822         for (const std::string &file_request : file_requests) {
823                 pkt << file_request;
824         }
825
826         Send(&pkt);
827
828         infostream << "Client: Sending media request list to server ("
829                         << file_requests.size() << " files, packet size "
830                         << pkt.getSize() << ")" << std::endl;
831 }
832
833 void Client::initLocalMapSaving(const Address &address,
834                 const std::string &hostname,
835                 bool is_local_server)
836 {
837         if (!g_settings->getBool("enable_local_map_saving") || is_local_server) {
838                 return;
839         }
840
841         std::string world_path;
842 #define set_world_path(hostname) \
843         world_path = porting::path_user \
844                 + DIR_DELIM + "worlds" \
845                 + DIR_DELIM + "server_" \
846                 + hostname + "_" + std::to_string(address.getPort());
847
848         set_world_path(hostname);
849         if (!fs::IsDir(world_path)) {
850                 std::string hostname_escaped = hostname;
851                 str_replace(hostname_escaped, ':', '_');
852                 set_world_path(hostname_escaped);
853         }
854 #undef set_world_path
855         fs::CreateAllDirs(world_path);
856
857         m_localdb = new MapDatabaseSQLite3(world_path);
858         m_localdb->beginSave();
859         actionstream << "Local map saving started, map will be saved at '" << world_path << "'" << std::endl;
860 }
861
862 void Client::ReceiveAll()
863 {
864         NetworkPacket pkt;
865         u64 start_ms = porting::getTimeMs();
866         const u64 budget = 100;
867         for(;;) {
868                 // Limit time even if there would be huge amounts of data to
869                 // process
870                 if (porting::getTimeMs() > start_ms + budget) {
871                         infostream << "Client::ReceiveAll(): "
872                                         "Packet processing budget exceeded." << std::endl;
873                         break;
874                 }
875
876                 pkt.clear();
877                 try {
878                         if (!m_con->TryReceive(&pkt))
879                                 break;
880                         ProcessData(&pkt);
881                 } catch (const con::InvalidIncomingDataException &e) {
882                         infostream << "Client::ReceiveAll(): "
883                                         "InvalidIncomingDataException: what()="
884                                          << e.what() << std::endl;
885                 }
886         }
887 }
888
889 inline void Client::handleCommand(NetworkPacket* pkt)
890 {
891         const ToClientCommandHandler& opHandle = toClientCommandTable[pkt->getCommand()];
892         (this->*opHandle.handler)(pkt);
893 }
894
895 /*
896         sender_peer_id given to this shall be quaranteed to be a valid peer
897 */
898 void Client::ProcessData(NetworkPacket *pkt)
899 {
900         ToClientCommand command = (ToClientCommand) pkt->getCommand();
901         u32 sender_peer_id = pkt->getPeerId();
902
903         //infostream<<"Client: received command="<<command<<std::endl;
904         m_packetcounter.add((u16)command);
905         g_profiler->graphAdd("client_received_packets", 1);
906
907         /*
908                 If this check is removed, be sure to change the queue
909                 system to know the ids
910         */
911         if(sender_peer_id != PEER_ID_SERVER) {
912                 infostream << "Client::ProcessData(): Discarding data not "
913                         "coming from server: peer_id=" << sender_peer_id << " command=" << pkt->getCommand()
914                         << std::endl;
915                 return;
916         }
917
918         // Command must be handled into ToClientCommandHandler
919         if (command >= TOCLIENT_NUM_MSG_TYPES) {
920                 infostream << "Client: Ignoring unknown command "
921                         << command << std::endl;
922                 return;
923         }
924
925         /*
926          * Those packets are handled before m_server_ser_ver is set, it's normal
927          * But we must use the new ToClientConnectionState in the future,
928          * as a byte mask
929          */
930         if(toClientCommandTable[command].state == TOCLIENT_STATE_NOT_CONNECTED) {
931                 handleCommand(pkt);
932                 return;
933         }
934
935         if(m_server_ser_ver == SER_FMT_VER_INVALID) {
936                 infostream << "Client: Server serialization"
937                                 " format invalid or not initialized."
938                                 " Skipping incoming command=" << command << std::endl;
939                 return;
940         }
941
942         /*
943           Handle runtime commands
944         */
945
946         handleCommand(pkt);
947 }
948
949 void Client::Send(NetworkPacket* pkt)
950 {
951         m_con->Send(PEER_ID_SERVER,
952                 serverCommandFactoryTable[pkt->getCommand()].channel,
953                 pkt,
954                 serverCommandFactoryTable[pkt->getCommand()].reliable);
955 }
956
957 // Will fill up 12 + 12 + 4 + 4 + 4 bytes
958 void writePlayerPos(LocalPlayer *myplayer, ClientMap *clientMap, NetworkPacket *pkt)
959 {
960         v3f pf           = myplayer->getPosition() * 100;
961         v3f sf           = myplayer->getSpeed() * 100;
962         s32 pitch        = myplayer->getPitch() * 100;
963         s32 yaw          = myplayer->getYaw() * 100;
964         u32 keyPressed   = myplayer->control.getKeysPressed();
965         // scaled by 80, so that pi can fit into a u8
966         u8 fov           = clientMap->getCameraFov() * 80;
967         u8 wanted_range  = MYMIN(255,
968                         std::ceil(clientMap->getControl().wanted_range / MAP_BLOCKSIZE));
969
970         v3s32 position(pf.X, pf.Y, pf.Z);
971         v3s32 speed(sf.X, sf.Y, sf.Z);
972
973         /*
974                 Format:
975                 [0] v3s32 position*100
976                 [12] v3s32 speed*100
977                 [12+12] s32 pitch*100
978                 [12+12+4] s32 yaw*100
979                 [12+12+4+4] u32 keyPressed
980                 [12+12+4+4+4] u8 fov*80
981                 [12+12+4+4+4+1] u8 ceil(wanted_range / MAP_BLOCKSIZE)
982         */
983         *pkt << position << speed << pitch << yaw << keyPressed;
984         *pkt << fov << wanted_range;
985 }
986
987 void Client::interact(InteractAction action, const PointedThing& pointed)
988 {
989         if(m_state != LC_Ready) {
990                 errorstream << "Client::interact() "
991                                 "Canceled (not connected)"
992                                 << std::endl;
993                 return;
994         }
995
996         LocalPlayer *myplayer = m_env.getLocalPlayer();
997         if (myplayer == NULL)
998                 return;
999
1000         /*
1001                 [0] u16 command
1002                 [2] u8 action
1003                 [3] u16 item
1004                 [5] u32 length of the next item (plen)
1005                 [9] serialized PointedThing
1006                 [9 + plen] player position information
1007         */
1008
1009         NetworkPacket pkt(TOSERVER_INTERACT, 1 + 2 + 0);
1010
1011         pkt << (u8)action;
1012         pkt << myplayer->getWieldIndex();
1013
1014         std::ostringstream tmp_os(std::ios::binary);
1015         pointed.serialize(tmp_os);
1016
1017         pkt.putLongString(tmp_os.str());
1018
1019         writePlayerPos(myplayer, &m_env.getClientMap(), &pkt);
1020
1021         Send(&pkt);
1022 }
1023
1024 void Client::deleteAuthData()
1025 {
1026         if (!m_auth_data)
1027                 return;
1028
1029         switch (m_chosen_auth_mech) {
1030                 case AUTH_MECHANISM_FIRST_SRP:
1031                         break;
1032                 case AUTH_MECHANISM_SRP:
1033                 case AUTH_MECHANISM_LEGACY_PASSWORD:
1034                         srp_user_delete((SRPUser *) m_auth_data);
1035                         m_auth_data = NULL;
1036                         break;
1037                 case AUTH_MECHANISM_NONE:
1038                         break;
1039         }
1040         m_chosen_auth_mech = AUTH_MECHANISM_NONE;
1041 }
1042
1043
1044 AuthMechanism Client::choseAuthMech(const u32 mechs)
1045 {
1046         if (mechs & AUTH_MECHANISM_SRP)
1047                 return AUTH_MECHANISM_SRP;
1048
1049         if (mechs & AUTH_MECHANISM_FIRST_SRP)
1050                 return AUTH_MECHANISM_FIRST_SRP;
1051
1052         if (mechs & AUTH_MECHANISM_LEGACY_PASSWORD)
1053                 return AUTH_MECHANISM_LEGACY_PASSWORD;
1054
1055         return AUTH_MECHANISM_NONE;
1056 }
1057
1058 void Client::sendInit(const std::string &playerName)
1059 {
1060         NetworkPacket pkt(TOSERVER_INIT, 1 + 2 + 2 + (1 + playerName.size()));
1061
1062         // we don't support network compression yet
1063         u16 supp_comp_modes = NETPROTO_COMPRESSION_NONE;
1064
1065         pkt << (u8) SER_FMT_VER_HIGHEST_READ << (u16) supp_comp_modes;
1066         pkt << (u16) CLIENT_PROTOCOL_VERSION_MIN << (u16) CLIENT_PROTOCOL_VERSION_MAX;
1067         pkt << playerName;
1068
1069         Send(&pkt);
1070 }
1071
1072 void Client::promptConfirmRegistration(AuthMechanism chosen_auth_mechanism)
1073 {
1074         m_chosen_auth_mech = chosen_auth_mechanism;
1075         m_is_registration_confirmation_state = true;
1076 }
1077
1078 void Client::confirmRegistration()
1079 {
1080         m_is_registration_confirmation_state = false;
1081         startAuth(m_chosen_auth_mech);
1082 }
1083
1084 void Client::startAuth(AuthMechanism chosen_auth_mechanism)
1085 {
1086         m_chosen_auth_mech = chosen_auth_mechanism;
1087
1088         switch (chosen_auth_mechanism) {
1089                 case AUTH_MECHANISM_FIRST_SRP: {
1090                         // send srp verifier to server
1091                         std::string verifier;
1092                         std::string salt;
1093                         generate_srp_verifier_and_salt(getPlayerName(), m_password,
1094                                 &verifier, &salt);
1095
1096                         NetworkPacket resp_pkt(TOSERVER_FIRST_SRP, 0);
1097                         resp_pkt << salt << verifier << (u8)((m_password.empty()) ? 1 : 0);
1098
1099                         Send(&resp_pkt);
1100                         break;
1101                 }
1102                 case AUTH_MECHANISM_SRP:
1103                 case AUTH_MECHANISM_LEGACY_PASSWORD: {
1104                         u8 based_on = 1;
1105
1106                         if (chosen_auth_mechanism == AUTH_MECHANISM_LEGACY_PASSWORD) {
1107                                 m_password = translate_password(getPlayerName(), m_password);
1108                                 based_on = 0;
1109                         }
1110
1111                         std::string playername_u = lowercase(getPlayerName());
1112                         m_auth_data = srp_user_new(SRP_SHA256, SRP_NG_2048,
1113                                 getPlayerName().c_str(), playername_u.c_str(),
1114                                 (const unsigned char *) m_password.c_str(),
1115                                 m_password.length(), NULL, NULL);
1116                         char *bytes_A = 0;
1117                         size_t len_A = 0;
1118                         SRP_Result res = srp_user_start_authentication(
1119                                 (struct SRPUser *) m_auth_data, NULL, NULL, 0,
1120                                 (unsigned char **) &bytes_A, &len_A);
1121                         FATAL_ERROR_IF(res != SRP_OK, "Creating local SRP user failed.");
1122
1123                         NetworkPacket resp_pkt(TOSERVER_SRP_BYTES_A, 0);
1124                         resp_pkt << std::string(bytes_A, len_A) << based_on;
1125                         Send(&resp_pkt);
1126                         break;
1127                 }
1128                 case AUTH_MECHANISM_NONE:
1129                         break; // not handled in this method
1130         }
1131 }
1132
1133 void Client::sendDeletedBlocks(std::vector<v3s16> &blocks)
1134 {
1135         NetworkPacket pkt(TOSERVER_DELETEDBLOCKS, 1 + sizeof(v3s16) * blocks.size());
1136
1137         pkt << (u8) blocks.size();
1138
1139         for (const v3s16 &block : blocks) {
1140                 pkt << block;
1141         }
1142
1143         Send(&pkt);
1144 }
1145
1146 void Client::sendGotBlocks(const std::vector<v3s16> &blocks)
1147 {
1148         NetworkPacket pkt(TOSERVER_GOTBLOCKS, 1 + 6 * blocks.size());
1149         pkt << (u8) blocks.size();
1150         for (const v3s16 &block : blocks)
1151                 pkt << block;
1152
1153         Send(&pkt);
1154 }
1155
1156 void Client::sendRemovedSounds(std::vector<s32> &soundList)
1157 {
1158         size_t server_ids = soundList.size();
1159         assert(server_ids <= 0xFFFF);
1160
1161         NetworkPacket pkt(TOSERVER_REMOVED_SOUNDS, 2 + server_ids * 4);
1162
1163         pkt << (u16) (server_ids & 0xFFFF);
1164
1165         for (s32 sound_id : soundList)
1166                 pkt << sound_id;
1167
1168         Send(&pkt);
1169 }
1170
1171 void Client::sendNodemetaFields(v3s16 p, const std::string &formname,
1172                 const StringMap &fields)
1173 {
1174         size_t fields_size = fields.size();
1175
1176         FATAL_ERROR_IF(fields_size > 0xFFFF, "Unsupported number of nodemeta fields");
1177
1178         NetworkPacket pkt(TOSERVER_NODEMETA_FIELDS, 0);
1179
1180         pkt << p << formname << (u16) (fields_size & 0xFFFF);
1181
1182         StringMap::const_iterator it;
1183         for (it = fields.begin(); it != fields.end(); ++it) {
1184                 const std::string &name = it->first;
1185                 const std::string &value = it->second;
1186                 pkt << name;
1187                 pkt.putLongString(value);
1188         }
1189
1190         Send(&pkt);
1191 }
1192
1193 void Client::sendInventoryFields(const std::string &formname,
1194                 const StringMap &fields)
1195 {
1196         size_t fields_size = fields.size();
1197         FATAL_ERROR_IF(fields_size > 0xFFFF, "Unsupported number of inventory fields");
1198
1199         NetworkPacket pkt(TOSERVER_INVENTORY_FIELDS, 0);
1200         pkt << formname << (u16) (fields_size & 0xFFFF);
1201
1202         StringMap::const_iterator it;
1203         for (it = fields.begin(); it != fields.end(); ++it) {
1204                 const std::string &name  = it->first;
1205                 const std::string &value = it->second;
1206                 pkt << name;
1207                 pkt.putLongString(value);
1208         }
1209
1210         Send(&pkt);
1211 }
1212
1213 void Client::sendInventoryAction(InventoryAction *a)
1214 {
1215         std::ostringstream os(std::ios_base::binary);
1216
1217         a->serialize(os);
1218
1219         // Make data buffer
1220         std::string s = os.str();
1221
1222         NetworkPacket pkt(TOSERVER_INVENTORY_ACTION, s.size());
1223         pkt.putRawString(s.c_str(),s.size());
1224
1225         Send(&pkt);
1226 }
1227
1228 bool Client::canSendChatMessage() const
1229 {
1230         u32 now = time(NULL);
1231         float time_passed = now - m_last_chat_message_sent;
1232
1233         float virt_chat_message_allowance = m_chat_message_allowance + time_passed *
1234                         (CLIENT_CHAT_MESSAGE_LIMIT_PER_10S / 8.0f);
1235
1236         if (virt_chat_message_allowance < 1.0f)
1237                 return false;
1238
1239         return true;
1240 }
1241
1242 void Client::sendChatMessage(const std::wstring &message)
1243 {
1244         const s16 max_queue_size = g_settings->getS16("max_out_chat_queue_size");
1245         if (canSendChatMessage()) {
1246                 u32 now = time(NULL);
1247                 float time_passed = now - m_last_chat_message_sent;
1248                 m_last_chat_message_sent = now;
1249
1250                 m_chat_message_allowance += time_passed * (CLIENT_CHAT_MESSAGE_LIMIT_PER_10S / 8.0f);
1251                 if (m_chat_message_allowance > CLIENT_CHAT_MESSAGE_LIMIT_PER_10S)
1252                         m_chat_message_allowance = CLIENT_CHAT_MESSAGE_LIMIT_PER_10S;
1253
1254                 m_chat_message_allowance -= 1.0f;
1255
1256                 NetworkPacket pkt(TOSERVER_CHAT_MESSAGE, 2 + message.size() * sizeof(u16));
1257
1258                 pkt << message;
1259
1260                 Send(&pkt);
1261         } else if (m_out_chat_queue.size() < (u16) max_queue_size || max_queue_size == -1) {
1262                 m_out_chat_queue.push(message);
1263         } else {
1264                 infostream << "Could not queue chat message because maximum out chat queue size ("
1265                                 << max_queue_size << ") is reached." << std::endl;
1266         }
1267 }
1268
1269 void Client::clearOutChatQueue()
1270 {
1271         m_out_chat_queue = std::queue<std::wstring>();
1272 }
1273
1274 void Client::sendChangePassword(const std::string &oldpassword,
1275         const std::string &newpassword)
1276 {
1277         LocalPlayer *player = m_env.getLocalPlayer();
1278         if (player == NULL)
1279                 return;
1280
1281         // get into sudo mode and then send new password to server
1282         m_password = oldpassword;
1283         m_new_password = newpassword;
1284         startAuth(choseAuthMech(m_sudo_auth_methods));
1285 }
1286
1287
1288 void Client::sendDamage(u16 damage)
1289 {
1290         NetworkPacket pkt(TOSERVER_DAMAGE, sizeof(u16));
1291         pkt << damage;
1292         Send(&pkt);
1293 }
1294
1295 void Client::sendRespawn()
1296 {
1297         NetworkPacket pkt(TOSERVER_RESPAWN, 0);
1298         Send(&pkt);
1299 }
1300
1301 void Client::sendReady()
1302 {
1303         NetworkPacket pkt(TOSERVER_CLIENT_READY,
1304                         1 + 1 + 1 + 1 + 2 + sizeof(char) * strlen(g_version_hash) + 2);
1305
1306         pkt << (u8) VERSION_MAJOR << (u8) VERSION_MINOR << (u8) VERSION_PATCH
1307                 << (u8) 0 << (u16) strlen(g_version_hash);
1308
1309         pkt.putRawString(g_version_hash, (u16) strlen(g_version_hash));
1310         pkt << (u16)FORMSPEC_API_VERSION;
1311         Send(&pkt);
1312 }
1313
1314 void Client::sendPlayerPos()
1315 {
1316         LocalPlayer *player = m_env.getLocalPlayer();
1317         if (!player)
1318                 return;
1319
1320         // Save bandwidth by only updating position when
1321         // player is not dead and something changed
1322
1323         if (m_activeobjects_received && player->isDead())
1324                 return;
1325
1326         ClientMap &map = m_env.getClientMap();
1327         u8 camera_fov   = map.getCameraFov();
1328         u8 wanted_range = map.getControl().wanted_range;
1329
1330         u32 keyPressed = player->control.getKeysPressed();
1331
1332         if (
1333                         player->last_position     == player->getPosition() &&
1334                         player->last_speed        == player->getSpeed()    &&
1335                         player->last_pitch        == player->getPitch()    &&
1336                         player->last_yaw          == player->getYaw()      &&
1337                         player->last_keyPressed   == keyPressed            &&
1338                         player->last_camera_fov   == camera_fov            &&
1339                         player->last_wanted_range == wanted_range)
1340                 return;
1341
1342         player->last_position     = player->getPosition();
1343         player->last_speed        = player->getSpeed();
1344         player->last_pitch        = player->getPitch();
1345         player->last_yaw          = player->getYaw();
1346         player->last_keyPressed   = keyPressed;
1347         player->last_camera_fov   = camera_fov;
1348         player->last_wanted_range = wanted_range;
1349
1350         NetworkPacket pkt(TOSERVER_PLAYERPOS, 12 + 12 + 4 + 4 + 4 + 1 + 1);
1351
1352         writePlayerPos(player, &map, &pkt);
1353
1354         Send(&pkt);
1355 }
1356
1357 void Client::sendHaveMedia(const std::vector<u32> &tokens)
1358 {
1359         NetworkPacket pkt(TOSERVER_HAVE_MEDIA, 1 + tokens.size() * 4);
1360
1361         sanity_check(tokens.size() < 256);
1362
1363         pkt << static_cast<u8>(tokens.size());
1364         for (u32 token : tokens)
1365                 pkt << token;
1366
1367         Send(&pkt);
1368 }
1369
1370 void Client::removeNode(v3s16 p)
1371 {
1372         std::map<v3s16, MapBlock*> modified_blocks;
1373
1374         try {
1375                 m_env.getMap().removeNodeAndUpdate(p, modified_blocks);
1376         }
1377         catch(InvalidPositionException &e) {
1378         }
1379
1380         for (const auto &modified_block : modified_blocks) {
1381                 addUpdateMeshTaskWithEdge(modified_block.first, false, true);
1382         }
1383 }
1384
1385 /**
1386  * Helper function for Client Side Modding
1387  * CSM restrictions are applied there, this should not be used for core engine
1388  * @param p
1389  * @param is_valid_position
1390  * @return
1391  */
1392 MapNode Client::CSMGetNode(v3s16 p, bool *is_valid_position)
1393 {
1394         if (checkCSMRestrictionFlag(CSMRestrictionFlags::CSM_RF_LOOKUP_NODES)) {
1395                 v3s16 ppos = floatToInt(m_env.getLocalPlayer()->getPosition(), BS);
1396                 if ((u32) ppos.getDistanceFrom(p) > m_csm_restriction_noderange) {
1397                         *is_valid_position = false;
1398                         return {};
1399                 }
1400         }
1401         return m_env.getMap().getNode(p, is_valid_position);
1402 }
1403
1404 int Client::CSMClampRadius(v3s16 pos, int radius)
1405 {
1406         if (!checkCSMRestrictionFlag(CSMRestrictionFlags::CSM_RF_LOOKUP_NODES))
1407                 return radius;
1408         // This is approximate and will cause some allowed nodes to be excluded
1409         v3s16 ppos = floatToInt(m_env.getLocalPlayer()->getPosition(), BS);
1410         u32 distance = ppos.getDistanceFrom(pos);
1411         if (distance >= m_csm_restriction_noderange)
1412                 return 0;
1413         return std::min<int>(radius, m_csm_restriction_noderange - distance);
1414 }
1415
1416 v3s16 Client::CSMClampPos(v3s16 pos)
1417 {
1418         if (!checkCSMRestrictionFlag(CSMRestrictionFlags::CSM_RF_LOOKUP_NODES))
1419                 return pos;
1420         v3s16 ppos = floatToInt(m_env.getLocalPlayer()->getPosition(), BS);
1421         const int range = m_csm_restriction_noderange;
1422         return v3s16(
1423                 core::clamp<int>(pos.X, (int)ppos.X - range, (int)ppos.X + range),
1424                 core::clamp<int>(pos.Y, (int)ppos.Y - range, (int)ppos.Y + range),
1425                 core::clamp<int>(pos.Z, (int)ppos.Z - range, (int)ppos.Z + range)
1426         );
1427 }
1428
1429 void Client::addNode(v3s16 p, MapNode n, bool remove_metadata)
1430 {
1431         //TimeTaker timer1("Client::addNode()");
1432
1433         std::map<v3s16, MapBlock*> modified_blocks;
1434
1435         try {
1436                 //TimeTaker timer3("Client::addNode(): addNodeAndUpdate");
1437                 m_env.getMap().addNodeAndUpdate(p, n, modified_blocks, remove_metadata);
1438         }
1439         catch(InvalidPositionException &e) {
1440         }
1441
1442         for (const auto &modified_block : modified_blocks) {
1443                 addUpdateMeshTaskWithEdge(modified_block.first, false, true);
1444         }
1445 }
1446
1447 void Client::setPlayerControl(PlayerControl &control)
1448 {
1449         LocalPlayer *player = m_env.getLocalPlayer();
1450         assert(player);
1451         player->control = control;
1452 }
1453
1454 void Client::setPlayerItem(u16 item)
1455 {
1456         m_env.getLocalPlayer()->setWieldIndex(item);
1457         m_update_wielded_item = true;
1458
1459         NetworkPacket pkt(TOSERVER_PLAYERITEM, 2);
1460         pkt << item;
1461         Send(&pkt);
1462 }
1463
1464 // Returns true once after the inventory of the local player
1465 // has been updated from the server.
1466 bool Client::updateWieldedItem()
1467 {
1468         if (!m_update_wielded_item)
1469                 return false;
1470
1471         m_update_wielded_item = false;
1472
1473         LocalPlayer *player = m_env.getLocalPlayer();
1474         assert(player);
1475         if (auto *list = player->inventory.getList("main"))
1476                 list->setModified(false);
1477         if (auto *list = player->inventory.getList("hand"))
1478                 list->setModified(false);
1479
1480         return true;
1481 }
1482
1483 scene::ISceneManager* Client::getSceneManager()
1484 {
1485         return m_rendering_engine->get_scene_manager();
1486 }
1487
1488 Inventory* Client::getInventory(const InventoryLocation &loc)
1489 {
1490         switch(loc.type){
1491         case InventoryLocation::UNDEFINED:
1492         {}
1493         break;
1494         case InventoryLocation::CURRENT_PLAYER:
1495         {
1496                 LocalPlayer *player = m_env.getLocalPlayer();
1497                 assert(player);
1498                 return &player->inventory;
1499         }
1500         break;
1501         case InventoryLocation::PLAYER:
1502         {
1503                 // Check if we are working with local player inventory
1504                 LocalPlayer *player = m_env.getLocalPlayer();
1505                 if (!player || strcmp(player->getName(), loc.name.c_str()) != 0)
1506                         return NULL;
1507                 return &player->inventory;
1508         }
1509         break;
1510         case InventoryLocation::NODEMETA:
1511         {
1512                 NodeMetadata *meta = m_env.getMap().getNodeMetadata(loc.p);
1513                 if(!meta)
1514                         return NULL;
1515                 return meta->getInventory();
1516         }
1517         break;
1518         case InventoryLocation::DETACHED:
1519         {
1520                 if (m_detached_inventories.count(loc.name) == 0)
1521                         return NULL;
1522                 return m_detached_inventories[loc.name];
1523         }
1524         break;
1525         default:
1526                 FATAL_ERROR("Invalid inventory location type.");
1527                 break;
1528         }
1529         return NULL;
1530 }
1531
1532 void Client::inventoryAction(InventoryAction *a)
1533 {
1534         /*
1535                 Send it to the server
1536         */
1537         sendInventoryAction(a);
1538
1539         /*
1540                 Predict some local inventory changes
1541         */
1542         a->clientApply(this, this);
1543
1544         // Remove it
1545         delete a;
1546 }
1547
1548 float Client::getAnimationTime()
1549 {
1550         return m_animation_time;
1551 }
1552
1553 int Client::getCrackLevel()
1554 {
1555         return m_crack_level;
1556 }
1557
1558 v3s16 Client::getCrackPos()
1559 {
1560         return m_crack_pos;
1561 }
1562
1563 void Client::setCrack(int level, v3s16 pos)
1564 {
1565         int old_crack_level = m_crack_level;
1566         v3s16 old_crack_pos = m_crack_pos;
1567
1568         m_crack_level = level;
1569         m_crack_pos = pos;
1570
1571         if(old_crack_level >= 0 && (level < 0 || pos != old_crack_pos))
1572         {
1573                 // remove old crack
1574                 addUpdateMeshTaskForNode(old_crack_pos, false, true);
1575         }
1576         if(level >= 0 && (old_crack_level < 0 || pos != old_crack_pos))
1577         {
1578                 // add new crack
1579                 addUpdateMeshTaskForNode(pos, false, true);
1580         }
1581 }
1582
1583 u16 Client::getHP()
1584 {
1585         LocalPlayer *player = m_env.getLocalPlayer();
1586         assert(player);
1587         return player->hp;
1588 }
1589
1590 bool Client::getChatMessage(std::wstring &res)
1591 {
1592         if (m_chat_queue.empty())
1593                 return false;
1594
1595         ChatMessage *chatMessage = m_chat_queue.front();
1596         m_chat_queue.pop();
1597
1598         res = L"";
1599
1600         switch (chatMessage->type) {
1601                 case CHATMESSAGE_TYPE_RAW:
1602                 case CHATMESSAGE_TYPE_ANNOUNCE:
1603                 case CHATMESSAGE_TYPE_SYSTEM:
1604                         res = chatMessage->message;
1605                         break;
1606                 case CHATMESSAGE_TYPE_NORMAL: {
1607                         if (!chatMessage->sender.empty())
1608                                 res = L"<" + chatMessage->sender + L"> " + chatMessage->message;
1609                         else
1610                                 res = chatMessage->message;
1611                         break;
1612                 }
1613                 default:
1614                         break;
1615         }
1616
1617         delete chatMessage;
1618         return true;
1619 }
1620
1621 void Client::typeChatMessage(const std::wstring &message)
1622 {
1623         // Discard empty line
1624         if (message.empty())
1625                 return;
1626
1627         // If message was consumed by script API, don't send it to server
1628         if (m_mods_loaded && m_script->on_sending_message(wide_to_utf8(message)))
1629                 return;
1630
1631         // Send to others
1632         sendChatMessage(message);
1633 }
1634
1635 void Client::addUpdateMeshTask(v3s16 p, bool ack_to_server, bool urgent)
1636 {
1637         // Check if the block exists to begin with. In the case when a non-existing
1638         // neighbor is automatically added, it may not. In that case we don't want
1639         // to tell the mesh update thread about it.
1640         MapBlock *b = m_env.getMap().getBlockNoCreateNoEx(p);
1641         if (b == NULL)
1642                 return;
1643
1644         m_mesh_update_thread.updateBlock(&m_env.getMap(), p, ack_to_server, urgent);
1645 }
1646
1647 void Client::addUpdateMeshTaskWithEdge(v3s16 blockpos, bool ack_to_server, bool urgent)
1648 {
1649         m_mesh_update_thread.updateBlock(&m_env.getMap(), blockpos, ack_to_server, urgent, true);
1650 }
1651
1652 void Client::addUpdateMeshTaskForNode(v3s16 nodepos, bool ack_to_server, bool urgent)
1653 {
1654         {
1655                 v3s16 p = nodepos;
1656                 infostream<<"Client::addUpdateMeshTaskForNode(): "
1657                                 <<"("<<p.X<<","<<p.Y<<","<<p.Z<<")"
1658                                 <<std::endl;
1659         }
1660
1661         v3s16 blockpos = getNodeBlockPos(nodepos);
1662         v3s16 blockpos_relative = blockpos * MAP_BLOCKSIZE;
1663         m_mesh_update_thread.updateBlock(&m_env.getMap(), blockpos, ack_to_server, urgent, false);
1664         // Leading edge
1665         if (nodepos.X == blockpos_relative.X)
1666                 addUpdateMeshTask(blockpos + v3s16(-1, 0, 0), false, urgent);
1667         if (nodepos.Y == blockpos_relative.Y)
1668                 addUpdateMeshTask(blockpos + v3s16(0, -1, 0), false, urgent);
1669         if (nodepos.Z == blockpos_relative.Z)
1670                 addUpdateMeshTask(blockpos + v3s16(0, 0, -1), false, urgent);
1671 }
1672
1673 ClientEvent *Client::getClientEvent()
1674 {
1675         FATAL_ERROR_IF(m_client_event_queue.empty(),
1676                         "Cannot getClientEvent, queue is empty.");
1677
1678         ClientEvent *event = m_client_event_queue.front();
1679         m_client_event_queue.pop();
1680         return event;
1681 }
1682
1683 const Address Client::getServerAddress()
1684 {
1685         return m_con->GetPeerAddress(PEER_ID_SERVER);
1686 }
1687
1688 float Client::mediaReceiveProgress()
1689 {
1690         if (m_media_downloader)
1691                 return m_media_downloader->getProgress();
1692
1693         return 1.0; // downloader only exists when not yet done
1694 }
1695
1696 struct TextureUpdateArgs {
1697         gui::IGUIEnvironment *guienv;
1698         u64 last_time_ms;
1699         u16 last_percent;
1700         const wchar_t* text_base;
1701         ITextureSource *tsrc;
1702 };
1703
1704 void Client::showUpdateProgressTexture(void *args, u32 progress, u32 max_progress)
1705 {
1706                 TextureUpdateArgs* targs = (TextureUpdateArgs*) args;
1707                 u16 cur_percent = ceil(progress / (double) max_progress * 100.);
1708
1709                 // update the loading menu -- if neccessary
1710                 bool do_draw = false;
1711                 u64 time_ms = targs->last_time_ms;
1712                 if (cur_percent != targs->last_percent) {
1713                         targs->last_percent = cur_percent;
1714                         time_ms = porting::getTimeMs();
1715                         // only draw when the user will notice something:
1716                         do_draw = (time_ms - targs->last_time_ms > 100);
1717                 }
1718
1719                 if (do_draw) {
1720                         targs->last_time_ms = time_ms;
1721                         std::wostringstream strm;
1722                         strm << targs->text_base << L" " << targs->last_percent << L"%...";
1723                         m_rendering_engine->draw_load_screen(strm.str(), targs->guienv, targs->tsrc, 0,
1724                                 72 + (u16) ((18. / 100.) * (double) targs->last_percent), true);
1725                 }
1726 }
1727
1728 void Client::afterContentReceived()
1729 {
1730         infostream<<"Client::afterContentReceived() started"<<std::endl;
1731         assert(m_itemdef_received); // pre-condition
1732         assert(m_nodedef_received); // pre-condition
1733         assert(mediaReceived()); // pre-condition
1734
1735         const wchar_t* text = wgettext("Loading textures...");
1736
1737         // Clear cached pre-scaled 2D GUI images, as this cache
1738         // might have images with the same name but different
1739         // content from previous sessions.
1740         guiScalingCacheClear();
1741
1742         // Rebuild inherited images and recreate textures
1743         infostream<<"- Rebuilding images and textures"<<std::endl;
1744         m_rendering_engine->draw_load_screen(text, guienv, m_tsrc, 0, 70);
1745         m_tsrc->rebuildImagesAndTextures();
1746         delete[] text;
1747
1748         // Rebuild shaders
1749         infostream<<"- Rebuilding shaders"<<std::endl;
1750         text = wgettext("Rebuilding shaders...");
1751         m_rendering_engine->draw_load_screen(text, guienv, m_tsrc, 0, 71);
1752         m_shsrc->rebuildShaders();
1753         delete[] text;
1754
1755         // Update node aliases
1756         infostream<<"- Updating node aliases"<<std::endl;
1757         text = wgettext("Initializing nodes...");
1758         m_rendering_engine->draw_load_screen(text, guienv, m_tsrc, 0, 72);
1759         m_nodedef->updateAliases(m_itemdef);
1760         for (const auto &path : getTextureDirs()) {
1761                 TextureOverrideSource override_source(path + DIR_DELIM + "override.txt");
1762                 m_nodedef->applyTextureOverrides(override_source.getNodeTileOverrides());
1763                 m_itemdef->applyTextureOverrides(override_source.getItemTextureOverrides());
1764         }
1765         m_nodedef->setNodeRegistrationStatus(true);
1766         m_nodedef->runNodeResolveCallbacks();
1767         delete[] text;
1768
1769         // Update node textures and assign shaders to each tile
1770         infostream<<"- Updating node textures"<<std::endl;
1771         TextureUpdateArgs tu_args;
1772         tu_args.guienv = guienv;
1773         tu_args.last_time_ms = porting::getTimeMs();
1774         tu_args.last_percent = 0;
1775         tu_args.text_base = wgettext("Initializing nodes");
1776         tu_args.tsrc = m_tsrc;
1777         m_nodedef->updateTextures(this, &tu_args);
1778         delete[] tu_args.text_base;
1779
1780         // Start mesh update thread after setting up content definitions
1781         infostream<<"- Starting mesh update thread"<<std::endl;
1782         m_mesh_update_thread.start();
1783
1784         m_state = LC_Ready;
1785         sendReady();
1786
1787         if (m_mods_loaded)
1788                 m_script->on_client_ready(m_env.getLocalPlayer());
1789
1790         text = wgettext("Done!");
1791         m_rendering_engine->draw_load_screen(text, guienv, m_tsrc, 0, 100);
1792         infostream<<"Client::afterContentReceived() done"<<std::endl;
1793         delete[] text;
1794 }
1795
1796 float Client::getRTT()
1797 {
1798         return m_con->getPeerStat(PEER_ID_SERVER,con::AVG_RTT);
1799 }
1800
1801 float Client::getCurRate()
1802 {
1803         return (m_con->getLocalStat(con::CUR_INC_RATE) +
1804                         m_con->getLocalStat(con::CUR_DL_RATE));
1805 }
1806
1807 void Client::makeScreenshot()
1808 {
1809         irr::video::IVideoDriver *driver = m_rendering_engine->get_video_driver();
1810         irr::video::IImage* const raw_image = driver->createScreenShot();
1811
1812         if (!raw_image)
1813                 return;
1814
1815         const struct tm tm = mt_localtime();
1816
1817         char timetstamp_c[64];
1818         strftime(timetstamp_c, sizeof(timetstamp_c), "%Y%m%d_%H%M%S", &tm);
1819
1820         std::string screenshot_dir;
1821
1822         if (fs::IsPathAbsolute(g_settings->get("screenshot_path")))
1823                 screenshot_dir = g_settings->get("screenshot_path");
1824         else
1825                 screenshot_dir = porting::path_user + DIR_DELIM + g_settings->get("screenshot_path");
1826
1827         std::string filename_base = screenshot_dir
1828                         + DIR_DELIM
1829                         + std::string("screenshot_")
1830                         + std::string(timetstamp_c);
1831         std::string filename_ext = "." + g_settings->get("screenshot_format");
1832         std::string filename;
1833
1834         // Create the directory if it doesn't already exist.
1835         // Otherwise, saving the screenshot would fail.
1836         fs::CreateDir(screenshot_dir);
1837
1838         u32 quality = (u32)g_settings->getS32("screenshot_quality");
1839         quality = MYMIN(MYMAX(quality, 0), 100) / 100.0 * 255;
1840
1841         // Try to find a unique filename
1842         unsigned serial = 0;
1843
1844         while (serial < SCREENSHOT_MAX_SERIAL_TRIES) {
1845                 filename = filename_base + (serial > 0 ? ("_" + itos(serial)) : "") + filename_ext;
1846                 std::ifstream tmp(filename.c_str());
1847                 if (!tmp.good())
1848                         break;  // File did not apparently exist, we'll go with it
1849                 serial++;
1850         }
1851
1852         if (serial == SCREENSHOT_MAX_SERIAL_TRIES) {
1853                 infostream << "Could not find suitable filename for screenshot" << std::endl;
1854         } else {
1855                 irr::video::IImage* const image =
1856                                 driver->createImage(video::ECF_R8G8B8, raw_image->getDimension());
1857
1858                 if (image) {
1859                         raw_image->copyTo(image);
1860
1861                         std::ostringstream sstr;
1862                         if (driver->writeImageToFile(image, filename.c_str(), quality)) {
1863                                 sstr << "Saved screenshot to '" << filename << "'";
1864                         } else {
1865                                 sstr << "Failed to save screenshot '" << filename << "'";
1866                         }
1867                         pushToChatQueue(new ChatMessage(CHATMESSAGE_TYPE_SYSTEM,
1868                                         utf8_to_wide(sstr.str())));
1869                         infostream << sstr.str() << std::endl;
1870                         image->drop();
1871                 }
1872         }
1873
1874         raw_image->drop();
1875 }
1876
1877 bool Client::shouldShowMinimap() const
1878 {
1879         return !m_minimap_disabled_by_server;
1880 }
1881
1882 void Client::pushToEventQueue(ClientEvent *event)
1883 {
1884         m_client_event_queue.push(event);
1885 }
1886
1887 void Client::showMinimap(const bool show)
1888 {
1889         m_game_ui->showMinimap(show);
1890 }
1891
1892 // IGameDef interface
1893 // Under envlock
1894 IItemDefManager* Client::getItemDefManager()
1895 {
1896         return m_itemdef;
1897 }
1898 const NodeDefManager* Client::getNodeDefManager()
1899 {
1900         return m_nodedef;
1901 }
1902 ICraftDefManager* Client::getCraftDefManager()
1903 {
1904         return NULL;
1905         //return m_craftdef;
1906 }
1907 ITextureSource* Client::getTextureSource()
1908 {
1909         return m_tsrc;
1910 }
1911 IWritableShaderSource* Client::getShaderSource()
1912 {
1913         return m_shsrc;
1914 }
1915
1916 u16 Client::allocateUnknownNodeId(const std::string &name)
1917 {
1918         errorstream << "Client::allocateUnknownNodeId(): "
1919                         << "Client cannot allocate node IDs" << std::endl;
1920         FATAL_ERROR("Client allocated unknown node");
1921
1922         return CONTENT_IGNORE;
1923 }
1924 ISoundManager* Client::getSoundManager()
1925 {
1926         return m_sound;
1927 }
1928 MtEventManager* Client::getEventManager()
1929 {
1930         return m_event;
1931 }
1932
1933 ParticleManager* Client::getParticleManager()
1934 {
1935         return &m_particle_manager;
1936 }
1937
1938 scene::IAnimatedMesh* Client::getMesh(const std::string &filename, bool cache)
1939 {
1940         StringMap::const_iterator it = m_mesh_data.find(filename);
1941         if (it == m_mesh_data.end()) {
1942                 errorstream << "Client::getMesh(): Mesh not found: \"" << filename
1943                         << "\"" << std::endl;
1944                 return NULL;
1945         }
1946         const std::string &data    = it->second;
1947
1948         // Create the mesh, remove it from cache and return it
1949         // This allows unique vertex colors and other properties for each instance
1950         io::IReadFile *rfile = m_rendering_engine->get_filesystem()->createMemoryReadFile(
1951                         data.c_str(), data.size(), filename.c_str());
1952         FATAL_ERROR_IF(!rfile, "Could not create/open RAM file");
1953
1954         scene::IAnimatedMesh *mesh = m_rendering_engine->get_scene_manager()->getMesh(rfile);
1955         rfile->drop();
1956         if (!mesh)
1957                 return nullptr;
1958         mesh->grab();
1959         if (!cache)
1960                 m_rendering_engine->removeMesh(mesh);
1961         return mesh;
1962 }
1963
1964 const std::string* Client::getModFile(std::string filename)
1965 {
1966         // strip dir delimiter from beginning of path
1967         auto pos = filename.find_first_of(':');
1968         if (pos == std::string::npos)
1969                 return nullptr;
1970         pos++;
1971         auto pos2 = filename.find_first_not_of('/', pos);
1972         if (pos2 > pos)
1973                 filename.erase(pos, pos2 - pos);
1974
1975         StringMap::const_iterator it = m_mod_vfs.find(filename);
1976         if (it == m_mod_vfs.end())
1977                 return nullptr;
1978         return &it->second;
1979 }
1980
1981 bool Client::registerModStorage(ModMetadata *storage)
1982 {
1983         if (m_mod_storages.find(storage->getModName()) != m_mod_storages.end()) {
1984                 errorstream << "Unable to register same mod storage twice. Storage name: "
1985                                 << storage->getModName() << std::endl;
1986                 return false;
1987         }
1988
1989         m_mod_storages[storage->getModName()] = storage;
1990         return true;
1991 }
1992
1993 void Client::unregisterModStorage(const std::string &name)
1994 {
1995         std::unordered_map<std::string, ModMetadata *>::const_iterator it =
1996                 m_mod_storages.find(name);
1997         if (it != m_mod_storages.end())
1998                 m_mod_storages.erase(name);
1999 }
2000
2001 /*
2002  * Mod channels
2003  */
2004
2005 bool Client::joinModChannel(const std::string &channel)
2006 {
2007         if (m_modchannel_mgr->channelRegistered(channel))
2008                 return false;
2009
2010         NetworkPacket pkt(TOSERVER_MODCHANNEL_JOIN, 2 + channel.size());
2011         pkt << channel;
2012         Send(&pkt);
2013
2014         m_modchannel_mgr->joinChannel(channel, 0);
2015         return true;
2016 }
2017
2018 bool Client::leaveModChannel(const std::string &channel)
2019 {
2020         if (!m_modchannel_mgr->channelRegistered(channel))
2021                 return false;
2022
2023         NetworkPacket pkt(TOSERVER_MODCHANNEL_LEAVE, 2 + channel.size());
2024         pkt << channel;
2025         Send(&pkt);
2026
2027         m_modchannel_mgr->leaveChannel(channel, 0);
2028         return true;
2029 }
2030
2031 bool Client::sendModChannelMessage(const std::string &channel, const std::string &message)
2032 {
2033         if (!m_modchannel_mgr->canWriteOnChannel(channel))
2034                 return false;
2035
2036         if (message.size() > STRING_MAX_LEN) {
2037                 warningstream << "ModChannel message too long, dropping before sending "
2038                                 << " (" << message.size() << " > " << STRING_MAX_LEN << ", channel: "
2039                                 << channel << ")" << std::endl;
2040                 return false;
2041         }
2042
2043         // @TODO: do some client rate limiting
2044         NetworkPacket pkt(TOSERVER_MODCHANNEL_MSG, 2 + channel.size() + 2 + message.size());
2045         pkt << channel << message;
2046         Send(&pkt);
2047         return true;
2048 }
2049
2050 ModChannel* Client::getModChannel(const std::string &channel)
2051 {
2052         return m_modchannel_mgr->getModChannel(channel);
2053 }