diff options
Diffstat (limited to 'src/client/game.h')
-rw-r--r-- | src/client/game.h | 883 |
1 files changed, 883 insertions, 0 deletions
diff --git a/src/client/game.h b/src/client/game.h index d87e747c5..0e5d0550d 100644 --- a/src/client/game.h +++ b/src/client/game.h @@ -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, |