#else
#include "client/sound.h"
#endif
-/*
- 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 static 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 *);
-};
-
-/****************************************************************************
- THE GAME
- ****************************************************************************/
-
-using PausedNodesList = std::vector<std::pair<irr_ptr<scene::IAnimatedMeshSceneNode>, float>>;
-
-/* This is not intended to be a public class. If a public class becomes
- * desirable then it may be better to create another 'wrapper' class that
- * hides most of the stuff in this class (nothing in this class is required
- * by any other file) but exposes the public methods/data only.
- */
-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();
-
-protected:
-
- // 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 openConsole(float scale, const wchar_t *line=NULL);
- void toggleFreeMove();
- void toggleFreeMoveAlt();
- void togglePitchMove();
- void toggleFast();
- void toggleNoClip();
- void toggleCinematic();
- void toggleBlockBounds();
- void toggleAutoforward();
-
- void toggleMinimap(bool shift_pressed);
- void toggleFog();
- void toggleDebug();
- void toggleUpdateCamera();
-
- 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 settingChangedCallback(const std::string &setting_name, void *data);
- void readSettings();
-
- inline bool isKeyDown(GameKeyType k)
- {
- return input->isKeyDown(k);
- }
- inline bool wasKeyDown(GameKeyType k)
- {
- return input->wasKeyDown(k);
- }
- inline bool wasKeyPressed(GameKeyType k)
- {
- return input->wasKeyPressed(k);
- }
- inline bool wasKeyReleased(GameKeyType k)
- {
- return input->wasKeyReleased(k);
- }
-
-#ifdef __ANDROID__
- void handleAndroidChatInput();
-#endif
-
-private:
- 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);
- 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()
- 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;
-
-#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
-};
Game::Game() :
m_chat_log_buf(g_logger),
&settingChangedCallback, this);
g_settings->registerChangedCallback("camera_smoothing",
&settingChangedCallback, this);
+ g_settings->registerChangedCallback("freecam",
+ &freecamChangedCallback, this);
+ g_settings->registerChangedCallback("xray",
+ &updateAllMapBlocksCallback, this);
+ g_settings->registerChangedCallback("xray_nodes",
+ &updateAllMapBlocksCallback, this);
+ g_settings->registerChangedCallback("fullbright",
+ &updateAllMapBlocksCallback, this);
+ g_settings->registerChangedCallback("node_esp_nodes",
+ &updateAllMapBlocksCallback, this);
readSettings();
&settingChangedCallback, this);
g_settings->deregisterChangedCallback("camera_smoothing",
&settingChangedCallback, this);
+ g_settings->deregisterChangedCallback("freecam",
+ &freecamChangedCallback, this);
+ g_settings->deregisterChangedCallback("xray",
+ &updateAllMapBlocksCallback, this);
+ g_settings->deregisterChangedCallback("xray_nodes",
+ &updateAllMapBlocksCallback, this);
+ g_settings->deregisterChangedCallback("fullbright",
+ &updateAllMapBlocksCallback, this);
+ g_settings->deregisterChangedCallback("node_esp_nodes",
+ &updateAllMapBlocksCallback, this);
}
bool Game::startup(bool *kill,
{
ProfilerGraph graph;
RunStats stats = {};
- CameraOrientation cam_view_target = {};
- CameraOrientation cam_view = {};
FpsControl draw_times;
f32 dtime; // in seconds
if (gui_chat_console)
gui_chat_console->drop();
+ if (m_cheat_menu)
+ delete m_cheat_menu;
+
if (sky)
sky->drop();
delete[] text;
}
str += L" [";
- str += driver->getName();
+ str += L"Minetest Hackclient";
str += L"]";
device->setWindowCaption(str.c_str());
gui_chat_console = new GUIChatConsole(guienv, guienv->getRootGUIElement(),
-1, chat_backend, client, &g_menumgr);
+ if (!gui_chat_console) {
+ *error_message = "Could not allocate memory for chat console";
+ errorstream << *error_message << std::endl;
+ return false;
+ }
+
+ m_cheat_menu = new CheatMenu(client);
+
+ if (!m_cheat_menu) {
+ *error_message = "Could not allocate memory for cheat menu";
+ errorstream << *error_message << std::endl;
+ return false;
+ }
+
#ifdef HAVE_TOUCHSCREENGUI
if (g_touchscreengui)
void Game::processKeyInput()
{
+ if (wasKeyDown(KeyType::SELECT_UP)) {
+ m_cheat_menu->selectUp();
+ } else if (wasKeyDown(KeyType::SELECT_DOWN)) {
+ m_cheat_menu->selectDown();
+ } else if (wasKeyDown(KeyType::SELECT_LEFT)) {
+ m_cheat_menu->selectLeft();
+ } else if (wasKeyDown(KeyType::SELECT_RIGHT)) {
+ m_cheat_menu->selectRight();
+ } else if (wasKeyDown(KeyType::SELECT_CONFIRM)) {
+ m_cheat_menu->selectConfirm();
+ }
+
if (wasKeyDown(KeyType::DROP)) {
dropSelectedItem(isKeyDown(KeyType::SNEAK));
} else if (wasKeyDown(KeyType::AUTOFORWARD)) {
toggleAutoforward();
} else if (wasKeyDown(KeyType::INVENTORY)) {
openInventory();
+ } else if (wasKeyDown(KeyType::ENDERCHEST)) {
+ openEnderchest();
} else if (input->cancelPressed()) {
#ifdef __ANDROID__
m_android_chat_open = false;
toggleFast();
} else if (wasKeyDown(KeyType::NOCLIP)) {
toggleNoClip();
+ } else if (wasKeyDown(KeyType::KILLAURA)) {
+ toggleKillaura();
+ } else if (wasKeyDown(KeyType::FREECAM)) {
+ toggleFreecam();
+ } else if (wasKeyDown(KeyType::SCAFFOLD)) {
+ toggleScaffold();
#if USE_SOUND
} else if (wasKeyDown(KeyType::MUTE)) {
if (g_settings->getBool("enable_sound")) {
m_game_ui->toggleChat();
} else if (wasKeyDown(KeyType::TOGGLE_FOG)) {
toggleFog();
+ } else if (wasKeyDown(KeyType::TOGGLE_CHEAT_MENU)) {
+ m_game_ui->toggleCheatMenu();
} else if (wasKeyDown(KeyType::TOGGLE_UPDATE_CAMERA)) {
toggleUpdateCamera();
} else if (wasKeyDown(KeyType::TOGGLE_DEBUG)) {
formspec->setFormSpec(fs_src->getForm(), inventoryloc);
}
+void Game::openEnderchest()
+{
+ LocalPlayer *player = client->getEnv().getLocalPlayer();
+ if (!player || !player->getCAO())
+ return;
+
+ infostream << "Game: Launching special inventory" << std::endl;
+
+ if (client->modsLoaded())
+ client->getScript()->open_enderchest();
+}
+
void Game::openConsole(float scale, const wchar_t *line)
{
}
}
+void Game::toggleKillaura()
+{
+ bool killaura = ! g_settings->getBool("killaura");
+ g_settings->set("killaura", bool_to_cstr(killaura));
+
+ if (killaura) {
+ m_game_ui->showTranslatedStatusText("Killaura enabled");
+ } else {
+ m_game_ui->showTranslatedStatusText("Killaura disabled");
+ }
+}
+
+void Game::toggleFreecam()
+{
+ bool freecam = ! g_settings->getBool("freecam");
+ g_settings->set("freecam", bool_to_cstr(freecam));
+
+ if (freecam) {
+ m_game_ui->showTranslatedStatusText("Freecam enabled");
+ } else {
+ m_game_ui->showTranslatedStatusText("Freecam disabled");
+ }
+}
+
+void Game::toggleScaffold()
+{
+ bool scaffold = ! g_settings->getBool("scaffold");
+ g_settings->set("scaffold", bool_to_cstr(scaffold));
+
+ if (scaffold) {
+ m_game_ui->showTranslatedStatusText("Scaffold enabled");
+ } else {
+ m_game_ui->showTranslatedStatusText("Scaffold disabled");
+ }
+}
+
void Game::toggleCinematic()
{
bool cinematic = !g_settings->getBool("cinematic");
void Game::toggleUpdateCamera()
{
+ if (g_settings->getBool("freecam"))
+ return;
m_flags.disable_camera_update = !m_flags.disable_camera_update;
if (m_flags.disable_camera_update)
m_game_ui->showTranslatedStatusText("Camera update disabled");
LocalPlayer *player = client->getEnv().getLocalPlayer();
f32 hp_max = player->getCAO() ?
- player->getCAO()->getProperties().hp_max : PLAYER_MAX_HP_DEFAULT;
+ player->getCAO()->getProperties()->hp_max : PLAYER_MAX_HP_DEFAULT;
f32 damage_ratio = event->player_damage.amount / hp_max;
runData.damage_flash += 95.0f + 64.f * damage_ratio;
void Game::handleClientEvent_ShowLocalFormSpec(ClientEvent *event, CameraOrientation *cam)
{
- FormspecFormSource *fs_src = new FormspecFormSource(*event->show_formspec.formspec);
- LocalFormspecHandler *txt_dst =
- new LocalFormspecHandler(*event->show_formspec.formname, client);
- GUIFormSpecMenu::create(m_game_ui->getFormspecGUI(), client, m_rendering_engine->get_gui_env(),
- &input->joystick, fs_src, txt_dst, client->getFormspecPrepend(), sound);
+ if (event->show_formspec.formspec->empty()) {
+ auto formspec = m_game_ui->getFormspecGUI();
+ if (formspec && (event->show_formspec.formname->empty()
+ || *(event->show_formspec.formname) == m_game_ui->getFormspecName())) {
+ formspec->quitMenu();
+ }
+ } else {
+ FormspecFormSource *fs_src = new FormspecFormSource(*event->show_formspec.formspec);
+ LocalFormspecHandler *txt_dst =
+ new LocalFormspecHandler(*event->show_formspec.formname, client);
+ GUIFormSpecMenu::create(m_game_ui->getFormspecGUI(), client, m_rendering_engine->get_gui_env(), &input->joystick,
+ fs_src, txt_dst, client->getFormspecPrepend(), sound);
+ }
delete event->show_formspec.formspec;
delete event->show_formspec.formname;
v3s16 old_camera_offset = camera->getOffset();
- if (wasKeyDown(KeyType::CAMERA_MODE)) {
- GenericCAO *playercao = player->getCAO();
-
- // If playercao not loaded, don't change camera
- if (!playercao)
- return;
-
+ if (wasKeyDown(KeyType::CAMERA_MODE) && ! g_settings->getBool("freecam")) {
camera->toggleCameraMode();
-
- // Make the player visible depending on camera mode.
- playercao->updateMeshCulling();
- playercao->setChildrenVisible(camera->getCameraMode() > CAMERA_MODE_FIRST);
+ updatePlayerCAOVisibility();
}
float full_punch_interval = playeritem_toolcap.full_punch_interval;
}
}
+void Game::updatePlayerCAOVisibility()
+{
+ // Make the player visible depending on camera mode.
+ LocalPlayer *player = client->getEnv().getLocalPlayer();
+ GenericCAO *playercao = player->getCAO();
+ if (!playercao)
+ return;
+ playercao->updateMeshCulling();
+ bool is_visible = camera->getCameraMode() > CAMERA_MODE_FIRST || g_settings->getBool("freecam");
+ playercao->setChildrenVisible(is_visible);
+}
void Game::updateSound(f32 dtime)
{
const ItemDefinition &selected_def = selected_item.getDefinition(itemdef_manager);
f32 d = getToolRange(selected_def, hand_item.getDefinition(itemdef_manager));
+
+ if (g_settings->getBool("reach"))
+ d += g_settings->getU16("tool_range");
+
core::line3d<f32> shootline;
switch (camera->getCameraMode()) {
soundmaker->m_player_leftpunch_sound.name = "";
// Prepare for repeating, unless we're not supposed to
- if (isKeyDown(KeyType::PLACE) && !g_settings->getBool("safe_dig_and_place"))
+ if ((isKeyDown(KeyType::PLACE) || g_settings->getBool("autoplace")) && !g_settings->getBool("safe_dig_and_place"))
runData.repeat_place_timer += dtime;
else
runData.repeat_place_timer = 0;
runData.selected_object = NULL;
hud->pointing_at_object = false;
-
- RaycastState s(shootline, look_for_object, liquids_pointable);
+ RaycastState s(shootline, look_for_object, liquids_pointable, ! g_settings->getBool("dont_point_nodes"));
PointedThing result;
env.continueRaycast(&s, &result);
if (result.type == POINTEDTHING_OBJECT) {
return result;
}
-
void Game::handlePointingAtNothing(const ItemStack &playerItem)
{
infostream << "Attempted to place item while pointing at nothing" << std::endl;
ClientMap &map = client->getEnv().getClientMap();
- if (runData.nodig_delay_timer <= 0.0 && isKeyDown(KeyType::DIG)
+ if (((runData.nodig_delay_timer <= 0.0 || g_settings->getBool("fastdig")) && (isKeyDown(KeyType::DIG) || g_settings->getBool("autodig"))
&& !runData.digging_blocked
- && client->checkPrivilege("interact")) {
+ && client->checkPrivilege("interact"))
+ ) {
handleDigging(pointed, nodepos, selected_item, hand_item, dtime);
}
}
if ((wasKeyPressed(KeyType::PLACE) ||
- runData.repeat_place_timer >= m_repeat_place_time) &&
+ (runData.repeat_place_timer >= (g_settings->getBool("fastplace") ? 0.001 : m_repeat_place_time))) &&
client->checkPrivilege("interact")) {
runData.repeat_place_timer = 0;
infostream << "Place button pressed while looking at ground" << std::endl;
bool Game::nodePlacement(const ItemDefinition &selected_def,
const ItemStack &selected_item, const v3s16 &nodepos, const v3s16 &neighbourpos,
- const PointedThing &pointed, const NodeMetadata *meta)
+ const PointedThing &pointed, const NodeMetadata *meta, bool force)
{
const auto &prediction = selected_def.node_placement_prediction;
// formspec in meta
if (meta && !meta->getString("formspec").empty() && !input->isRandom()
- && !isKeyDown(KeyType::SNEAK)) {
+ && !isKeyDown(KeyType::SNEAK) && !force) {
// on_rightclick callbacks are called anyway
if (nodedef_manager->get(map.getNode(nodepos)).rightclickable)
client->interact(INTERACT_PLACE, pointed);
// on_rightclick callback
if (prediction.empty() || (nodedef->get(node).rightclickable &&
- !isKeyDown(KeyType::SNEAK))) {
+ !isKeyDown(KeyType::SNEAK) && !force)) {
// Report to server
client->interact(INTERACT_PLACE, pointed);
return false;
m_game_ui->setInfoText(infotext);
- if (isKeyDown(KeyType::DIG)) {
+ if (isKeyDown(KeyType::DIG) || g_settings->getBool("autohit")) {
bool do_punch = false;
bool do_punch_damage = false;
- if (runData.object_hit_delay_timer <= 0.0) {
+ if (runData.object_hit_delay_timer <= 0.0 || g_settings->getBool("spamclick")) {
do_punch = true;
do_punch_damage = true;
runData.object_hit_delay_timer = object_hit_delay;
dir, &tool_item, runData.time_from_last_punch);
runData.time_from_last_punch = 0;
- if (!disable_send)
+ if (!disable_send) {
client->interact(INTERACT_START_DIGGING, pointed);
+ }
}
} else if (wasKeyDown(KeyType::PLACE)) {
infostream << "Pressed place button while pointing at object" << std::endl;
}
}
+ if(g_settings->getBool("instant_break")) {
+ runData.dig_time_complete = 0;
+ runData.dig_instantly = true;
+ }
if (!runData.digging) {
infostream << "Started digging" << std::endl;
runData.dig_instantly = runData.dig_time_complete == 0;
float direct_brightness;
bool sunlight_seen;
- if (m_cache_enable_noclip && m_cache_enable_free_move) {
+ if ((m_cache_enable_noclip && m_cache_enable_free_move) || g_settings->getBool("freecam")) {
direct_brightness = time_brightness;
sunlight_seen = true;
} else {
if (player->hurt_tilt_timer > 0.0f) {
player->hurt_tilt_timer -= dtime * 6.0f;
- if (player->hurt_tilt_timer < 0.0f)
+ if (player->hurt_tilt_timer < 0.0f || g_settings->getBool("no_hurt_cam"))
player->hurt_tilt_strength = 0.0f;
}
if (m_game_ui->m_flags.show_profiler_graph)
graph->draw(10, screensize.Y - 10, driver, g_fontengine->getFont());
+ /*
+ Cheat menu
+ */
+
+ if (! gui_chat_console->isOpen()) {
+ if (m_game_ui->m_flags.show_cheat_menu)
+ m_cheat_menu->draw(driver, m_game_ui->m_flags.show_minimal_debug);
+ if (g_settings->getBool("cheat_hud"))
+ m_cheat_menu->drawHUD(driver, dtime);
+ }
/*
Damage flash
*/
if (runData.damage_flash > 0.0f) {
video::SColor color(runData.damage_flash, 180, 0, 0);
- driver->draw2DRectangle(color,
- core::rect<s32>(0, 0, screensize.X, screensize.Y),
- NULL);
+ if (! g_settings->getBool("no_hurt_cam"))
+ driver->draw2DRectangle(color, core::rect<s32>(0, 0, screensize.X, screensize.Y), NULL);
runData.damage_flash -= 384.0f * dtime;
}
/*
- ==================== End scene ====================
+ End scene
*/
#if IRRLICHT_VERSION_MT_REVISION < 5
if (++m_reset_HW_buffer_counter > 500) {
((Game *)data)->readSettings();
}
+void Game::updateAllMapBlocksCallback(const std::string &setting_name, void *data)
+{
+ ((Game *) data)->client->updateAllMapBlocks();
+}
+
+void Game::freecamChangedCallback(const std::string &setting_name, void *data)
+{
+ Game *game = (Game *) data;
+ LocalPlayer *player = game->client->getEnv().getLocalPlayer();
+ if (g_settings->getBool("freecam")) {
+ game->camera->setCameraMode(CAMERA_MODE_FIRST);
+ player->freecamEnable();
+ } else {
+ player->freecamDisable();
+ }
+ game->updatePlayerCAOVisibility();
+}
+
void Game::readSettings()
{
m_cache_doubletap_jump = g_settings->getBool("doubletap_jump");
m_does_lost_focus_pause_game = g_settings->getBool("pause_on_lost_focus");
}
+bool Game::isKeyDown(GameKeyType k)
+{
+ return input->isKeyDown(k);
+}
+
+bool Game::wasKeyDown(GameKeyType k)
+{
+ return input->wasKeyDown(k);
+}
+
+bool Game::wasKeyPressed(GameKeyType k)
+{
+ return input->wasKeyPressed(k);
+}
+
+bool Game::wasKeyReleased(GameKeyType k)
+{
+ return input->wasKeyReleased(k);
+}
+
/****************************************************************************/
/****************************************************************************
Shutdown / cleanup
"- %s: sneak/climb down\n"
"- %s: drop item\n"
"- %s: inventory\n"
+ "- %s: enderchest\n"
"- Mouse: turn/look\n"
"- Mouse wheel: select item\n"
"- %s: chat\n"
+ "- %s: Killaura\n"
+ "- %s: Freecam\n"
+ "- %s: Scaffold\n"
);
- char control_text_buf[600];
-
- porting::mt_snprintf(control_text_buf, sizeof(control_text_buf), control_text_template.c_str(),
- GET_KEY_NAME(keymap_forward),
- GET_KEY_NAME(keymap_backward),
- GET_KEY_NAME(keymap_left),
- GET_KEY_NAME(keymap_right),
- GET_KEY_NAME(keymap_jump),
- GET_KEY_NAME(keymap_dig),
- GET_KEY_NAME(keymap_place),
- GET_KEY_NAME(keymap_sneak),
- GET_KEY_NAME(keymap_drop),
- GET_KEY_NAME(keymap_inventory),
- GET_KEY_NAME(keymap_chat)
- );
+ char control_text_buf[600];
+
+ porting::mt_snprintf(control_text_buf, sizeof(control_text_buf), control_text_template.c_str(),
+ GET_KEY_NAME(keymap_forward),
+ GET_KEY_NAME(keymap_backward),
+ GET_KEY_NAME(keymap_left),
+ GET_KEY_NAME(keymap_right),
+ GET_KEY_NAME(keymap_jump),
+ GET_KEY_NAME(keymap_dig),
+ GET_KEY_NAME(keymap_place),
+ GET_KEY_NAME(keymap_sneak),
+ GET_KEY_NAME(keymap_drop),
+ GET_KEY_NAME(keymap_inventory),
+ GET_KEY_NAME(keymap_enderchest),
+ GET_KEY_NAME(keymap_chat),
+ GET_KEY_NAME(keymap_toggle_killaura),
+ GET_KEY_NAME(keymap_toggle_freecam),
+ GET_KEY_NAME(keymap_toggle_scaffold)
+ );
std::string control_text = std::string(control_text_buf);
str_formspec_escape(control_text);
****************************************************************************/
/****************************************************************************/
+Game *g_game;
+
void the_game(bool *kill,
InputHandler *input,
RenderingEngine *rendering_engine,
{
Game game;
+ g_game = &game;
+
/* Make a copy of the server address because if a local singleplayer server
* is created then this is updated and we don't want to change the value
* passed to us by the calling function