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