/* Minetest Copyright (C) 2013 celeron55, Perttu Ahola This program is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #pragma once #include #include #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 "version.h" #include "script/scripting_client.h" #include "hud.h" #include "irrlichttypes.h" #include class InputHandler; class ChatBackend; /* to avoid having to include chat.h */ struct SubgameSpec; struct GameStartData; struct Jitter { f32 max, min, avg, counter, max_sample, min_sample, max_fraction; }; struct RunStats { u32 drawtime; Jitter dtime_jitter, busy_time_jitter; }; struct CameraOrientation { f32 camera_yaw; // "right/left" 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 m_fetched; private: void paths_insert(std::set &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 &dst_paths, std::set &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); } }; // before 1.8 there isn't a "integer interface", only float #if (IRRLICHT_VERSION_MAJOR == 1 && IRRLICHT_VERSION_MINOR < 8) typedef f32 SamplerLayer_t; #else typedef s32 SamplerLayer_t; #endif class GameGlobalShaderConstantSetter : public IShaderConstantSetter { Sky *m_sky; bool *m_force_fog_off; f32 *m_fog_range; bool m_fog_enabled; CachedPixelShaderSetting m_sky_bg_color; CachedPixelShaderSetting m_fog_distance; CachedVertexShaderSetting m_animation_timer_vertex; CachedPixelShaderSetting m_animation_timer_pixel; CachedPixelShaderSetting m_day_light; CachedPixelShaderSetting m_star_color; CachedPixelShaderSetting m_eye_position_pixel; CachedVertexShaderSetting m_eye_position_vertex; CachedPixelShaderSetting m_minimap_yaw; CachedPixelShaderSetting m_camera_offset_pixel; CachedPixelShaderSetting m_camera_offset_vertex; CachedPixelShaderSetting m_base_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(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_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(); #if (IRRLICHT_VERSION_MAJOR == 1 && IRRLICHT_VERSION_MINOR < 8) eye_position_array[0] = epos.X; eye_position_array[1] = epos.Y; eye_position_array[2] = epos.Z; #else epos.getAs3Values(eye_position_array); #endif 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(); #if (IRRLICHT_VERSION_MAJOR == 1 && IRRLICHT_VERSION_MINOR < 8) minimap_yaw_array[0] = minimap_yaw.X; minimap_yaw_array[1] = minimap_yaw.Y; minimap_yaw_array[2] = minimap_yaw.Z; #else minimap_yaw.getAs3Values(minimap_yaw_array); #endif m_minimap_yaw.set(minimap_yaw_array, services); } float camera_offset_array[3]; v3f offset = intToFloat(m_client->getCamera()->getOffset(), BS); #if (IRRLICHT_VERSION_MAJOR == 1 && IRRLICHT_VERSION_MINOR < 8) camera_offset_array[0] = offset.X; camera_offset_array[1] = offset.Y; camera_offset_array[2] = offset.Z; #else offset.getAs3Values(camera_offset_array); #endif m_camera_offset_pixel.set(camera_offset_array, services); m_camera_offset_vertex.set(camera_offset_array, services); SamplerLayer_t base_tex = 0; m_base_texture.set(&base_tex, services); } }; class GameGlobalShaderConstantSetterFactory : public IShaderConstantSetterFactory { Sky *m_sky; bool *m_force_fog_off; f32 *m_fog_range; Client *m_client; std::vector 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 __ANDROID__ #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 { u32 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 *); }; class Game { public: Game(); ~Game(); bool startup(bool *kill, InputHandler *input, const GameStartData &game_params, std::string &error_message, bool *reconnect, ChatBackend *chat_backend); void run(); void shutdown(); void extendedResourceCleanup(); // 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 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 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(u32 busy_time, f32 dtime); void updateSound(f32 dtime); void processPlayerInteraction(f32 dtime, bool show_hud, bool show_debug); /*! * 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 &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); // Misc void limitFps(FpsControl *fps_timings, f32 *dtime); 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(); // 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, const v2u32 &screensize); bool nodePlacement(const ItemDefinition &selected_def, const ItemStack &selected_item, const v3s16 &nodepos, const v3s16 &neighbourpos, const PointedThing &pointed, const NodeMetadata *meta); static const ClientEventHandler clientEventHandler[CLIENTEVENT_MAX]; 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 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; 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; video::IVideoDriver *driver; scene::ISceneManager *smgr; bool *kill; std::string *error_message; bool *reconnect_requested; scene::ISceneNode *skybox; 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 = { 0 }; CameraOrientation cam_view = { 0 }; int m_reset_HW_buffer_counter = 0; #ifdef __ANDROID__ bool m_cache_hold_aux1; bool m_android_chat_open; #endif }; extern Game *g_game; void the_game(bool *kill, InputHandler *input, const GameStartData &start_data, std::string &error_message, ChatBackend &chat_backend, bool *reconnect_requested);