]> git.lizzy.rs Git - dragonfireclient.git/blob - src/client/game.h
Added customizable keybindings, improved freecam, added special inventory keybind...
[dragonfireclient.git] / src / client / game.h
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 #pragma once
21
22 #include <iomanip>
23 #include <cmath>
24 #include "client/renderingengine.h"
25 #include "camera.h"
26 #include "client.h"
27 #include "client/clientevent.h"
28 //#include "client/gameui.h"
29 #include "client/inputhandler.h"
30 #include "client/sound.h"
31 #include "client/tile.h"     // For TextureSource
32 #include "client/keys.h"
33 #include "client/joystick_controller.h"
34 #include "clientmap.h"
35 #include "clouds.h"
36 #include "config.h"
37 #include "content_cao.h"
38 #include "client/event_manager.h"
39 #include "fontengine.h"
40 #include "itemdef.h"
41 #include "log.h"
42 #include "filesys.h"
43 #include "gettext.h"
44 #include "gui/guiChatConsole.h"
45 #include "gui/guiConfirmRegistration.h"
46 #include "gui/guiFormSpecMenu.h"
47 #include "gui/guiKeyChangeMenu.h"
48 #include "gui/guiPasswordChange.h"
49 #include "gui/guiVolumeChange.h"
50 #include "gui/mainmenumanager.h"
51 #include "gui/profilergraph.h"
52 #include "mapblock.h"
53 #include "minimap.h"
54 #include "nodedef.h"         // Needed for determining pointing to nodes
55 #include "nodemetadata.h"
56 #include "particles.h"
57 #include "porting.h"
58 #include "profiler.h"
59 #include "raycast.h"
60 #include "server.h"
61 #include "settings.h"
62 #include "shader.h"
63 #include "sky.h"
64 #include "translation.h"
65 #include "util/basic_macros.h"
66 #include "util/directiontables.h"
67 #include "util/pointedthing.h"
68 #include "util/quicktune_shortcutter.h"
69 #include "irrlicht_changes/static_text.h"
70 #include "version.h"
71 #include "script/scripting_client.h"
72 #include "hud.h"
73 #include "irrlichttypes.h"
74 #include <string>
75
76 class InputHandler;
77 class ChatBackend;  /* to avoid having to include chat.h */
78 struct SubgameSpec;
79 struct GameStartData;
80
81 struct Jitter {
82         f32 max, min, avg, counter, max_sample, min_sample, max_fraction;
83 };
84
85 struct RunStats {
86         u32 drawtime;
87
88         Jitter dtime_jitter, busy_time_jitter;
89 };
90
91 struct CameraOrientation {
92         f32 camera_yaw;    // "right/left"
93         f32 camera_pitch;  // "up/down"
94 };
95
96 /*
97         Text input system
98 */
99
100 struct TextDestNodeMetadata : public TextDest
101 {
102         TextDestNodeMetadata(v3s16 p, Client *client)
103         {
104                 m_p = p;
105                 m_client = client;
106         }
107         // This is deprecated I guess? -celeron55
108         void gotText(const std::wstring &text)
109         {
110                 std::string ntext = wide_to_utf8(text);
111                 infostream << "Submitting 'text' field of node at (" << m_p.X << ","
112                            << m_p.Y << "," << m_p.Z << "): " << ntext << std::endl;
113                 StringMap fields;
114                 fields["text"] = ntext;
115                 m_client->sendNodemetaFields(m_p, "", fields);
116         }
117         void gotText(const StringMap &fields)
118         {
119                 m_client->sendNodemetaFields(m_p, "", fields);
120         }
121
122         v3s16 m_p;
123         Client *m_client;
124 };
125
126 struct TextDestPlayerInventory : public TextDest
127 {
128         TextDestPlayerInventory(Client *client)
129         {
130                 m_client = client;
131                 m_formname = "";
132         }
133         TextDestPlayerInventory(Client *client, const std::string &formname)
134         {
135                 m_client = client;
136                 m_formname = formname;
137         }
138         void gotText(const StringMap &fields)
139         {
140                 m_client->sendInventoryFields(m_formname, fields);
141         }
142
143         Client *m_client;
144 };
145
146 struct LocalFormspecHandler : public TextDest
147 {
148         LocalFormspecHandler(const std::string &formname)
149         {
150                 m_formname = formname;
151         }
152
153         LocalFormspecHandler(const std::string &formname, Client *client):
154                 m_client(client)
155         {
156                 m_formname = formname;
157         }
158
159         void gotText(const StringMap &fields)
160         {
161                 if (m_formname == "MT_PAUSE_MENU") {
162                         if (fields.find("btn_sound") != fields.end()) {
163                                 g_gamecallback->changeVolume();
164                                 return;
165                         }
166
167                         if (fields.find("btn_key_config") != fields.end()) {
168                                 g_gamecallback->keyConfig();
169                                 return;
170                         }
171
172                         if (fields.find("btn_exit_menu") != fields.end()) {
173                                 g_gamecallback->disconnect();
174                                 return;
175                         }
176
177                         if (fields.find("btn_exit_os") != fields.end()) {
178                                 g_gamecallback->exitToOS();
179 #ifndef __ANDROID__
180                                 RenderingEngine::get_raw_device()->closeDevice();
181 #endif
182                                 return;
183                         }
184
185                         if (fields.find("btn_change_password") != fields.end()) {
186                                 g_gamecallback->changePassword();
187                                 return;
188                         }
189
190                         if (fields.find("quit") != fields.end()) {
191                                 return;
192                         }
193
194                         if (fields.find("btn_continue") != fields.end()) {
195                                 return;
196                         }
197                 }
198
199                 if (m_formname == "MT_DEATH_SCREEN") {
200                         assert(m_client != 0);
201                         m_client->sendRespawn();
202                         return;
203                 }
204
205                 if (m_client && m_client->modsLoaded())
206                         m_client->getScript()->on_formspec_input(m_formname, fields);
207         }
208
209         Client *m_client = nullptr;
210 };
211
212 /* Form update callback */
213
214 class NodeMetadataFormSource: public IFormSource
215 {
216 public:
217         NodeMetadataFormSource(ClientMap *map, v3s16 p):
218                 m_map(map),
219                 m_p(p)
220         {
221         }
222         const std::string &getForm() const
223         {
224                 static const std::string empty_string = "";
225                 NodeMetadata *meta = m_map->getNodeMetadata(m_p);
226
227                 if (!meta)
228                         return empty_string;
229
230                 return meta->getString("formspec");
231         }
232
233         virtual std::string resolveText(const std::string &str)
234         {
235                 NodeMetadata *meta = m_map->getNodeMetadata(m_p);
236
237                 if (!meta)
238                         return str;
239
240                 return meta->resolveString(str);
241         }
242
243         ClientMap *m_map;
244         v3s16 m_p;
245 };
246
247 class PlayerInventoryFormSource: public IFormSource
248 {
249 public:
250         PlayerInventoryFormSource(Client *client):
251                 m_client(client)
252         {
253         }
254
255         const std::string &getForm() const
256         {
257                 LocalPlayer *player = m_client->getEnv().getLocalPlayer();
258                 return player->inventory_formspec;
259         }
260
261         Client *m_client;
262 };
263
264 class NodeDugEvent: public MtEvent
265 {
266 public:
267         v3s16 p;
268         MapNode n;
269
270         NodeDugEvent(v3s16 p, MapNode n):
271                 p(p),
272                 n(n)
273         {}
274         MtEvent::Type getType() const
275         {
276                 return MtEvent::NODE_DUG;
277         }
278 };
279
280 class SoundMaker
281 {
282         ISoundManager *m_sound;
283         const NodeDefManager *m_ndef;
284 public:
285         bool makes_footstep_sound;
286         float m_player_step_timer;
287         float m_player_jump_timer;
288
289         SimpleSoundSpec m_player_step_sound;
290         SimpleSoundSpec m_player_leftpunch_sound;
291         SimpleSoundSpec m_player_rightpunch_sound;
292
293         SoundMaker(ISoundManager *sound, const NodeDefManager *ndef):
294                 m_sound(sound),
295                 m_ndef(ndef),
296                 makes_footstep_sound(true),
297                 m_player_step_timer(0),
298                 m_player_jump_timer(0.0f)
299         {
300         }
301
302         void playPlayerStep()
303         {
304                 if (m_player_step_timer <= 0 && m_player_step_sound.exists()) {
305                         m_player_step_timer = 0.03;
306                         if (makes_footstep_sound)
307                                 m_sound->playSound(m_player_step_sound, false);
308                 }
309         }
310
311         void playPlayerJump()
312         {
313                 if (m_player_jump_timer <= 0.0f) {
314                         m_player_jump_timer = 0.2f;
315                         m_sound->playSound(SimpleSoundSpec("player_jump", 0.5f), false);
316                 }
317         }
318
319         static void viewBobbingStep(MtEvent *e, void *data)
320         {
321                 SoundMaker *sm = (SoundMaker *)data;
322                 sm->playPlayerStep();
323         }
324
325         static void playerRegainGround(MtEvent *e, void *data)
326         {
327                 SoundMaker *sm = (SoundMaker *)data;
328                 sm->playPlayerStep();
329         }
330
331         static void playerJump(MtEvent *e, void *data)
332         {
333                 SoundMaker *sm = (SoundMaker *)data;
334                 sm->playPlayerJump();
335         }
336
337         static void cameraPunchLeft(MtEvent *e, void *data)
338         {
339                 SoundMaker *sm = (SoundMaker *)data;
340                 sm->m_sound->playSound(sm->m_player_leftpunch_sound, false);
341         }
342
343         static void cameraPunchRight(MtEvent *e, void *data)
344         {
345                 SoundMaker *sm = (SoundMaker *)data;
346                 sm->m_sound->playSound(sm->m_player_rightpunch_sound, false);
347         }
348
349         static void nodeDug(MtEvent *e, void *data)
350         {
351                 SoundMaker *sm = (SoundMaker *)data;
352                 NodeDugEvent *nde = (NodeDugEvent *)e;
353                 sm->m_sound->playSound(sm->m_ndef->get(nde->n).sound_dug, false);
354         }
355
356         static void playerDamage(MtEvent *e, void *data)
357         {
358                 SoundMaker *sm = (SoundMaker *)data;
359                 sm->m_sound->playSound(SimpleSoundSpec("player_damage", 0.5), false);
360         }
361
362         static void playerFallingDamage(MtEvent *e, void *data)
363         {
364                 SoundMaker *sm = (SoundMaker *)data;
365                 sm->m_sound->playSound(SimpleSoundSpec("player_falling_damage", 0.5), false);
366         }
367
368         void registerReceiver(MtEventManager *mgr)
369         {
370                 mgr->reg(MtEvent::VIEW_BOBBING_STEP, SoundMaker::viewBobbingStep, this);
371                 mgr->reg(MtEvent::PLAYER_REGAIN_GROUND, SoundMaker::playerRegainGround, this);
372                 mgr->reg(MtEvent::PLAYER_JUMP, SoundMaker::playerJump, this);
373                 mgr->reg(MtEvent::CAMERA_PUNCH_LEFT, SoundMaker::cameraPunchLeft, this);
374                 mgr->reg(MtEvent::CAMERA_PUNCH_RIGHT, SoundMaker::cameraPunchRight, this);
375                 mgr->reg(MtEvent::NODE_DUG, SoundMaker::nodeDug, this);
376                 mgr->reg(MtEvent::PLAYER_DAMAGE, SoundMaker::playerDamage, this);
377                 mgr->reg(MtEvent::PLAYER_FALLING_DAMAGE, SoundMaker::playerFallingDamage, this);
378         }
379
380         void step(float dtime)
381         {
382                 m_player_step_timer -= dtime;
383                 m_player_jump_timer -= dtime;
384         }
385 };
386
387 // Locally stored sounds don't need to be preloaded because of this
388 class GameOnDemandSoundFetcher: public OnDemandSoundFetcher
389 {
390         std::set<std::string> m_fetched;
391 private:
392         void paths_insert(std::set<std::string> &dst_paths,
393                 const std::string &base,
394                 const std::string &name)
395         {
396                 dst_paths.insert(base + DIR_DELIM + "sounds" + DIR_DELIM + name + ".ogg");
397                 dst_paths.insert(base + DIR_DELIM + "sounds" + DIR_DELIM + name + ".0.ogg");
398                 dst_paths.insert(base + DIR_DELIM + "sounds" + DIR_DELIM + name + ".1.ogg");
399                 dst_paths.insert(base + DIR_DELIM + "sounds" + DIR_DELIM + name + ".2.ogg");
400                 dst_paths.insert(base + DIR_DELIM + "sounds" + DIR_DELIM + name + ".3.ogg");
401                 dst_paths.insert(base + DIR_DELIM + "sounds" + DIR_DELIM + name + ".4.ogg");
402                 dst_paths.insert(base + DIR_DELIM + "sounds" + DIR_DELIM + name + ".5.ogg");
403                 dst_paths.insert(base + DIR_DELIM + "sounds" + DIR_DELIM + name + ".6.ogg");
404                 dst_paths.insert(base + DIR_DELIM + "sounds" + DIR_DELIM + name + ".7.ogg");
405                 dst_paths.insert(base + DIR_DELIM + "sounds" + DIR_DELIM + name + ".8.ogg");
406                 dst_paths.insert(base + DIR_DELIM + "sounds" + DIR_DELIM + name + ".9.ogg");
407         }
408 public:
409         void fetchSounds(const std::string &name,
410                 std::set<std::string> &dst_paths,
411                 std::set<std::string> &dst_datas)
412         {
413                 if (m_fetched.count(name))
414                         return;
415
416                 m_fetched.insert(name);
417
418                 paths_insert(dst_paths, porting::path_share, name);
419                 paths_insert(dst_paths, porting::path_user,  name);
420         }
421 };
422
423
424 // before 1.8 there isn't a "integer interface", only float
425 #if (IRRLICHT_VERSION_MAJOR == 1 && IRRLICHT_VERSION_MINOR < 8)
426 typedef f32 SamplerLayer_t;
427 #else
428 typedef s32 SamplerLayer_t;
429 #endif
430
431
432 class GameGlobalShaderConstantSetter : public IShaderConstantSetter
433 {
434         Sky *m_sky;
435         bool *m_force_fog_off;
436         f32 *m_fog_range;
437         bool m_fog_enabled;
438         CachedPixelShaderSetting<float, 4> m_sky_bg_color;
439         CachedPixelShaderSetting<float> m_fog_distance;
440         CachedVertexShaderSetting<float> m_animation_timer_vertex;
441         CachedPixelShaderSetting<float> m_animation_timer_pixel;
442         CachedPixelShaderSetting<float, 3> m_day_light;
443         CachedPixelShaderSetting<float, 3> m_eye_position_pixel;
444         CachedVertexShaderSetting<float, 3> m_eye_position_vertex;
445         CachedPixelShaderSetting<float, 3> m_minimap_yaw;
446         CachedPixelShaderSetting<float, 3> m_camera_offset_pixel;
447         CachedPixelShaderSetting<float, 3> m_camera_offset_vertex;
448         CachedPixelShaderSetting<SamplerLayer_t> m_base_texture;
449         CachedPixelShaderSetting<SamplerLayer_t> m_normal_texture;
450         CachedPixelShaderSetting<SamplerLayer_t> m_texture_flags;
451         Client *m_client;
452
453 public:
454         void onSettingsChange(const std::string &name)
455         {
456                 if (name == "enable_fog")
457                         m_fog_enabled = g_settings->getBool("enable_fog");
458         }
459
460         static void settingsCallback(const std::string &name, void *userdata)
461         {
462                 reinterpret_cast<GameGlobalShaderConstantSetter*>(userdata)->onSettingsChange(name);
463         }
464
465         void setSky(Sky *sky) { m_sky = sky; }
466
467         GameGlobalShaderConstantSetter(Sky *sky, bool *force_fog_off,
468                         f32 *fog_range, Client *client) :
469                 m_sky(sky),
470                 m_force_fog_off(force_fog_off),
471                 m_fog_range(fog_range),
472                 m_sky_bg_color("skyBgColor"),
473                 m_fog_distance("fogDistance"),
474                 m_animation_timer_vertex("animationTimer"),
475                 m_animation_timer_pixel("animationTimer"),
476                 m_day_light("dayLight"),
477                 m_eye_position_pixel("eyePosition"),
478                 m_eye_position_vertex("eyePosition"),
479                 m_minimap_yaw("yawVec"),
480                 m_camera_offset_pixel("cameraOffset"),
481                 m_camera_offset_vertex("cameraOffset"),
482                 m_base_texture("baseTexture"),
483                 m_normal_texture("normalTexture"),
484                 m_texture_flags("textureFlags"),
485                 m_client(client)
486         {
487                 g_settings->registerChangedCallback("enable_fog", settingsCallback, this);
488                 m_fog_enabled = g_settings->getBool("enable_fog");
489         }
490
491         ~GameGlobalShaderConstantSetter()
492         {
493                 g_settings->deregisterChangedCallback("enable_fog", settingsCallback, this);
494         }
495
496         virtual void onSetConstants(video::IMaterialRendererServices *services,
497                         bool is_highlevel)
498         {
499                 if (!is_highlevel)
500                         return;
501
502                 // Background color
503                 video::SColor bgcolor = m_sky->getBgColor();
504                 video::SColorf bgcolorf(bgcolor);
505                 float bgcolorfa[4] = {
506                         bgcolorf.r,
507                         bgcolorf.g,
508                         bgcolorf.b,
509                         bgcolorf.a,
510                 };
511                 m_sky_bg_color.set(bgcolorfa, services);
512
513                 // Fog distance
514                 float fog_distance = 10000 * BS;
515
516                 if (m_fog_enabled && !*m_force_fog_off)
517                         fog_distance = *m_fog_range;
518
519                 m_fog_distance.set(&fog_distance, services);
520
521                 u32 daynight_ratio = (float)m_client->getEnv().getDayNightRatio();
522                 video::SColorf sunlight;
523                 get_sunlight_color(&sunlight, daynight_ratio);
524                 float dnc[3] = {
525                         sunlight.r,
526                         sunlight.g,
527                         sunlight.b };
528                 m_day_light.set(dnc, services);
529
530                 u32 animation_timer = porting::getTimeMs() % 1000000;
531                 float animation_timer_f = (float)animation_timer / 100000.f;
532                 m_animation_timer_vertex.set(&animation_timer_f, services);
533                 m_animation_timer_pixel.set(&animation_timer_f, services);
534
535                 float eye_position_array[3];
536                 v3f epos = m_client->getEnv().getLocalPlayer()->getEyePosition();
537 #if (IRRLICHT_VERSION_MAJOR == 1 && IRRLICHT_VERSION_MINOR < 8)
538                 eye_position_array[0] = epos.X;
539                 eye_position_array[1] = epos.Y;
540                 eye_position_array[2] = epos.Z;
541 #else
542                 epos.getAs3Values(eye_position_array);
543 #endif
544                 m_eye_position_pixel.set(eye_position_array, services);
545                 m_eye_position_vertex.set(eye_position_array, services);
546
547                 if (m_client->getMinimap()) {
548                         float minimap_yaw_array[3];
549                         v3f minimap_yaw = m_client->getMinimap()->getYawVec();
550 #if (IRRLICHT_VERSION_MAJOR == 1 && IRRLICHT_VERSION_MINOR < 8)
551                         minimap_yaw_array[0] = minimap_yaw.X;
552                         minimap_yaw_array[1] = minimap_yaw.Y;
553                         minimap_yaw_array[2] = minimap_yaw.Z;
554 #else
555                         minimap_yaw.getAs3Values(minimap_yaw_array);
556 #endif
557                         m_minimap_yaw.set(minimap_yaw_array, services);
558                 }
559
560                 float camera_offset_array[3];
561                 v3f offset = intToFloat(m_client->getCamera()->getOffset(), BS);
562 #if (IRRLICHT_VERSION_MAJOR == 1 && IRRLICHT_VERSION_MINOR < 8)
563                 camera_offset_array[0] = offset.X;
564                 camera_offset_array[1] = offset.Y;
565                 camera_offset_array[2] = offset.Z;
566 #else
567                 offset.getAs3Values(camera_offset_array);
568 #endif
569                 m_camera_offset_pixel.set(camera_offset_array, services);
570                 m_camera_offset_vertex.set(camera_offset_array, services);
571
572                 SamplerLayer_t base_tex = 0,
573                                 normal_tex = 1,
574                                 flags_tex = 2;
575                 m_base_texture.set(&base_tex, services);
576                 m_normal_texture.set(&normal_tex, services);
577                 m_texture_flags.set(&flags_tex, services);
578         }
579 };
580
581
582 class GameGlobalShaderConstantSetterFactory : public IShaderConstantSetterFactory
583 {
584         Sky *m_sky;
585         bool *m_force_fog_off;
586         f32 *m_fog_range;
587         Client *m_client;
588         std::vector<GameGlobalShaderConstantSetter *> created_nosky;
589 public:
590         GameGlobalShaderConstantSetterFactory(bool *force_fog_off,
591                         f32 *fog_range, Client *client) :
592                 m_sky(NULL),
593                 m_force_fog_off(force_fog_off),
594                 m_fog_range(fog_range),
595                 m_client(client)
596         {}
597
598         void setSky(Sky *sky) {
599                 m_sky = sky;
600                 for (GameGlobalShaderConstantSetter *ggscs : created_nosky) {
601                         ggscs->setSky(m_sky);
602                 }
603                 created_nosky.clear();
604         }
605
606         virtual IShaderConstantSetter* create()
607         {
608                 GameGlobalShaderConstantSetter *scs = new GameGlobalShaderConstantSetter(
609                                 m_sky, m_force_fog_off, m_fog_range, m_client);
610                 if (!m_sky)
611                         created_nosky.push_back(scs);
612                 return scs;
613         }
614 };
615
616 #ifdef __ANDROID__
617 #define SIZE_TAG "size[11,5.5]"
618 #else
619 #define SIZE_TAG "size[11,5.5,true]" // Fixed size on desktop
620 #endif
621
622 /****************************************************************************
623
624  ****************************************************************************/
625
626 const float object_hit_delay = 0.2;
627
628 struct FpsControl {
629         u32 last_time, busy_time, sleep_time;
630 };
631
632
633 /* The reason the following structs are not anonymous structs within the
634  * class is that they are not used by the majority of member functions and
635  * many functions that do require objects of thse types do not modify them
636  * (so they can be passed as a const qualified parameter)
637  */
638
639 struct GameRunData {
640         u16 dig_index;
641         u16 new_playeritem;
642         PointedThing pointed_old;
643         bool digging;
644         bool ldown_for_dig;
645         bool dig_instantly;
646         bool digging_blocked;
647         bool left_punch;
648         bool reset_jump_timer;
649         float nodig_delay_timer;
650         float dig_time;
651         float dig_time_complete;
652         float repeat_rightclick_timer;
653         float object_hit_delay_timer;
654         float time_from_last_punch;
655         ClientActiveObject *selected_object;
656
657         float jump_timer;
658         float damage_flash;
659         float update_draw_list_timer;
660
661         f32 fog_range;
662
663         v3f update_draw_list_last_cam_dir;
664
665         float time_of_day_smooth;
666 };
667
668 class Game;
669
670 struct ClientEventHandler
671 {
672         void (Game::*handler)(ClientEvent *, CameraOrientation *);
673 };
674
675 class Game {
676 public:
677         Game();
678         ~Game();
679
680         bool startup(bool *kill,
681                         InputHandler *input,
682                         const GameStartData &game_params,
683                         std::string &error_message,
684                         bool *reconnect,
685                         ChatBackend *chat_backend);
686
687
688         void run();
689         void shutdown();
690
691         void extendedResourceCleanup();
692
693         // Basic initialisation
694         bool init(const std::string &map_dir, const std::string &address,
695                         u16 port, const SubgameSpec &gamespec);
696         bool initSound();
697         bool createSingleplayerServer(const std::string &map_dir,
698                         const SubgameSpec &gamespec, u16 port);
699
700         // Client creation
701         bool createClient(const GameStartData &start_data);
702         bool initGui();
703
704         // Client connection
705         bool connectToServer(const GameStartData &start_data,
706                         bool *connect_ok, bool *aborted);
707         bool getServerContent(bool *aborted);
708
709         // Main loop
710
711         void updateInteractTimers(f32 dtime);
712         bool checkConnection();
713         bool handleCallbacks();
714         void processQueues();
715         void updateProfilers(const RunStats &stats, const FpsControl &draw_times, f32 dtime);
716         void updateStats(RunStats *stats, const FpsControl &draw_times, f32 dtime);
717         void updateProfilerGraphs(ProfilerGraph *graph);
718
719         // Input related
720         void processUserInput(f32 dtime);
721         void processKeyInput();
722         void processItemSelection(u16 *new_playeritem);
723
724         void dropSelectedItem(bool single_item = false);
725         void openInventory();
726         void openSpecialInventory();
727         void openConsole(float scale, const wchar_t *line=NULL);
728         void toggleFreeMove();
729         void toggleFreeMoveAlt();
730         void togglePitchMove();
731         void toggleFast();
732         void toggleNoClip();
733         void toggleXray();
734         void toggleFullbright();
735         void toggleKillaura();
736         void toggleFreecam();
737         void toggleCinematic();
738         void toggleAutoforward();
739
740         void toggleMinimap(bool shift_pressed);
741         void toggleFog();
742         void toggleDebug();
743         void toggleUpdateCamera();
744
745         void increaseViewRange();
746         void decreaseViewRange();
747         void toggleFullViewRange();
748         void checkZoomEnabled();
749
750         void updateCameraDirection(CameraOrientation *cam, float dtime);
751         void updateCameraOrientation(CameraOrientation *cam, float dtime);
752         void updatePlayerControl(const CameraOrientation &cam);
753         void step(f32 *dtime);
754         void processClientEvents(CameraOrientation *cam);
755         void updateCamera(u32 busy_time, f32 dtime);
756         void updateSound(f32 dtime);
757         void processPlayerInteraction(f32 dtime, bool show_hud, bool show_debug);
758         /*!
759          * Returns the object or node the player is pointing at.
760          * Also updates the selected thing in the Hud.
761          *
762          * @param[in]  shootline         the shootline, starting from
763          * the camera position. This also gives the maximal distance
764          * of the search.
765          * @param[in]  liquids_pointable if false, liquids are ignored
766          * @param[in]  look_for_object   if false, objects are ignored
767          * @param[in]  camera_offset     offset of the camera
768          * @param[out] selected_object   the selected object or
769          * NULL if not found
770          */
771         PointedThing updatePointedThing(
772                         const core::line3d<f32> &shootline, bool liquids_pointable,
773                         bool look_for_object, const v3s16 &camera_offset);
774         void handlePointingAtNothing(const ItemStack &playerItem);
775         void handlePointingAtNode(const PointedThing &pointed,
776                         const ItemStack &selected_item, const ItemStack &hand_item, f32 dtime);
777         void handlePointingAtObject(const PointedThing &pointed, const ItemStack &playeritem,
778                         const v3f &player_position, bool show_debug);
779         void handleDigging(const PointedThing &pointed, const v3s16 &nodepos,
780                         const ItemStack &selected_item, const ItemStack &hand_item, f32 dtime);
781         void updateFrame(ProfilerGraph *graph, RunStats *stats, f32 dtime,
782                         const CameraOrientation &cam);
783
784         // Misc
785         void limitFps(FpsControl *fps_timings, f32 *dtime);
786
787         void showOverlayMessage(const char *msg, float dtime, int percent,
788                         bool draw_clouds = true);
789
790         static void settingChangedCallback(const std::string &setting_name, void *data);
791         void readSettings();
792
793         inline bool isKeyDown(GameKeyType k)
794         {
795                 return input->isKeyDown(k);
796         }
797         inline bool wasKeyDown(GameKeyType k)
798         {
799                 return input->wasKeyDown(k);
800         }
801
802 #ifdef __ANDROID__
803         void handleAndroidChatInput();
804 #endif
805
806         struct Flags {
807                 bool force_fog_off = false;
808                 bool disable_camera_update = false;
809         };
810
811         void showDeathFormspec();
812         void showPauseMenu();
813
814         // ClientEvent handlers
815         void handleClientEvent_None(ClientEvent *event, CameraOrientation *cam);
816         void handleClientEvent_PlayerDamage(ClientEvent *event, CameraOrientation *cam);
817         void handleClientEvent_PlayerForceMove(ClientEvent *event, CameraOrientation *cam);
818         void handleClientEvent_Deathscreen(ClientEvent *event, CameraOrientation *cam);
819         void handleClientEvent_ShowFormSpec(ClientEvent *event, CameraOrientation *cam);
820         void handleClientEvent_ShowLocalFormSpec(ClientEvent *event, CameraOrientation *cam);
821         void handleClientEvent_HandleParticleEvent(ClientEvent *event,
822                 CameraOrientation *cam);
823         void handleClientEvent_HudAdd(ClientEvent *event, CameraOrientation *cam);
824         void handleClientEvent_HudRemove(ClientEvent *event, CameraOrientation *cam);
825         void handleClientEvent_HudChange(ClientEvent *event, CameraOrientation *cam);
826         void handleClientEvent_SetSky(ClientEvent *event, CameraOrientation *cam);
827         void handleClientEvent_SetSun(ClientEvent *event, CameraOrientation *cam);
828         void handleClientEvent_SetMoon(ClientEvent *event, CameraOrientation *cam);
829         void handleClientEvent_SetStars(ClientEvent *event, CameraOrientation *cam);
830         void handleClientEvent_OverrideDayNigthRatio(ClientEvent *event,
831                 CameraOrientation *cam);
832         void handleClientEvent_CloudParams(ClientEvent *event, CameraOrientation *cam);
833
834         void updateChat(f32 dtime, const v2u32 &screensize);
835
836         bool nodePlacement(const ItemDefinition &selected_def, const ItemStack &selected_item,
837                 const v3s16 &nodepos, const v3s16 &neighbourpos, const PointedThing &pointed,
838                 const NodeMetadata *meta);
839         static const ClientEventHandler clientEventHandler[CLIENTEVENT_MAX];
840
841         InputHandler *input = nullptr;
842
843         Client *client = nullptr;
844         Server *server = nullptr;
845
846         IWritableTextureSource *texture_src = nullptr;
847         IWritableShaderSource *shader_src = nullptr;
848
849         // When created, these will be filled with data received from the server
850         IWritableItemDefManager *itemdef_manager = nullptr;
851         NodeDefManager *nodedef_manager = nullptr;
852
853         GameOnDemandSoundFetcher soundfetcher; // useful when testing
854         ISoundManager *sound = nullptr;
855         bool sound_is_dummy = false;
856         SoundMaker *soundmaker = nullptr;
857
858         ChatBackend *chat_backend = nullptr;
859         LogOutputBuffer m_chat_log_buf;
860         
861         EventManager *eventmgr = nullptr;
862         QuicktuneShortcutter *quicktune = nullptr;
863         bool registration_confirmation_shown = false;
864
865         std::unique_ptr<GameUI> m_game_ui;
866         GUIChatConsole *gui_chat_console = nullptr; // Free using ->Drop()
867         MapDrawControl *draw_control = nullptr;
868         Camera *camera = nullptr;
869         Clouds *clouds = nullptr;                         // Free using ->Drop()
870         Sky *sky = nullptr;                         // Free using ->Drop()
871         Hud *hud = nullptr;
872         Minimap *mapper = nullptr;
873
874         GameRunData runData;
875         Flags m_flags;
876
877         /* 'cache'
878            This class does take ownership/responsibily for cleaning up etc of any of
879            these items (e.g. device)
880         */
881         IrrlichtDevice *device;
882         video::IVideoDriver *driver;
883         scene::ISceneManager *smgr;
884         bool *kill;
885         std::string *error_message;
886         bool *reconnect_requested;
887         scene::ISceneNode *skybox;
888
889         bool random_input;
890         bool simple_singleplayer_mode;
891         /* End 'cache' */
892
893         /* Pre-calculated values
894          */
895         int crack_animation_length;
896
897         IntervalLimiter profiler_interval;
898
899         /*
900          * TODO: Local caching of settings is not optimal and should at some stage
901          *       be updated to use a global settings object for getting thse values
902          *       (as opposed to the this local caching). This can be addressed in
903          *       a later release.
904          */
905         bool m_cache_doubletap_jump;
906         bool m_cache_enable_clouds;
907         bool m_cache_enable_joysticks;
908         bool m_cache_enable_particles;
909         bool m_cache_enable_fog;
910         bool m_cache_enable_noclip;
911         bool m_cache_enable_free_move;
912         f32  m_cache_mouse_sensitivity;
913         f32  m_cache_joystick_frustum_sensitivity;
914         f32  m_repeat_right_click_time;
915         f32  m_cache_cam_smoothing;
916         f32  m_cache_fog_start;
917
918         bool m_invert_mouse = false;
919         bool m_first_loop_after_window_activation = false;
920         bool m_camera_offset_changed = false;
921
922         bool m_does_lost_focus_pause_game = false;
923
924 #ifdef __ANDROID__
925         bool m_cache_hold_aux1;
926         bool m_android_chat_open;
927 #endif
928 };
929 extern Game *g_game;
930
931 void the_game(bool *kill,
932                 InputHandler *input,
933                 const GameStartData &start_data,
934                 std::string &error_message,
935                 ChatBackend &chat_backend,
936                 bool *reconnect_requested);