diff options
Diffstat (limited to 'src/client/game.cpp')
-rw-r--r-- | src/client/game.cpp | 478 |
1 files changed, 217 insertions, 261 deletions
diff --git a/src/client/game.cpp b/src/client/game.cpp index 069c482ca..3c58fb46f 100644 --- a/src/client/game.cpp +++ b/src/client/game.cpp @@ -34,11 +34,13 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "clouds.h" #include "config.h" #include "content_cao.h" +#include "content/subgames.h" #include "client/event_manager.h" #include "fontengine.h" #include "itemdef.h" #include "log.h" #include "filesys.h" +#include "gameparams.h" #include "gettext.h" #include "gui/guiChatConsole.h" #include "gui/guiConfirmRegistration.h" @@ -169,13 +171,7 @@ struct LocalFormspecHandler : public TextDest return; } - if (fields.find("quit") != fields.end()) { - return; - } - - if (fields.find("btn_continue") != fields.end()) { - return; - } + return; } if (m_formname == "MT_DEATH_SCREEN") { @@ -184,7 +180,7 @@ struct LocalFormspecHandler : public TextDest return; } - if (m_client && m_client->modsLoaded()) + if (m_client->modsLoaded()) m_client->getScript()->on_formspec_input(m_formname, fields); } @@ -422,14 +418,13 @@ class GameGlobalShaderConstantSetter : public IShaderConstantSetter 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; - CachedPixelShaderSetting<SamplerLayer_t> m_texture_flags; Client *m_client; public: @@ -456,14 +451,13 @@ public: 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_texture_flags("textureFlags"), m_client(client) { g_settings->registerChangedCallback("enable_fog", settingsCallback, this); @@ -475,12 +469,8 @@ public: g_settings->deregisterChangedCallback("enable_fog", settingsCallback, this); } - virtual void onSetConstants(video::IMaterialRendererServices *services, - bool is_highlevel) + void onSetConstants(video::IMaterialRendererServices *services) override { - if (!is_highlevel) - return; - // Background color video::SColor bgcolor = m_sky->getBgColor(); video::SColorf bgcolorf(bgcolor); @@ -509,6 +499,10 @@ public: 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); @@ -551,12 +545,8 @@ public: 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, - flags_tex = 2; + SamplerLayer_t base_tex = 0; m_base_texture.set(&base_tex, services); - m_normal_texture.set(&normal_tex, services); - m_texture_flags.set(&flags_tex, services); } }; @@ -587,7 +577,7 @@ public: virtual IShaderConstantSetter* create() { - GameGlobalShaderConstantSetter *scs = new GameGlobalShaderConstantSetter( + auto *scs = new GameGlobalShaderConstantSetter( m_sky, m_force_fog_off, m_fog_range, m_client); if (!m_sky) created_nosky.push_back(scs); @@ -602,7 +592,6 @@ public: #endif /**************************************************************************** - ****************************************************************************/ const float object_hit_delay = 0.2; @@ -623,15 +612,15 @@ struct GameRunData { u16 new_playeritem; PointedThing pointed_old; bool digging; - bool ldown_for_dig; + bool punching; + bool btn_down_for_dig; bool dig_instantly; bool digging_blocked; - bool left_punch; bool reset_jump_timer; float nodig_delay_timer; float dig_time; float dig_time_complete; - float repeat_rightclick_timer; + float repeat_place_timer; float object_hit_delay_timer; float time_from_last_punch; ClientActiveObject *selected_object; @@ -669,19 +658,11 @@ public: ~Game(); bool startup(bool *kill, - bool random_input, InputHandler *input, - const std::string &map_dir, - const std::string &playername, - const std::string &password, - // If address is "", local server is used and address is updated - std::string *address, - u16 port, + const GameStartData &game_params, std::string &error_message, bool *reconnect, - ChatBackend *chat_backend, - const SubgameSpec &gamespec, // Used for local game - bool simple_singleplayer_mode); + ChatBackend *chat_backend); void run(); void shutdown(); @@ -691,21 +672,18 @@ protected: void extendedResourceCleanup(); // Basic initialisation - bool init(const std::string &map_dir, std::string *address, - u16 port, - const SubgameSpec &gamespec); + 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, std::string *address); + const SubgameSpec &gamespec, u16 port); // Client creation - bool createClient(const std::string &playername, - const std::string &password, std::string *address, u16 port); + bool createClient(const GameStartData &start_data); bool initGui(); // Client connection - bool connectToServer(const std::string &playername, - const std::string &password, std::string *address, u16 port, + bool connectToServer(const GameStartData &start_data, bool *connect_ok, bool *aborted); bool getServerContent(bool *aborted); @@ -796,6 +774,14 @@ protected: { 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(); @@ -885,7 +871,6 @@ private: bool *reconnect_requested; scene::ISceneNode *skybox; - bool random_input; bool simple_singleplayer_mode; /* End 'cache' */ @@ -910,7 +895,7 @@ private: bool m_cache_enable_free_move; f32 m_cache_mouse_sensitivity; f32 m_cache_joystick_frustum_sensitivity; - f32 m_repeat_right_click_time; + f32 m_repeat_place_time; f32 m_cache_cam_smoothing; f32 m_cache_fog_start; @@ -920,6 +905,7 @@ private: bool m_does_lost_focus_pause_game = false; + int m_reset_HW_buffer_counter = 0; #ifdef __ANDROID__ bool m_cache_hold_aux1; bool m_android_chat_open; @@ -944,7 +930,7 @@ Game::Game() : &settingChangedCallback, this); g_settings->registerChangedCallback("joystick_frustum_sensitivity", &settingChangedCallback, this); - g_settings->registerChangedCallback("repeat_rightclick_time", + g_settings->registerChangedCallback("repeat_place_time", &settingChangedCallback, this); g_settings->registerChangedCallback("noclip", &settingChangedCallback, this); @@ -1002,7 +988,7 @@ Game::~Game() &settingChangedCallback, this); g_settings->deregisterChangedCallback("mouse_sensitivity", &settingChangedCallback, this); - g_settings->deregisterChangedCallback("repeat_rightclick_time", + g_settings->deregisterChangedCallback("repeat_place_time", &settingChangedCallback, this); g_settings->deregisterChangedCallback("noclip", &settingChangedCallback, this); @@ -1017,28 +1003,21 @@ Game::~Game() } bool Game::startup(bool *kill, - bool random_input, InputHandler *input, - const std::string &map_dir, - const std::string &playername, - const std::string &password, - std::string *address, // can change if simple_singleplayer_mode - u16 port, + const GameStartData &start_data, std::string &error_message, bool *reconnect, - ChatBackend *chat_backend, - const SubgameSpec &gamespec, - bool simple_singleplayer_mode) + ChatBackend *chat_backend) { + // "cache" this->device = RenderingEngine::get_raw_device(); this->kill = kill; this->error_message = &error_message; this->reconnect_requested = reconnect; - this->random_input = random_input; this->input = input; this->chat_backend = chat_backend; - this->simple_singleplayer_mode = simple_singleplayer_mode; + this->simple_singleplayer_mode = start_data.isSinglePlayer(); input->keycache.populate(); @@ -1059,10 +1038,12 @@ bool Game::startup(bool *kill, g_client_translations->clear(); - if (!init(map_dir, address, port, gamespec)) + // address can change if simple_singleplayer_mode + if (!init(start_data.world_spec.path, start_data.address, + start_data.socket_port, start_data.game_spec)) return false; - if (!createClient(playername, password, address, port)) + if (!createClient(start_data)) return false; RenderingEngine::initialize(client, hud); @@ -1221,7 +1202,7 @@ void Game::shutdown() bool Game::init( const std::string &map_dir, - std::string *address, + const std::string &address, u16 port, const SubgameSpec &gamespec) { @@ -1245,8 +1226,8 @@ bool Game::init( return false; // Create a server if not connecting to an existing one - if (address->empty()) { - if (!createSingleplayerServer(map_dir, gamespec, port, address)) + if (address.empty()) { + if (!createSingleplayerServer(map_dir, gamespec, port)) return false; } @@ -1281,7 +1262,7 @@ bool Game::initSound() } bool Game::createSingleplayerServer(const std::string &map_dir, - const SubgameSpec &gamespec, u16 port, std::string *address) + const SubgameSpec &gamespec, u16 port) { showOverlayMessage(N_("Creating server..."), 0, 5); @@ -1308,14 +1289,14 @@ bool Game::createSingleplayerServer(const std::string &map_dir, return false; } - server = new Server(map_dir, gamespec, simple_singleplayer_mode, bind_addr, false); + server = new Server(map_dir, gamespec, simple_singleplayer_mode, bind_addr, + false, nullptr, error_message); server->start(); return true; } -bool Game::createClient(const std::string &playername, - const std::string &password, std::string *address, u16 port) +bool Game::createClient(const GameStartData &start_data) { showOverlayMessage(N_("Creating client..."), 0, 10); @@ -1330,8 +1311,7 @@ bool Game::createClient(const std::string &playername, g_touchscreengui->hide(); } #endif - if (!connectToServer(playername, password, address, port, - &could_connect, &connect_aborted)) + if (!connectToServer(start_data, &could_connect, &connect_aborted)) return false; if (!could_connect) { @@ -1352,7 +1332,7 @@ bool Game::createClient(const std::string &playername, return false; } - GameGlobalShaderConstantSetterFactory *scsf = new GameGlobalShaderConstantSetterFactory( + auto *scsf = new GameGlobalShaderConstantSetterFactory( &m_flags.force_fog_off, &runData.fog_range, client); shader_src->addShaderConstantSetterFactory(scsf); @@ -1362,33 +1342,21 @@ bool Game::createClient(const std::string &playername, /* Camera */ camera = new Camera(*draw_control, client); - if (!camera || !camera->successfullyCreated(*error_message)) + if (!camera->successfullyCreated(*error_message)) return false; client->setCamera(camera); /* Clouds */ - if (m_cache_enable_clouds) { + if (m_cache_enable_clouds) clouds = new Clouds(smgr, -1, time(0)); - if (!clouds) { - *error_message = "Memory allocation error (clouds)"; - errorstream << *error_message << std::endl; - return false; - } - } /* Skybox */ - sky = new Sky(-1, texture_src); + sky = new Sky(-1, texture_src, shader_src); scsf->setSky(sky); skybox = NULL; // This is used/set later on in the main run loop - if (!sky) { - *error_message = "Memory allocation error sky"; - errorstream << *error_message << std::endl; - return false; - } - /* Pre-calculated values */ video::ITexture *t = texture_src->getTexture("crack_anylength.png"); @@ -1418,18 +1386,10 @@ bool Game::createClient(const std::string &playername, hud = new Hud(guienv, client, player, &player->inventory); - if (!hud) { - *error_message = "Memory error: could not create HUD"; - errorstream << *error_message << std::endl; - return false; - } - mapper = client->getMinimap(); - if (mapper) { - mapper->setMinimapMode(MINIMAP_MODE_OFF); - if (client->modsLoaded()) - client->getScript()->on_minimap_ready(mapper); - } + + if (mapper && client->modsLoaded()) + client->getScript()->on_minimap_ready(mapper); return true; } @@ -1447,11 +1407,6 @@ bool Game::initGui() // Chat backend and console 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; - } #ifdef HAVE_TOUCHSCREENGUI @@ -1463,8 +1418,7 @@ bool Game::initGui() return true; } -bool Game::connectToServer(const std::string &playername, - const std::string &password, std::string *address, u16 port, +bool Game::connectToServer(const GameStartData &start_data, bool *connect_ok, bool *connection_aborted) { *connect_ok = false; // Let's not be overly optimistic @@ -1473,10 +1427,10 @@ bool Game::connectToServer(const std::string &playername, showOverlayMessage(N_("Resolving address..."), 0, 15); - Address connect_address(0, 0, 0, 0, port); + Address connect_address(0, 0, 0, 0, start_data.socket_port); try { - connect_address.Resolve(address->c_str()); + connect_address.Resolve(start_data.address.c_str()); if (connect_address.isZero()) { // i.e. INADDR_ANY, IN6ADDR_ANY //connect_address.Resolve("localhost"); @@ -1503,14 +1457,12 @@ bool Game::connectToServer(const std::string &playername, return false; } - client = new Client(playername.c_str(), password, *address, + client = new Client(start_data.name.c_str(), + start_data.password, start_data.address, *draw_control, texture_src, shader_src, itemdef_manager, nodedef_manager, sound, eventmgr, connect_address.isIPv6(), m_game_ui.get()); - if (!client) - return false; - client->m_simple_singleplayer_mode = simple_singleplayer_mode; infostream << "Connecting to server at "; @@ -1574,13 +1526,13 @@ bool Game::connectToServer(const std::string &playername, } else { registration_confirmation_shown = true; (new GUIConfirmRegistration(guienv, guienv->getRootGUIElement(), -1, - &g_menumgr, client, playername, password, + &g_menumgr, client, start_data.name, start_data.password, connection_aborted, texture_src))->drop(); } } else { wait_time += dtime; // Only time out if we aren't waiting for the server we started - if (!address->empty() && wait_time > 10) { + if (!start_data.isSinglePlayer() && wait_time > 10) { *error_message = "Connection timed out."; errorstream << *error_message << std::endl; break; @@ -1659,7 +1611,10 @@ bool Game::getServerContent(bool *aborted) std::stringstream message; std::fixed(message); message.precision(0); - message << gettext("Media...") << " " << (client->mediaReceiveProgress()*100) << "%"; + float receive = client->mediaReceiveProgress() * 100; + message << gettext("Media..."); + if (receive > 0) + message << " " << receive << "%"; message.precision(2); if ((USE_CURL == 0) || @@ -2029,15 +1984,11 @@ void Game::processItemSelection(u16 *new_playeritem) s32 dir = wheel; - if (input->joystick.wasKeyDown(KeyType::SCROLL_DOWN) || - wasKeyDown(KeyType::HOTBAR_NEXT)) { + if (wasKeyDown(KeyType::HOTBAR_NEXT)) dir = -1; - } - if (input->joystick.wasKeyDown(KeyType::SCROLL_UP) || - wasKeyDown(KeyType::HOTBAR_PREV)) { + if (wasKeyDown(KeyType::HOTBAR_PREV)) dir = 1; - } if (dir < 0) *new_playeritem = *new_playeritem < max_item ? *new_playeritem + 1 : 0; @@ -2090,7 +2041,7 @@ void Game::openInventory() TextDest *txt_dst = new TextDestPlayerInventory(client); auto *&formspec = m_game_ui->updateFormspec(""); GUIFormSpecMenu::create(formspec, client, &input->joystick, fs_src, - txt_dst, client->getFormspecPrepend()); + txt_dst, client->getFormspecPrepend(), sound); formspec->setFormSpec(fs_src->getForm(), inventoryloc); } @@ -2231,52 +2182,37 @@ void Game::toggleMinimap(bool shift_pressed) if (!mapper || !m_game_ui->m_flags.show_hud || !g_settings->getBool("enable_minimap")) return; - if (shift_pressed) { + if (shift_pressed) mapper->toggleMinimapShape(); - return; - } + else + mapper->nextMode(); + + // TODO: When legacy minimap is deprecated, keep only HUD minimap stuff here + // Not so satisying code to keep compatibility with old fixed mode system + // --> u32 hud_flags = client->getEnv().getLocalPlayer()->hud_flags; - MinimapMode mode = MINIMAP_MODE_OFF; - if (hud_flags & HUD_FLAG_MINIMAP_VISIBLE) { - mode = mapper->getMinimapMode(); - mode = (MinimapMode)((int)mode + 1); - // If radar is disabled and in, or switching to, radar mode - if (!(hud_flags & HUD_FLAG_MINIMAP_RADAR_VISIBLE) && mode > 3) - mode = MINIMAP_MODE_OFF; - } + if (!(hud_flags & HUD_FLAG_MINIMAP_VISIBLE)) { + m_game_ui->m_flags.show_minimap = false; + } else { - m_game_ui->m_flags.show_minimap = true; - switch (mode) { - case MINIMAP_MODE_SURFACEx1: - m_game_ui->showTranslatedStatusText("Minimap in surface mode, Zoom x1"); - break; - case MINIMAP_MODE_SURFACEx2: - m_game_ui->showTranslatedStatusText("Minimap in surface mode, Zoom x2"); - break; - case MINIMAP_MODE_SURFACEx4: - m_game_ui->showTranslatedStatusText("Minimap in surface mode, Zoom x4"); - break; - case MINIMAP_MODE_RADARx1: - m_game_ui->showTranslatedStatusText("Minimap in radar mode, Zoom x1"); - break; - case MINIMAP_MODE_RADARx2: - m_game_ui->showTranslatedStatusText("Minimap in radar mode, Zoom x2"); - break; - case MINIMAP_MODE_RADARx4: - m_game_ui->showTranslatedStatusText("Minimap in radar mode, Zoom x4"); - break; - default: - mode = MINIMAP_MODE_OFF; - m_game_ui->m_flags.show_minimap = false; - if (hud_flags & HUD_FLAG_MINIMAP_VISIBLE) - m_game_ui->showTranslatedStatusText("Minimap hidden"); - else - m_game_ui->showTranslatedStatusText("Minimap currently disabled by game or mod"); - } + // If radar is disabled, try to find a non radar mode or fall back to 0 + if (!(hud_flags & HUD_FLAG_MINIMAP_RADAR_VISIBLE)) + while (mapper->getModeIndex() && + mapper->getModeDef().type == MINIMAP_TYPE_RADAR) + mapper->nextMode(); - mapper->setMinimapMode(mode); + m_game_ui->m_flags.show_minimap = mapper->getModeDef().type != + MINIMAP_TYPE_OFF; + } + // <-- + // End of 'not so satifying code' + if ((hud_flags & HUD_FLAG_MINIMAP_VISIBLE) || + (hud && hud->hasElementOfType(HUD_ELEM_MINIMAP))) + m_game_ui->showStatusText(utf8_to_wide(mapper->getModeDef().label)); + else + m_game_ui->showTranslatedStatusText("Minimap currently disabled by game or mod"); } void Game::toggleFog() @@ -2399,10 +2335,10 @@ void Game::checkZoomEnabled() void Game::updateCameraDirection(CameraOrientation *cam, float dtime) { if ((device->isWindowActive() && device->isWindowFocused() - && !isMenuActive()) || random_input) { + && !isMenuActive()) || input->isRandom()) { #ifndef __ANDROID__ - if (!random_input) { + if (!input->isRandom()) { // Mac OSX gets upset if this is set every frame if (device->getCursorControl()->isVisible()) device->getCursorControl()->setVisible(false); @@ -2482,8 +2418,8 @@ void Game::updatePlayerControl(const CameraOrientation &cam) isKeyDown(KeyType::SPECIAL1), isKeyDown(KeyType::SNEAK), isKeyDown(KeyType::ZOOM), - input->getLeftState(), - input->getRightState(), + isKeyDown(KeyType::DIG), + isKeyDown(KeyType::PLACE), cam.camera_pitch, cam.camera_yaw, input->joystick.getAxisWithoutDead(JA_SIDEWARD_MOVE), @@ -2498,8 +2434,8 @@ void Game::updatePlayerControl(const CameraOrientation &cam) ( (u32)(isKeyDown(KeyType::JUMP) & 0x1) << 4) | ( (u32)(isKeyDown(KeyType::SPECIAL1) & 0x1) << 5) | ( (u32)(isKeyDown(KeyType::SNEAK) & 0x1) << 6) | - ( (u32)(input->getLeftState() & 0x1) << 7) | - ( (u32)(input->getRightState() & 0x1) << 8) | + ( (u32)(isKeyDown(KeyType::DIG) & 0x1) << 7) | + ( (u32)(isKeyDown(KeyType::PLACE) & 0x1) << 8) | ( (u32)(isKeyDown(KeyType::ZOOM) & 0x1) << 9) ); @@ -2637,7 +2573,7 @@ void Game::handleClientEvent_ShowFormSpec(ClientEvent *event, CameraOrientation auto *&formspec = m_game_ui->updateFormspec(*(event->show_formspec.formname)); GUIFormSpecMenu::create(formspec, client, &input->joystick, - fs_src, txt_dst, client->getFormspecPrepend()); + fs_src, txt_dst, client->getFormspecPrepend(), sound); } delete event->show_formspec.formspec; @@ -2650,7 +2586,7 @@ void Game::handleClientEvent_ShowLocalFormSpec(ClientEvent *event, CameraOrienta LocalFormspecHandler *txt_dst = new LocalFormspecHandler(*event->show_formspec.formname, client); GUIFormSpecMenu::create(m_game_ui->getFormspecGUI(), client, &input->joystick, - fs_src, txt_dst, client->getFormspecPrepend()); + fs_src, txt_dst, client->getFormspecPrepend(), sound); delete event->show_formspec.formspec; delete event->show_formspec.formname; @@ -2959,7 +2895,8 @@ void Game::updateCamera(u32 busy_time, f32 dtime) camera->toggleCameraMode(); - playercao->setVisible(camera->getCameraMode() > CAMERA_MODE_FIRST); + // Make the player visible depending on camera mode. + playercao->updateMeshCulling(); playercao->setChildrenVisible(camera->getCameraMode() > CAMERA_MODE_FIRST); } @@ -3081,7 +3018,7 @@ void Game::processPlayerInteraction(f32 dtime, bool show_hud, bool show_debug) PointedThing pointed = updatePointedThing(shootline, selected_def.liquids_pointable, - !runData.ldown_for_dig, + !runData.btn_down_for_dig, camera_offset); if (pointed != runData.pointed_old) { @@ -3089,20 +3026,18 @@ void Game::processPlayerInteraction(f32 dtime, bool show_hud, bool show_debug) hud->updateSelectionMesh(camera_offset); } - if (runData.digging_blocked && !input->getLeftState()) { - // allow digging again if button is not pressed + // Allow digging again if button is not pressed + if (runData.digging_blocked && !isKeyDown(KeyType::DIG)) runData.digging_blocked = false; - } /* Stop digging when - - releasing left mouse button + - releasing dig button - pointing away from node */ if (runData.digging) { - if (input->getLeftReleased()) { - infostream << "Left button released" - << " (stopped digging)" << std::endl; + if (wasKeyReleased(KeyType::DIG)) { + infostream << "Dig button released (stopped digging)" << std::endl; runData.digging = false; } else if (pointed != runData.pointed_old) { if (pointed.type == POINTEDTHING_NODE @@ -3112,8 +3047,7 @@ void Game::processPlayerInteraction(f32 dtime, bool show_hud, bool show_debug) // Still pointing to the same node, but a different face. // Don't reset. } else { - infostream << "Pointing away from node" - << " (stopped digging)" << std::endl; + infostream << "Pointing away from node (stopped digging)" << std::endl; runData.digging = false; hud->updateSelectionMesh(camera_offset); } @@ -3124,55 +3058,60 @@ void Game::processPlayerInteraction(f32 dtime, bool show_hud, bool show_debug) client->setCrack(-1, v3s16(0, 0, 0)); runData.dig_time = 0.0; } - } else if (runData.dig_instantly && input->getLeftReleased()) { - // Remove e.g. torches faster when clicking instead of holding LMB + } else if (runData.dig_instantly && wasKeyReleased(KeyType::DIG)) { + // Remove e.g. torches faster when clicking instead of holding dig button runData.nodig_delay_timer = 0; runData.dig_instantly = false; } - if (!runData.digging && runData.ldown_for_dig && !input->getLeftState()) { - runData.ldown_for_dig = false; - } + if (!runData.digging && runData.btn_down_for_dig && !isKeyDown(KeyType::DIG)) + runData.btn_down_for_dig = false; - runData.left_punch = false; + runData.punching = false; soundmaker->m_player_leftpunch_sound.name = ""; // Prepare for repeating, unless we're not supposed to - if (input->getRightState() && !g_settings->getBool("safe_dig_and_place")) - runData.repeat_rightclick_timer += dtime; + if (isKeyDown(KeyType::PLACE) && !g_settings->getBool("safe_dig_and_place")) + runData.repeat_place_timer += dtime; else - runData.repeat_rightclick_timer = 0; + runData.repeat_place_timer = 0; - if (selected_def.usable && input->getLeftState()) { - if (input->getLeftClicked() && (!client->modsLoaded() - || !client->getScript()->on_item_use(selected_item, pointed))) + if (selected_def.usable && isKeyDown(KeyType::DIG)) { + if (wasKeyPressed(KeyType::DIG) && (!client->modsLoaded() || + !client->getScript()->on_item_use(selected_item, pointed))) client->interact(INTERACT_USE, pointed); } else if (pointed.type == POINTEDTHING_NODE) { handlePointingAtNode(pointed, selected_item, hand_item, dtime); } else if (pointed.type == POINTEDTHING_OBJECT) { v3f player_position = player->getPosition(); handlePointingAtObject(pointed, tool_item, player_position, show_debug); - } else if (input->getLeftState()) { + } else if (isKeyDown(KeyType::DIG)) { // When button is held down in air, show continuous animation - runData.left_punch = true; + runData.punching = true; // Run callback even though item is not usable - if (input->getLeftClicked() && client->modsLoaded()) + if (wasKeyPressed(KeyType::DIG) && client->modsLoaded()) client->getScript()->on_item_use(selected_item, pointed); - } else if (input->getRightClicked()) { + } else if (wasKeyPressed(KeyType::PLACE)) { handlePointingAtNothing(selected_item); } runData.pointed_old = pointed; - if (runData.left_punch || input->getLeftClicked()) - camera->setDigging(0); // left click animation + if (runData.punching || wasKeyPressed(KeyType::DIG)) + camera->setDigging(0); // dig animation - input->resetLeftClicked(); - input->resetRightClicked(); + input->clearWasKeyPressed(); + input->clearWasKeyReleased(); + // Ensure DIG & PLACE are marked as handled + wasKeyDown(KeyType::DIG); + wasKeyDown(KeyType::PLACE); - input->resetLeftReleased(); - input->resetRightReleased(); + input->joystick.clearWasKeyPressed(KeyType::DIG); + input->joystick.clearWasKeyPressed(KeyType::PLACE); + + input->joystick.clearWasKeyReleased(KeyType::DIG); + input->joystick.clearWasKeyReleased(KeyType::PLACE); } @@ -3193,11 +3132,14 @@ PointedThing Game::updatePointedThing( const NodeDefManager *nodedef = map.getNodeDefManager(); runData.selected_object = NULL; + hud->pointing_at_object = false; RaycastState s(shootline, look_for_object, liquids_pointable); PointedThing result; env.continueRaycast(&s, &result); if (result.type == POINTEDTHING_OBJECT) { + hud->pointing_at_object = true; + runData.selected_object = client->getEnv().getActiveObject(result.object_id); aabb3f selection_box; if (show_entity_selectionbox && runData.selected_object->doShowSelectionBox() && @@ -3269,7 +3211,7 @@ PointedThing Game::updatePointedThing( void Game::handlePointingAtNothing(const ItemStack &playerItem) { - infostream << "Right Clicked in Air" << std::endl; + infostream << "Attempted to place item while pointing at nothing" << std::endl; PointedThing fauxPointed; fauxPointed.type = POINTEDTHING_NOTHING; client->interact(INTERACT_ACTIVATE, fauxPointed); @@ -3288,7 +3230,7 @@ void Game::handlePointingAtNode(const PointedThing &pointed, ClientMap &map = client->getEnv().getClientMap(); - if (runData.nodig_delay_timer <= 0.0 && input->getLeftState() + if (runData.nodig_delay_timer <= 0.0 && isKeyDown(KeyType::DIG) && !runData.digging_blocked && client->checkPrivilege("interact")) { handleDigging(pointed, nodepos, selected_item, hand_item, dtime); @@ -3309,13 +3251,14 @@ void Game::handlePointingAtNode(const PointedThing &pointed, } } - if ((input->getRightClicked() || - runData.repeat_rightclick_timer >= m_repeat_right_click_time) && + if ((wasKeyPressed(KeyType::PLACE) || + runData.repeat_place_timer >= m_repeat_place_time) && client->checkPrivilege("interact")) { - runData.repeat_rightclick_timer = 0; - infostream << "Ground right-clicked" << std::endl; + runData.repeat_place_timer = 0; + infostream << "Place button pressed while looking at ground" << std::endl; - camera->setDigging(1); // right click animation (always shown for feedback) + // Placing animation (always shown for feedback) + camera->setDigging(1); soundmaker->m_player_rightpunch_sound = SimpleSoundSpec(); @@ -3349,7 +3292,7 @@ bool Game::nodePlacement(const ItemDefinition &selected_def, } // formspec in meta - if (meta && !meta->getString("formspec").empty() && !random_input + if (meta && !meta->getString("formspec").empty() && !input->isRandom() && !isKeyDown(KeyType::SNEAK)) { // on_rightclick callbacks are called anyway if (nodedef_manager->get(map.getNode(nodepos)).rightclickable) @@ -3366,7 +3309,7 @@ bool Game::nodePlacement(const ItemDefinition &selected_def, auto *&formspec = m_game_ui->updateFormspec(""); GUIFormSpecMenu::create(formspec, client, &input->joystick, fs_src, - txt_dst, client->getFormspecPrepend()); + txt_dst, client->getFormspecPrepend(), sound); formspec->setFormSpec(meta->getString("formspec"), inventoryloc); return false; @@ -3381,8 +3324,7 @@ bool Game::nodePlacement(const ItemDefinition &selected_def, } verbosestream << "Node placement prediction for " - << selected_def.name << " is " - << prediction << std::endl; + << selected_def.name << " is " << prediction << std::endl; v3s16 p = neighbourpos; // Place inside node itself if buildable_to @@ -3393,6 +3335,7 @@ bool Game::nodePlacement(const ItemDefinition &selected_def, } else { node = map.getNode(p, &is_valid_position); if (is_valid_position && !nodedef->get(node).buildable_to) { + soundmaker->m_player_rightpunch_sound = selected_def.sound_place_failed; // Report to server client->interact(INTERACT_PLACE, pointed); return false; @@ -3465,6 +3408,7 @@ bool Game::nodePlacement(const ItemDefinition &selected_def, pp = p + v3s16(0, -1, 0); if (!nodedef->get(map.getNode(pp)).walkable) { + soundmaker->m_player_rightpunch_sound = selected_def.sound_place_failed; // Report to server client->interact(INTERACT_PLACE, pointed); return false; @@ -3541,7 +3485,7 @@ void Game::handlePointingAtObject(const PointedThing &pointed, m_game_ui->setInfoText(infotext); - if (input->getLeftState()) { + if (isKeyDown(KeyType::DIG)) { bool do_punch = false; bool do_punch_damage = false; @@ -3551,12 +3495,12 @@ void Game::handlePointingAtObject(const PointedThing &pointed, runData.object_hit_delay_timer = object_hit_delay; } - if (input->getLeftClicked()) + if (wasKeyPressed(KeyType::DIG)) do_punch = true; if (do_punch) { - infostream << "Left-clicked object" << std::endl; - runData.left_punch = true; + infostream << "Punched object" << std::endl; + runData.punching = true; } if (do_punch_damage) { @@ -3571,8 +3515,8 @@ void Game::handlePointingAtObject(const PointedThing &pointed, if (!disable_send) client->interact(INTERACT_START_DIGGING, pointed); } - } else if (input->getRightClicked()) { - infostream << "Right-clicked object" << std::endl; + } else if (wasKeyDown(KeyType::PLACE)) { + infostream << "Pressed place button while pointing at object" << std::endl; client->interact(INTERACT_PLACE, pointed); // place } } @@ -3618,7 +3562,7 @@ void Game::handleDigging(const PointedThing &pointed, const v3s16 &nodepos, return; client->interact(INTERACT_START_DIGGING, pointed); runData.digging = true; - runData.ldown_for_dig = true; + runData.btn_down_for_dig = true; } if (!runData.dig_instantly) { @@ -3712,10 +3656,9 @@ void Game::handleDigging(const PointedThing &pointed, const v3s16 &nodepos, client->setCrack(-1, nodepos); } - camera->setDigging(0); // left click animation + camera->setDigging(0); // Dig animation } - void Game::updateFrame(ProfilerGraph *graph, RunStats *stats, f32 dtime, const CameraOrientation &cam) { @@ -3958,7 +3901,7 @@ void Game::updateFrame(ProfilerGraph *graph, RunStats *stats, f32 dtime, /* Update minimap pos and rotation */ - if (mapper && m_game_ui->m_flags.show_minimap && m_game_ui->m_flags.show_hud) { + if (mapper && m_game_ui->m_flags.show_hud) { mapper->setPos(floatToInt(player->getPosition(), BS)); mapper->setAngle(player->getYaw()); } @@ -3966,6 +3909,27 @@ void Game::updateFrame(ProfilerGraph *graph, RunStats *stats, f32 dtime, /* End scene */ + if (++m_reset_HW_buffer_counter > 500) { + /* + Periodically remove all mesh HW buffers. + + Work around for a quirk in Irrlicht where a HW buffer is only + released after 20000 iterations (triggered from endScene()). + + Without this, all loaded but unused meshes will retain their HW + buffers for at least 5 minutes, at which point looking up the HW buffers + becomes a bottleneck and the framerate drops (as much as 30%). + + Tests showed that numbers between 50 and 1000 are good, so picked 500. + There are no other public Irrlicht APIs that allow interacting with the + HW buffers without tracking the status of every individual mesh. + + The HW buffers for _visible_ meshes will be reinitialized in the next frame. + */ + infostream << "Game::updateFrame(): Removing all HW buffers." << std::endl; + driver->removeAllHardwareBuffers(); + m_reset_HW_buffer_counter = 0; + } driver->endScene(); stats->drawtime = tt_draw.stop(true); @@ -4001,9 +3965,10 @@ inline void Game::limitFps(FpsControl *fps_timings, f32 *dtime) else fps_timings->busy_time = 0; - u32 frametime_min = 1000 / (g_menumgr.pausesGame() - ? g_settings->getFloat("pause_fps_max") - : g_settings->getFloat("fps_max")); + u32 frametime_min = 1000 / ( + device->isWindowFocused() && !g_menumgr.pausesGame() + ? g_settings->getFloat("fps_max") + : g_settings->getFloat("fps_max_unfocused")); if (fps_timings->busy_time < frametime_min) { fps_timings->sleep_time = frametime_min - fps_timings->busy_time; @@ -4051,7 +4016,7 @@ void Game::readSettings() m_cache_enable_fog = g_settings->getBool("enable_fog"); m_cache_mouse_sensitivity = g_settings->getFloat("mouse_sensitivity"); m_cache_joystick_frustum_sensitivity = g_settings->getFloat("joystick_frustum_sensitivity"); - m_repeat_right_click_time = g_settings->getFloat("repeat_rightclick_time"); + m_repeat_place_time = g_settings->getFloat("repeat_place_time"); m_cache_enable_noclip = g_settings->getBool("noclip"); m_cache_enable_free_move = g_settings->getBool("free_move"); @@ -4116,7 +4081,7 @@ void Game::showDeathFormspec() auto *&formspec = m_game_ui->getFormspecGUI(); GUIFormSpecMenu::create(formspec, client, &input->joystick, - fs_src, txt_dst, client->getFormspecPrepend()); + fs_src, txt_dst, client->getFormspecPrepend(), sound); formspec->setFocus("btn_respawn"); } @@ -4143,30 +4108,32 @@ void Game::showPauseMenu() "- %s: move backwards\n" "- %s: move left\n" "- %s: move right\n" - "- %s: jump/climb\n" - "- %s: sneak/go down\n" + "- %s: jump/climb up\n" + "- %s: dig/punch\n" + "- %s: place/use\n" + "- %s: sneak/climb down\n" "- %s: drop item\n" "- %s: inventory\n" "- Mouse: turn/look\n" - "- Mouse left: dig/punch\n" - "- Mouse right: place/use\n" "- Mouse wheel: select item\n" "- %s: chat\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_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_chat) + ); std::string control_text = std::string(control_text_buf); str_formspec_escape(control_text); @@ -4248,7 +4215,7 @@ void Game::showPauseMenu() auto *&formspec = m_game_ui->getFormspecGUI(); GUIFormSpecMenu::create(formspec, client, &input->joystick, - fs_src, txt_dst, client->getFormspecPrepend()); + fs_src, txt_dst, client->getFormspecPrepend(), sound); formspec->setFocus("btn_continue"); formspec->doPause = true; } @@ -4260,19 +4227,11 @@ void Game::showPauseMenu() /****************************************************************************/ void the_game(bool *kill, - bool random_input, InputHandler *input, - const std::string &map_dir, - const std::string &playername, - const std::string &password, - const std::string &address, // If empty local server is created - u16 port, - + const GameStartData &start_data, std::string &error_message, ChatBackend &chat_backend, - bool *reconnect_requested, - const SubgameSpec &gamespec, // Used for local game - bool simple_singleplayer_mode) + bool *reconnect_requested) // Used for local game { Game game; @@ -4280,14 +4239,11 @@ void the_game(bool *kill, * is created then this is updated and we don't want to change the value * passed to us by the calling function */ - std::string server_address = address; try { - if (game.startup(kill, random_input, input, map_dir, - playername, password, &server_address, port, error_message, - reconnect_requested, &chat_backend, gamespec, - simple_singleplayer_mode)) { + if (game.startup(kill, input, start_data, error_message, + reconnect_requested, &chat_backend)) { game.run(); } |