]> git.lizzy.rs Git - dragonfireclient.git/blobdiff - src/client/game.h
Merge branch 'master' of https://github.com/minetest/minetest
[dragonfireclient.git] / src / client / game.h
index d87e747c58a009f2ac550d4ce4a0b79d01a0821b..0e5d0550d296b156acd1652b7bfcf205197b5a95 100644 (file)
@@ -19,6 +19,59 @@ with this program; if not, write to the Free Software Foundation, Inc.,
 
 #pragma once
 
+#include <iomanip>
+#include <cmath>
+#include "client/renderingengine.h"
+#include "camera.h"
+#include "client.h"
+#include "client/clientevent.h"
+//#include "client/gameui.h"
+#include "client/inputhandler.h"
+#include "client/sound.h"
+#include "client/tile.h"     // For TextureSource
+#include "client/keys.h"
+#include "client/joystick_controller.h"
+#include "clientmap.h"
+#include "clouds.h"
+#include "config.h"
+#include "content_cao.h"
+#include "client/event_manager.h"
+#include "fontengine.h"
+#include "itemdef.h"
+#include "log.h"
+#include "filesys.h"
+#include "gettext.h"
+#include "gui/cheatMenu.h"
+#include "gui/guiChatConsole.h"
+#include "gui/guiConfirmRegistration.h"
+#include "gui/guiFormSpecMenu.h"
+#include "gui/guiKeyChangeMenu.h"
+#include "gui/guiPasswordChange.h"
+#include "gui/guiVolumeChange.h"
+#include "gui/mainmenumanager.h"
+#include "gui/profilergraph.h"
+#include "mapblock.h"
+#include "minimap.h"
+#include "nodedef.h"         // Needed for determining pointing to nodes
+#include "nodemetadata.h"
+#include "particles.h"
+#include "porting.h"
+#include "profiler.h"
+#include "raycast.h"
+#include "server.h"
+#include "settings.h"
+#include "shader.h"
+#include "sky.h"
+#include "translation.h"
+#include "util/basic_macros.h"
+#include "util/directiontables.h"
+#include "util/pointedthing.h"
+#include "util/quicktune_shortcutter.h"
+#include "irrlicht_changes/static_text.h"
+#include "irr_ptr.h"
+#include "version.h"
+#include "script/scripting_client.h"
+#include "hud.h"
 #include "irrlichttypes.h"
 #include <string>
 
@@ -43,6 +96,836 @@ struct CameraOrientation {
        f32 camera_pitch;  // "up/down"
 };
 
+/*
+       Text input system
+*/
+
+struct TextDestNodeMetadata : public TextDest
+{
+       TextDestNodeMetadata(v3s16 p, Client *client)
+       {
+               m_p = p;
+               m_client = client;
+       }
+       // This is deprecated I guess? -celeron55
+       void gotText(const std::wstring &text)
+       {
+               std::string ntext = wide_to_utf8(text);
+               infostream << "Submitting 'text' field of node at (" << m_p.X << ","
+                          << m_p.Y << "," << m_p.Z << "): " << ntext << std::endl;
+               StringMap fields;
+               fields["text"] = ntext;
+               m_client->sendNodemetaFields(m_p, "", fields);
+       }
+       void gotText(const StringMap &fields)
+       {
+               m_client->sendNodemetaFields(m_p, "", fields);
+       }
+
+       v3s16 m_p;
+       Client *m_client;
+};
+
+struct TextDestPlayerInventory : public TextDest
+{
+       TextDestPlayerInventory(Client *client)
+       {
+               m_client = client;
+               m_formname = "";
+       }
+       TextDestPlayerInventory(Client *client, const std::string &formname)
+       {
+               m_client = client;
+               m_formname = formname;
+       }
+       void gotText(const StringMap &fields)
+       {
+               m_client->sendInventoryFields(m_formname, fields);
+       }
+
+       Client *m_client;
+};
+
+struct LocalFormspecHandler : public TextDest
+{
+       LocalFormspecHandler(const std::string &formname)
+       {
+               m_formname = formname;
+       }
+
+       LocalFormspecHandler(const std::string &formname, Client *client):
+               m_client(client)
+       {
+               m_formname = formname;
+       }
+
+       void gotText(const StringMap &fields)
+       {
+               if (m_formname == "MT_PAUSE_MENU") {
+                       if (fields.find("btn_sound") != fields.end()) {
+                               g_gamecallback->changeVolume();
+                               return;
+                       }
+
+                       if (fields.find("btn_key_config") != fields.end()) {
+                               g_gamecallback->keyConfig();
+                               return;
+                       }
+
+                       if (fields.find("btn_exit_menu") != fields.end()) {
+                               g_gamecallback->disconnect();
+                               return;
+                       }
+
+                       if (fields.find("btn_exit_os") != fields.end()) {
+                               g_gamecallback->exitToOS();
+#ifndef __ANDROID__
+                               RenderingEngine::get_raw_device()->closeDevice();
+#endif
+                               return;
+                       }
+
+                       if (fields.find("btn_change_password") != fields.end()) {
+                               g_gamecallback->changePassword();
+                               return;
+                       }
+
+                       return;
+               }
+
+               if (m_formname == "MT_DEATH_SCREEN") {
+                       assert(m_client != 0);
+                       m_client->sendRespawn();
+                       return;
+               }
+
+               if (m_client->modsLoaded())
+                       m_client->getScript()->on_formspec_input(m_formname, fields);
+       }
+
+       Client *m_client = nullptr;
+};
+
+/* Form update callback */
+
+class NodeMetadataFormSource: public IFormSource
+{
+public:
+       NodeMetadataFormSource(ClientMap *map, v3s16 p):
+               m_map(map),
+               m_p(p)
+       {
+       }
+       const std::string &getForm() const
+       {
+               static const std::string empty_string = "";
+               NodeMetadata *meta = m_map->getNodeMetadata(m_p);
+
+               if (!meta)
+                       return empty_string;
+
+               return meta->getString("formspec");
+       }
+
+       virtual std::string resolveText(const std::string &str)
+       {
+               NodeMetadata *meta = m_map->getNodeMetadata(m_p);
+
+               if (!meta)
+                       return str;
+
+               return meta->resolveString(str);
+       }
+
+       ClientMap *m_map;
+       v3s16 m_p;
+};
+
+class PlayerInventoryFormSource: public IFormSource
+{
+public:
+       PlayerInventoryFormSource(Client *client):
+               m_client(client)
+       {
+       }
+
+       const std::string &getForm() const
+       {
+               LocalPlayer *player = m_client->getEnv().getLocalPlayer();
+               return player->inventory_formspec;
+       }
+
+       Client *m_client;
+};
+
+class NodeDugEvent: public MtEvent
+{
+public:
+       v3s16 p;
+       MapNode n;
+
+       NodeDugEvent(v3s16 p, MapNode n):
+               p(p),
+               n(n)
+       {}
+       MtEvent::Type getType() const
+       {
+               return MtEvent::NODE_DUG;
+       }
+};
+
+class SoundMaker
+{
+       ISoundManager *m_sound;
+       const NodeDefManager *m_ndef;
+public:
+       bool makes_footstep_sound;
+       float m_player_step_timer;
+       float m_player_jump_timer;
+
+       SimpleSoundSpec m_player_step_sound;
+       SimpleSoundSpec m_player_leftpunch_sound;
+       SimpleSoundSpec m_player_rightpunch_sound;
+
+       SoundMaker(ISoundManager *sound, const NodeDefManager *ndef):
+               m_sound(sound),
+               m_ndef(ndef),
+               makes_footstep_sound(true),
+               m_player_step_timer(0.0f),
+               m_player_jump_timer(0.0f)
+       {
+       }
+
+       void playPlayerStep()
+       {
+               if (m_player_step_timer <= 0 && m_player_step_sound.exists()) {
+                       m_player_step_timer = 0.03;
+                       if (makes_footstep_sound)
+                               m_sound->playSound(m_player_step_sound, false);
+               }
+       }
+
+       void playPlayerJump()
+       {
+               if (m_player_jump_timer <= 0.0f) {
+                       m_player_jump_timer = 0.2f;
+                       m_sound->playSound(SimpleSoundSpec("player_jump", 0.5f), false);
+               }
+       }
+
+       static void viewBobbingStep(MtEvent *e, void *data)
+       {
+               SoundMaker *sm = (SoundMaker *)data;
+               sm->playPlayerStep();
+       }
+
+       static void playerRegainGround(MtEvent *e, void *data)
+       {
+               SoundMaker *sm = (SoundMaker *)data;
+               sm->playPlayerStep();
+       }
+
+       static void playerJump(MtEvent *e, void *data)
+       {
+               SoundMaker *sm = (SoundMaker *)data;
+               sm->playPlayerJump();
+       }
+
+       static void cameraPunchLeft(MtEvent *e, void *data)
+       {
+               SoundMaker *sm = (SoundMaker *)data;
+               sm->m_sound->playSound(sm->m_player_leftpunch_sound, false);
+       }
+
+       static void cameraPunchRight(MtEvent *e, void *data)
+       {
+               SoundMaker *sm = (SoundMaker *)data;
+               sm->m_sound->playSound(sm->m_player_rightpunch_sound, false);
+       }
+
+       static void nodeDug(MtEvent *e, void *data)
+       {
+               SoundMaker *sm = (SoundMaker *)data;
+               NodeDugEvent *nde = (NodeDugEvent *)e;
+               sm->m_sound->playSound(sm->m_ndef->get(nde->n).sound_dug, false);
+       }
+
+       static void playerDamage(MtEvent *e, void *data)
+       {
+               SoundMaker *sm = (SoundMaker *)data;
+               sm->m_sound->playSound(SimpleSoundSpec("player_damage", 0.5), false);
+       }
+
+       static void playerFallingDamage(MtEvent *e, void *data)
+       {
+               SoundMaker *sm = (SoundMaker *)data;
+               sm->m_sound->playSound(SimpleSoundSpec("player_falling_damage", 0.5), false);
+       }
+
+       void registerReceiver(MtEventManager *mgr)
+       {
+               mgr->reg(MtEvent::VIEW_BOBBING_STEP, SoundMaker::viewBobbingStep, this);
+               mgr->reg(MtEvent::PLAYER_REGAIN_GROUND, SoundMaker::playerRegainGround, this);
+               mgr->reg(MtEvent::PLAYER_JUMP, SoundMaker::playerJump, this);
+               mgr->reg(MtEvent::CAMERA_PUNCH_LEFT, SoundMaker::cameraPunchLeft, this);
+               mgr->reg(MtEvent::CAMERA_PUNCH_RIGHT, SoundMaker::cameraPunchRight, this);
+               mgr->reg(MtEvent::NODE_DUG, SoundMaker::nodeDug, this);
+               mgr->reg(MtEvent::PLAYER_DAMAGE, SoundMaker::playerDamage, this);
+               mgr->reg(MtEvent::PLAYER_FALLING_DAMAGE, SoundMaker::playerFallingDamage, this);
+       }
+
+       void step(float dtime)
+       {
+               m_player_step_timer -= dtime;
+               m_player_jump_timer -= dtime;
+       }
+};
+
+// Locally stored sounds don't need to be preloaded because of this
+class GameOnDemandSoundFetcher: public OnDemandSoundFetcher
+{
+       std::set<std::string> m_fetched;
+private:
+       void paths_insert(std::set<std::string> &dst_paths,
+               const std::string &base,
+               const std::string &name)
+       {
+               dst_paths.insert(base + DIR_DELIM + "sounds" + DIR_DELIM + name + ".ogg");
+               dst_paths.insert(base + DIR_DELIM + "sounds" + DIR_DELIM + name + ".0.ogg");
+               dst_paths.insert(base + DIR_DELIM + "sounds" + DIR_DELIM + name + ".1.ogg");
+               dst_paths.insert(base + DIR_DELIM + "sounds" + DIR_DELIM + name + ".2.ogg");
+               dst_paths.insert(base + DIR_DELIM + "sounds" + DIR_DELIM + name + ".3.ogg");
+               dst_paths.insert(base + DIR_DELIM + "sounds" + DIR_DELIM + name + ".4.ogg");
+               dst_paths.insert(base + DIR_DELIM + "sounds" + DIR_DELIM + name + ".5.ogg");
+               dst_paths.insert(base + DIR_DELIM + "sounds" + DIR_DELIM + name + ".6.ogg");
+               dst_paths.insert(base + DIR_DELIM + "sounds" + DIR_DELIM + name + ".7.ogg");
+               dst_paths.insert(base + DIR_DELIM + "sounds" + DIR_DELIM + name + ".8.ogg");
+               dst_paths.insert(base + DIR_DELIM + "sounds" + DIR_DELIM + name + ".9.ogg");
+       }
+public:
+       void fetchSounds(const std::string &name,
+               std::set<std::string> &dst_paths,
+               std::set<std::string> &dst_datas)
+       {
+               if (m_fetched.count(name))
+                       return;
+
+               m_fetched.insert(name);
+
+               paths_insert(dst_paths, porting::path_share, name);
+               paths_insert(dst_paths, porting::path_user,  name);
+       }
+};
+
+
+typedef s32 SamplerLayer_t;
+
+
+class GameGlobalShaderConstantSetter : public IShaderConstantSetter
+{
+       Sky *m_sky;
+       bool *m_force_fog_off;
+       f32 *m_fog_range;
+       bool m_fog_enabled;
+       CachedPixelShaderSetting<float, 4> m_sky_bg_color;
+       CachedPixelShaderSetting<float> m_fog_distance;
+       CachedVertexShaderSetting<float> m_animation_timer_vertex;
+       CachedPixelShaderSetting<float> m_animation_timer_pixel;
+       CachedPixelShaderSetting<float, 3> m_day_light;
+       CachedPixelShaderSetting<float, 4> m_star_color;
+       CachedPixelShaderSetting<float, 3> m_eye_position_pixel;
+       CachedVertexShaderSetting<float, 3> m_eye_position_vertex;
+       CachedPixelShaderSetting<float, 3> m_minimap_yaw;
+       CachedPixelShaderSetting<float, 3> m_camera_offset_pixel;
+       CachedPixelShaderSetting<float, 3> m_camera_offset_vertex;
+       CachedPixelShaderSetting<SamplerLayer_t> m_base_texture;
+       CachedPixelShaderSetting<SamplerLayer_t> m_normal_texture;
+       Client *m_client;
+
+public:
+       void onSettingsChange(const std::string &name)
+       {
+               if (name == "enable_fog")
+                       m_fog_enabled = g_settings->getBool("enable_fog");
+       }
+
+       static void settingsCallback(const std::string &name, void *userdata)
+       {
+               reinterpret_cast<GameGlobalShaderConstantSetter*>(userdata)->onSettingsChange(name);
+       }
+
+       void setSky(Sky *sky) { m_sky = sky; }
+
+       GameGlobalShaderConstantSetter(Sky *sky, bool *force_fog_off,
+                       f32 *fog_range, Client *client) :
+               m_sky(sky),
+               m_force_fog_off(force_fog_off),
+               m_fog_range(fog_range),
+               m_sky_bg_color("skyBgColor"),
+               m_fog_distance("fogDistance"),
+               m_animation_timer_vertex("animationTimer"),
+               m_animation_timer_pixel("animationTimer"),
+               m_day_light("dayLight"),
+               m_star_color("starColor"),
+               m_eye_position_pixel("eyePosition"),
+               m_eye_position_vertex("eyePosition"),
+               m_minimap_yaw("yawVec"),
+               m_camera_offset_pixel("cameraOffset"),
+               m_camera_offset_vertex("cameraOffset"),
+               m_base_texture("baseTexture"),
+               m_normal_texture("normalTexture"),
+               m_client(client)
+       {
+               g_settings->registerChangedCallback("enable_fog", settingsCallback, this);
+               m_fog_enabled = g_settings->getBool("enable_fog");
+       }
+
+       ~GameGlobalShaderConstantSetter()
+       {
+               g_settings->deregisterChangedCallback("enable_fog", settingsCallback, this);
+       }
+
+       void onSetConstants(video::IMaterialRendererServices *services) override
+       {
+               // Background color
+               video::SColor bgcolor = m_sky->getBgColor();
+               video::SColorf bgcolorf(bgcolor);
+               float bgcolorfa[4] = {
+                       bgcolorf.r,
+                       bgcolorf.g,
+                       bgcolorf.b,
+                       bgcolorf.a,
+               };
+               m_sky_bg_color.set(bgcolorfa, services);
+
+               // Fog distance
+               float fog_distance = 10000 * BS;
+
+               if (m_fog_enabled && !*m_force_fog_off)
+                       fog_distance = *m_fog_range;
+
+               m_fog_distance.set(&fog_distance, services);
+
+               u32 daynight_ratio = (float)m_client->getEnv().getDayNightRatio();
+               video::SColorf sunlight;
+               get_sunlight_color(&sunlight, daynight_ratio);
+               float dnc[3] = {
+                       sunlight.r,
+                       sunlight.g,
+                       sunlight.b };
+               m_day_light.set(dnc, services);
+
+               video::SColorf star_color = m_sky->getCurrentStarColor();
+               float clr[4] = {star_color.r, star_color.g, star_color.b, star_color.a};
+               m_star_color.set(clr, services);
+
+               u32 animation_timer = porting::getTimeMs() % 1000000;
+               float animation_timer_f = (float)animation_timer / 100000.f;
+               m_animation_timer_vertex.set(&animation_timer_f, services);
+               m_animation_timer_pixel.set(&animation_timer_f, services);
+
+               float eye_position_array[3];
+               v3f epos = m_client->getEnv().getLocalPlayer()->getEyePosition();
+               epos.getAs3Values(eye_position_array);
+               m_eye_position_pixel.set(eye_position_array, services);
+               m_eye_position_vertex.set(eye_position_array, services);
+
+               if (m_client->getMinimap()) {
+                       float minimap_yaw_array[3];
+                       v3f minimap_yaw = m_client->getMinimap()->getYawVec();
+                       minimap_yaw.getAs3Values(minimap_yaw_array);
+                       m_minimap_yaw.set(minimap_yaw_array, services);
+               }
+
+               float camera_offset_array[3];
+               v3f offset = intToFloat(m_client->getCamera()->getOffset(), BS);
+               offset.getAs3Values(camera_offset_array);
+               m_camera_offset_pixel.set(camera_offset_array, services);
+               m_camera_offset_vertex.set(camera_offset_array, services);
+
+               SamplerLayer_t base_tex = 0, normal_tex = 1;
+               m_base_texture.set(&base_tex, services);
+               m_normal_texture.set(&normal_tex, services);
+       }
+};
+
+
+class GameGlobalShaderConstantSetterFactory : public IShaderConstantSetterFactory
+{
+       Sky *m_sky;
+       bool *m_force_fog_off;
+       f32 *m_fog_range;
+       Client *m_client;
+       std::vector<GameGlobalShaderConstantSetter *> created_nosky;
+public:
+       GameGlobalShaderConstantSetterFactory(bool *force_fog_off,
+                       f32 *fog_range, Client *client) :
+               m_sky(NULL),
+               m_force_fog_off(force_fog_off),
+               m_fog_range(fog_range),
+               m_client(client)
+       {}
+
+       void setSky(Sky *sky) {
+               m_sky = sky;
+               for (GameGlobalShaderConstantSetter *ggscs : created_nosky) {
+                       ggscs->setSky(m_sky);
+               }
+               created_nosky.clear();
+       }
+
+       virtual IShaderConstantSetter* create()
+       {
+               auto *scs = new GameGlobalShaderConstantSetter(
+                               m_sky, m_force_fog_off, m_fog_range, m_client);
+               if (!m_sky)
+                       created_nosky.push_back(scs);
+               return scs;
+       }
+};
+
+#ifdef HAVE_TOUCHSCREENGUI
+#define SIZE_TAG "size[11,5.5]"
+#else
+#define SIZE_TAG "size[11,5.5,true]" // Fixed size on desktop
+#endif
+
+/****************************************************************************
+ ****************************************************************************/
+
+const float object_hit_delay = 0.2;
+
+struct FpsControl {
+       FpsControl() : last_time(0), busy_time(0), sleep_time(0) {}
+
+       void reset();
+
+       void limit(IrrlichtDevice *device, f32 *dtime);
+
+       u32 getBusyMs() const { return busy_time / 1000; }
+
+       // all values in microseconds (us)
+       u64 last_time, busy_time, sleep_time;
+};
+
+
+/* The reason the following structs are not anonymous structs within the
+ * class is that they are not used by the majority of member functions and
+ * many functions that do require objects of thse types do not modify them
+ * (so they can be passed as a const qualified parameter)
+ */
+
+struct GameRunData {
+       u16 dig_index;
+       u16 new_playeritem;
+       PointedThing pointed_old;
+       bool digging;
+       bool punching;
+       bool btn_down_for_dig;
+       bool dig_instantly;
+       bool digging_blocked;
+       bool reset_jump_timer;
+       float nodig_delay_timer;
+       float dig_time;
+       float dig_time_complete;
+       float repeat_place_timer;
+       float object_hit_delay_timer;
+       float time_from_last_punch;
+       ClientActiveObject *selected_object;
+
+       float jump_timer;
+       float damage_flash;
+       float update_draw_list_timer;
+
+       f32 fog_range;
+
+       v3f update_draw_list_last_cam_dir;
+
+       float time_of_day_smooth;
+};
+
+class Game;
+
+struct ClientEventHandler
+{
+       void (Game::*handler)(ClientEvent *, CameraOrientation *);
+};
+
+using PausedNodesList = std::vector<std::pair<irr_ptr<scene::IAnimatedMeshSceneNode>, float>>;
+
+class Game {
+public:
+       Game();
+       ~Game();
+
+       bool startup(bool *kill,
+                       InputHandler *input,
+                       RenderingEngine *rendering_engine,
+                       const GameStartData &game_params,
+                       std::string &error_message,
+                       bool *reconnect,
+                       ChatBackend *chat_backend);
+
+
+       void run();
+       void shutdown();
+
+       // Basic initialisation
+       bool init(const std::string &map_dir, const std::string &address,
+                       u16 port, const SubgameSpec &gamespec);
+       bool initSound();
+       bool createSingleplayerServer(const std::string &map_dir,
+                       const SubgameSpec &gamespec, u16 port);
+
+       // Client creation
+       bool createClient(const GameStartData &start_data);
+       bool initGui();
+
+       // Client connection
+       bool connectToServer(const GameStartData &start_data,
+                       bool *connect_ok, bool *aborted);
+       bool getServerContent(bool *aborted);
+
+       // Main loop
+
+       void updateInteractTimers(f32 dtime);
+       bool checkConnection();
+       bool handleCallbacks();
+       void processQueues();
+       void updateProfilers(const RunStats &stats, const FpsControl &draw_times, f32 dtime);
+       void updateDebugState();
+       void updateStats(RunStats *stats, const FpsControl &draw_times, f32 dtime);
+       void updateProfilerGraphs(ProfilerGraph *graph);
+
+       // Input related
+       void processUserInput(f32 dtime);
+       void processKeyInput();
+       void processItemSelection(u16 *new_playeritem);
+
+       void dropSelectedItem(bool single_item = false);
+       void openInventory();
+       void openEnderchest();
+       void openConsole(float scale, const wchar_t *line=NULL);
+       void toggleFreeMove();
+       void toggleFreeMoveAlt();
+       void togglePitchMove();
+       void toggleFast();
+       void toggleNoClip();
+       void toggleKillaura();
+       void toggleFreecam();
+       void toggleScaffold();
+       void toggleNextItem();
+       void toggleCinematic();
+       void toggleBlockBounds();
+       void toggleAutoforward();
+
+       void toggleMinimap(bool shift_pressed);
+       void toggleFog();
+       void toggleDebug();
+       void toggleUpdateCamera();
+       void updatePlayerCAOVisibility();
+
+       void increaseViewRange();
+       void decreaseViewRange();
+       void toggleFullViewRange();
+       void checkZoomEnabled();
+
+       void updateCameraDirection(CameraOrientation *cam, float dtime);
+       void updateCameraOrientation(CameraOrientation *cam, float dtime);
+       void updatePlayerControl(const CameraOrientation &cam);
+       void step(f32 *dtime);
+       void processClientEvents(CameraOrientation *cam);
+       void updateCamera(f32 dtime);
+       void updateSound(f32 dtime);
+       void processPlayerInteraction(f32 dtime, bool show_hud);
+       /*!
+        * Returns the object or node the player is pointing at.
+        * Also updates the selected thing in the Hud.
+        *
+        * @param[in]  shootline         the shootline, starting from
+        * the camera position. This also gives the maximal distance
+        * of the search.
+        * @param[in]  liquids_pointable if false, liquids are ignored
+        * @param[in]  look_for_object   if false, objects are ignored
+        * @param[in]  camera_offset     offset of the camera
+        * @param[out] selected_object   the selected object or
+        * NULL if not found
+        */
+       PointedThing updatePointedThing(
+                       const core::line3d<f32> &shootline, bool liquids_pointable,
+                       bool look_for_object, const v3s16 &camera_offset);
+       void handlePointingAtNothing(const ItemStack &playerItem);
+       void handlePointingAtNode(const PointedThing &pointed,
+                       const ItemStack &selected_item, const ItemStack &hand_item, f32 dtime);
+       void handlePointingAtObject(const PointedThing &pointed, const ItemStack &playeritem,
+                       const v3f &player_position, bool show_debug);
+       void handleDigging(const PointedThing &pointed, const v3s16 &nodepos,
+                       const ItemStack &selected_item, const ItemStack &hand_item, f32 dtime);
+       void updateFrame(ProfilerGraph *graph, RunStats *stats, f32 dtime,
+                       const CameraOrientation &cam);
+       void updateShadows();
+
+       // Misc
+       void showOverlayMessage(const char *msg, float dtime, int percent,
+                       bool draw_clouds = true);
+
+       static void freecamChangedCallback(const std::string &setting_name, void *data);
+       static void settingChangedCallback(const std::string &setting_name, void *data);
+       static void updateAllMapBlocksCallback(const std::string &setting_name, void *data);
+       void readSettings();
+
+       bool isKeyDown(GameKeyType k);
+       bool wasKeyDown(GameKeyType k);
+       bool wasKeyPressed(GameKeyType k);
+       bool wasKeyReleased(GameKeyType k);
+
+#ifdef __ANDROID__
+       void handleAndroidChatInput();
+#endif
+
+       struct Flags {
+               bool force_fog_off = false;
+               bool disable_camera_update = false;
+       };
+
+       void showDeathFormspec();
+       void showPauseMenu();
+
+       void pauseAnimation();
+       void resumeAnimation();
+
+       // ClientEvent handlers
+       void handleClientEvent_None(ClientEvent *event, CameraOrientation *cam);
+       void handleClientEvent_PlayerDamage(ClientEvent *event, CameraOrientation *cam);
+       void handleClientEvent_PlayerForceMove(ClientEvent *event, CameraOrientation *cam);
+       void handleClientEvent_Deathscreen(ClientEvent *event, CameraOrientation *cam);
+       void handleClientEvent_ShowFormSpec(ClientEvent *event, CameraOrientation *cam);
+       void handleClientEvent_ShowLocalFormSpec(ClientEvent *event, CameraOrientation *cam);
+       void handleClientEvent_HandleParticleEvent(ClientEvent *event,
+               CameraOrientation *cam);
+       void handleClientEvent_HudAdd(ClientEvent *event, CameraOrientation *cam);
+       void handleClientEvent_HudRemove(ClientEvent *event, CameraOrientation *cam);
+       void handleClientEvent_HudChange(ClientEvent *event, CameraOrientation *cam);
+       void handleClientEvent_SetSky(ClientEvent *event, CameraOrientation *cam);
+       void handleClientEvent_SetSun(ClientEvent *event, CameraOrientation *cam);
+       void handleClientEvent_SetMoon(ClientEvent *event, CameraOrientation *cam);
+       void handleClientEvent_SetStars(ClientEvent *event, CameraOrientation *cam);
+       void handleClientEvent_OverrideDayNigthRatio(ClientEvent *event,
+               CameraOrientation *cam);
+       void handleClientEvent_CloudParams(ClientEvent *event, CameraOrientation *cam);
+
+       void updateChat(f32 dtime);
+
+       bool nodePlacement(const ItemDefinition &selected_def, const ItemStack &selected_item,
+               const v3s16 &nodepos, const v3s16 &neighbourpos, const PointedThing &pointed,
+               const NodeMetadata *meta, bool force = false);
+       static const ClientEventHandler clientEventHandler[CLIENTEVENT_MAX];
+
+       f32 getSensitivityScaleFactor() const;
+
+       InputHandler *input = nullptr;
+
+       Client *client = nullptr;
+       Server *server = nullptr;
+
+       IWritableTextureSource *texture_src = nullptr;
+       IWritableShaderSource *shader_src = nullptr;
+
+       // When created, these will be filled with data received from the server
+       IWritableItemDefManager *itemdef_manager = nullptr;
+       NodeDefManager *nodedef_manager = nullptr;
+
+       GameOnDemandSoundFetcher soundfetcher; // useful when testing
+       ISoundManager *sound = nullptr;
+       bool sound_is_dummy = false;
+       SoundMaker *soundmaker = nullptr;
+
+       ChatBackend *chat_backend = nullptr;
+       LogOutputBuffer m_chat_log_buf;
+
+       EventManager *eventmgr = nullptr;
+       QuicktuneShortcutter *quicktune = nullptr;
+       bool registration_confirmation_shown = false;
+
+       std::unique_ptr<GameUI> m_game_ui;
+       GUIChatConsole *gui_chat_console = nullptr; // Free using ->Drop()
+       CheatMenu *m_cheat_menu = nullptr;
+       MapDrawControl *draw_control = nullptr;
+       Camera *camera = nullptr;
+       Clouds *clouds = nullptr;                         // Free using ->Drop()
+       Sky *sky = nullptr;                         // Free using ->Drop()
+       Hud *hud = nullptr;
+       Minimap *mapper = nullptr;
+
+       // Map server hud ids to client hud ids
+       std::unordered_map<u32, u32> m_hud_server_to_client;
+
+       GameRunData runData;
+       Flags m_flags;
+
+       /* 'cache'
+          This class does take ownership/responsibily for cleaning up etc of any of
+          these items (e.g. device)
+       */
+       IrrlichtDevice *device;
+       RenderingEngine *m_rendering_engine;
+       video::IVideoDriver *driver;
+       scene::ISceneManager *smgr;
+       bool *kill;
+       std::string *error_message;
+       bool *reconnect_requested;
+       scene::ISceneNode *skybox;
+       PausedNodesList paused_animated_nodes;
+
+       bool simple_singleplayer_mode;
+       /* End 'cache' */
+
+       /* Pre-calculated values
+        */
+       int crack_animation_length;
+
+       IntervalLimiter profiler_interval;
+
+       /*
+        * TODO: Local caching of settings is not optimal and should at some stage
+        *       be updated to use a global settings object for getting thse values
+        *       (as opposed to the this local caching). This can be addressed in
+        *       a later release.
+        */
+       bool m_cache_doubletap_jump;
+       bool m_cache_enable_clouds;
+       bool m_cache_enable_joysticks;
+       bool m_cache_enable_particles;
+       bool m_cache_enable_fog;
+       bool m_cache_enable_noclip;
+       bool m_cache_enable_free_move;
+       f32  m_cache_mouse_sensitivity;
+       f32  m_cache_joystick_frustum_sensitivity;
+       f32  m_repeat_place_time;
+       f32  m_cache_cam_smoothing;
+       f32  m_cache_fog_start;
+
+       bool m_invert_mouse = false;
+       bool m_first_loop_after_window_activation = false;
+       bool m_camera_offset_changed = false;
+
+       bool m_does_lost_focus_pause_game = false;
+
+       CameraOrientation cam_view_target = {}; // added by dragonfireclient
+       CameraOrientation cam_view  = {};       // added by dragonfireclient
+
+#if IRRLICHT_VERSION_MT_REVISION < 5
+       int m_reset_HW_buffer_counter = 0;
+#endif
+
+#ifdef HAVE_TOUCHSCREENGUI
+       bool m_cache_hold_aux1;
+#endif
+#ifdef __ANDROID__
+       bool m_android_chat_open;
+#endif
+};
+extern Game *g_game;
 
 void the_game(bool *kill,
                InputHandler *input,