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